Firebase functions RangeError: Maximum call stack size exceeded - function

I have a Callable function that uploads an image and update Firestore and Storage accordingly. The function does what it should do. but I still get this error:
Unhandled error RangeError: Maximum call stack size exceeded
here is the function:
export const uploadImageToStripe = functions.https.onCall(async (data, context) => {
let businessDoc: DocumentSnapshot
try {
if (!fireStoreDB) {
fireStoreDB = admin.firestore();
fireStoreDB.settings(settings);
}
businessDoc = await fireStoreDB.collection('businesses').doc(data.business_id).get()
const bucketName = functions.config().storage.default_bucket;
const tempLocalFile = path.join(os.tmpdir(), 'img.jpg').trim();
const tempLocalDir = path.dirname(tempLocalFile);
const bucket = admin.storage().bucket(bucketName);
// Create the temp directory where the storage file will be downloaded.
await mkdirp(tempLocalDir);
console.log('Temporary directory has been created', tempLocalDir);
// Download file from bucket.
await bucket.file(data.photo_location).download({ destination: tempLocalFile });
console.log('The file has been downloaded to', tempLocalFile);
// Downloads the file
console.log(`gs://${bucketName}/${data.photo_location} downloaded to ${tempLocalDir}.`)
const uploadedFile: stripeM.fileUploads.IFileUpdate = await stripe.fileUploads.create({
file: {
data: fs.readFileSync(tempLocalFile),
name: 'img.jpg',
type: 'application.octet-stream',
}
});
if (!businessDoc.exists) {
throw new functions.https.HttpsError('not-found', `Couldn't find business document ` + data.business_id);
}
await stripe.accounts.update(businessDoc.data().stripeId,
{ document: uploadedFile.id });
await businessDoc.ref.update({ "photoNeeded": false })
return await bucket.file(data.photo_location).delete()
} catch (error) {
console.error(error);
await businessDoc.ref.update({ "photoNeeded": true })
throw new functions.https.HttpsError('unavailable', `failed to upload photo to stripe`);
}
})
Any ideas why I get this error?

This line throw the error:
return await bucket.file(data.photo_location).delete()
splitting it to:
await bucket.file(data.photo_location).delete()
return "Success"
solve it.

Related

req.file.stream is undefined

I'm having troubles with node 16 and ES6. I'm trying to make a upload file controller but i'm stuck with req.file.stream which is undefined
I'm using multer to handle upload files.
The first issue was __dirname undefined that I was able to fix with path and New Url.
The error I got with pipeline
node:internal/process/promises:246
triggerUncaughtException(err, true /* fromPromise */);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "source" argument must be of type function or an instance of Stream, Iterable, or AsyncIterable. Received undefined
my userRoutes.js
import express from "express";
import { signin, signup, logout } from "../Controller/AuthController.js";
import {
getUsers,
getUser,
updateUser,
deleteUser,
follow,
unfollow,
} from "../Controller/UserController.js";
import { upload } from "../Controller/UploadController.js";
import multer from "multer";
const router = express.Router();
// Auth
router.post("/signin", signin);
router.post("/signup", signup);
router.post("/logout", logout);
// users
router.get("/", getUsers);
router.get("/:id", getUser);
router.patch("/:id", updateUser);
router.delete("/:id", deleteUser);
router.patch("/follow/:id", follow);
router.patch("/unfollow/:id", unfollow);
// upload
router.post("/upload", multer().single("file"), upload);
export default router;
And my UploadController.js
import fs from "fs";
import { promisify } from "util";
import stream from "stream";
const pipeline = promisify(stream.pipeline);
// const { uploadErrors } = require("../utils/errors.utils");
import path from "path";
const __dirname = path.dirname(new URL(import.meta.url).pathname);
export const upload = async (req, res) => {
try {
// console.log(req.file);
console.log(__dirname);
if (
!req.file.mimetype == "image/jpg" ||
!req.file.mimetype == "image/png" ||
!req.file.mimetype == "image/jpeg"
)
throw Error("invalid file");
if (req.file.size > 2818128) throw Error("max size");
} catch (err) {
const errors = uploadErrors(err);
return res.status(201).json({ err });
}
const fileName = req.body.name + ".jpg";
await pipeline(
req.file.stream,
fs.createWriteStream(
`${__dirname}/../client/public/uploads/profil/${fileName}`
)
);
try {
await User.findByIdAndUpdate(
req.body.userId,
{ $set: { picture: "./uploads/profil/" + fileName } },
{ new: true, upsert: true, setDefaultsOnInsert: true },
(err, docs) => {
if (!err) return res.send(docs);
else return res.status(500).send({ message: err });
}
);
} catch (err) {
return res.status(500).send({ message: err });
}
};
Multer gives you the file as a Buffer, not a Stream. req.file.stream is not valid property, but req.file.buffer is: https://github.com/expressjs/multer#file-information.
From the look of your code, you're trying to save the file on disk. You can use multer's DiskStorage for that. Create a storage instance and pass it to the multer instance as a configuration:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, `${__dirname}/../client/public/uploads/profil/`);
},
filename: function (req, file, cb) {
cb(null, req.body.name + '.jpg');
},
});
const upload = multer({ storage });
router.post('/upload', upload.single('file'), upload);
Have a look at this free Request Parsing in Node.js Guide for working with file uploads in Node.js.
if you want to use req.file.stream, you will need to install this version of multer:
npm install --save multer#^2.0.0-rc.1
and your code will work perfectly, just change your req.file.mimetype to req.file.detectedMimeType !!

how to get WSendpoint of a puppeteer-cluster browser

in a project that requires:
Starting each session with logging in credentials + notification/OTP
work with multiple accounts asynchronously
remote debugging or monitoring of the session
5+ different operations can be requested on a open session , in any order
I want it to be a puppeteer cluster browser with one remote debugging port to monitor it
but couldn't integrate WsEndpoints
const puppeteer = require('puppeteer-extra');
const { Cluster } = require('puppeteer-cluster');
class SingleBrowserCluster {
browserInstance
options
constructor() {
if (SingleBrowserCluster._instance) {
//throw new Error("Singleton classes can't be instantiated more than once.")
}
else{
SingleBrowserCluster._instance = this;
// ... Your rest of the constructor code goes after this
console.log("pre optArgs");
const optArgs = [
'--remote-debugging-port=3002',//works if dockerised
'--remote-debugging-address=0.0.0.0',// at localhost.3002
'--window-size=1920,1080',
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-gpu', '--no-zygote', //'--single-process',
];
console.log("pre options");
this.options = {
headless: true,//for dockerization
args: optArgs,
defaultViewport: null,
waitUntil: 'networkidle2'
};
console.log("Do launch now");
return this;
}
}
async screenshotMethod({ page, data: url }) {
await page.goto(url);
console.log(`%c worker X is running on ${url} `, `color:green;`);
console.log("will wait 20 second");
await page.waitForTimeout(20000)
const path = url.replace(/[^a-zA-Z]/g, '_') + '.png';
await page.screenshot({ path });
};
async launchCluster (){
try {
this.browserInstance = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_CONTEXT,
maxConcurrency: 3,
puppeteerOptions: this.options
})
console.log(this.browserInstance);
return this.browserInstance;
} catch (error) {
console.log(`%c ERRORR`,`color:red;`);
console.log(error);
}
}
}
const StartScraper = async (Url, useProxy) => new Promise((resolve, reject) => {
(async () => {
// get proxy url from environment files
const proxyUrl = process.env.PROXY_URL;
//--disable-dev-shm-usage
// By default, Docker runs a container with a /dev/shm shared memory space 64MB. This is typically too small for Chrome and will cause Chrome to crash when rendering large pages.
//his will write shared memory files into /tmp instead of /dev/shm. See crbug.com/736452 for more details.
var instanceOne1= new SingleBrowserCluster()//.launchCluster()
var browser= await instanceOne1.launchCluster();
browser.queue('https://www.google.com/', instanceOne1.screenshotMethod);
//THE PROBLEM LINE
const wsEndpoint = browser.wsEndpoint();
try {
const page = (await browser.pages())[0];
await page.goto(Url, { waitUntil: 'load' });
return resolve(wsEndpoint);
} catch (e) {
browser.close();
return reject(false);
}
})();
});
how can i have WSendpoint of any session in a puppeteer-cluster
( more info:
i will put those in a session file
to provide my next selected consequtive operation a connection point on its session
localhost/StartScraper creates WSendpoint
localhost/login==WSendpoint==>Connects to existing session do login stuff
localhost/listItems==WSendpoint==>Connects to existing session do listItems stuff
...
)

how to read properly a json string in react native

I sent to asyncStorage all the info as stringify,
i tried to parse it.
this is what i get from console log:
"{\"metadata\":{\"lastSignInTime\":1610728860334,\"creationTime\":1610728860334},\"phoneNumber\":null,\"displayName\":null,\"isAnonymous\":false,\"providerData\":[{\"email\":\"ad#ad.com\",\"phoneNumber\":null,\"uid\":\"ad#ad.com\",\"photoURL\":null,\"displayName\":null,\"providerId\":\"password\"}],\"email\":\"ad#ad.com\",\"emailVerified\":false,\"providerId\":\"firebase\",\"photoURL\":null,\"uid\":\"3lkoKoMxQSMKeSxFOyysESt3oKh1\"}"
and i need to get email and uid seperate.
how do I get in that object? i tried user.email or user.providerData.email non of them work.
any suggestion?
edited:
here is the object I get from firebase
let res = await auth().createUserWithEmailAndPassword(Email, Password)
if (res) {
console.log( "?", res)
this.setState({ userData: JSON.stringify( res.user) });
this.storeToken(JSON.stringify(res.user));
then I store the token in async:
async storeToken(user) {
console.log('set user register: ', user)
try {
await AsyncStorage.setItem("userData", JSON.stringify(user));
} catch (error) {
console.log("Something went wrong", error);
}
}
and I get the object from above.
const readData = async () => {
console.log('data === ')
try {
const data = await AsyncStorage.getItem('userData')
let _data = JSON.parse(data);
console.log('data === ', data)
If you share code block it'll be easy for us.
Here is general answer.
Console log shows its still in string format. I use this separate file to read and write json to AsyncStorage. You can either use this OR match to see your mistake.
import AsyncStorage from '#react-native-community/async-storage';
const Api = {
storeData: async function (name, value) {
try {
await AsyncStorage.setItem(name, value);
return true;
} catch (error) {
return false;
}
},
readData: async function (name) {
let value = null;
try {
value = await AsyncStorage.getItem(name)
return JSON.parse(value);
} catch (e) {
return [];
}
},
}
export default Api;
after few console log I was able to get it by double parsing the object.
let _data = JSON.parse(JSON.parse(data));
console.log('data === ', _data.email)
and seem to work.

Why can't I patch, update, or delete an AppPackage that I created?

I am trying to change the required engine version of an AppPackage that I have posted using v2 of the Design Automation API.
I've tried using Postman and the Forge Node Client. I'm using the Forge documentation as a reference.
https://forge.autodesk.com/en/docs/design-automation/v2/reference/http/AppPackages(':id')-PATCH/
My credentials are correct and I have a valid token, but for some reason I keep getting a 404 Not Found status and an error that says "AppPackage with the name MyPlugin doesn't belong to you. You cannot operate on AppPackage you do not own." Also, I get the same message when I try to delete or update the AppPackage.
That's really weird because I definitely own this AppPackage. I uploaded it with these same credentials and I can view it by doing a GET request to view all of my AppPackages. Furthermore, the name of the AppPackage is correct and I specified the right scope (code:all) when I authenticated.
Why does Design Automation think this AppPackage doesn't belong to me and why can't I patch, update, or delete it?
UPDATE 3/28/2019: Setting the resource value still results in the same error
UPDATE 4/2/2019: Getting a fresh upload URL doesn't work either. I get an internal server error saying "Object reference not set to an instance of an object."
const ForgeSDK = require('forge-apis');
const oAuth2TwoLegged = new ForgeSDK.AuthClientTwoLegged(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, SCOPES);
const appPackageApi = new ForgeSDK.AppPackagesApi();
const getToken = () => {
return oAuth2TwoLegged.authenticate();
};
const getUploadURL = () => {
return appPackageApi.getUploadUrl(oAuth2TwoLegged, oAuth2TwoLegged.getCredentials());
};
const patchPackage = (id, url) => {
const appPack = {
Resource: url,
RequiredEngineVersion: APP_PACKAGE_REQUIRED_ENGINE
};
return appPackageApi.patchAppPackage(id, appPack, oAuth2TwoLegged, oAuth2TwoLegged.getCredentials());
};
(async () => {
try {
const token = await getToken();
const url = await getUploadURL();
const patchPackRes = await patchPackage(APP_PACKAGE_ID, url);
if (patchPackRes.statusCode == 201)
console.log('Patch package succeeded!');
else
console.log('Patch package failed!' + patchPackRes.statusCode);
} catch (ex) {
console.log('Exception :(');
console.log(ex);
}
})();
When calling PATCH the "Resource" property must be set. It can be set to the same URL as the one you receive from GET but it must be present and valid.
This should work:
const ForgeSDK = require('forge-apis');
const oAuth2TwoLegged = new ForgeSDK.AuthClientTwoLegged(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, SCOPES);
const appPackageApi = new ForgeSDK.AppPackagesApi();
const getToken = () => {
return oAuth2TwoLegged.authenticate();
};
const getUploadURL = async (id) => {
const app = await appPackageApi.getAppPackage(id, oAuth2TwoLegged, oAuth2TwoLegged.getCredentials());
return app.body.Resource;
};
const patchPackage = (id, url) => {
const appPack = {
Resource: url,
RequiredEngineVersion: APP_PACKAGE_REQUIRED_ENGINE
};
return appPackageApi.patchAppPackage(id, appPack, oAuth2TwoLegged, oAuth2TwoLegged.getCredentials());
};
(async () => {
try {
const token = await getToken();
const url = await getUploadURL(APP_PACKAGE_ID);
const patchPackRes = await patchPackage(APP_PACKAGE_ID, url);
if (patchPackRes.statusCode == 201)
console.log('Patch package succeeded!');
else
console.log('Patch package failed!' + patchPackRes.statusCode);
} catch (ex) {
console.log('Exception :(');
console.log(ex);
}
})();

Puppeteer can't catch failing request & errors

I trying to collect data from failing requests and js error.
I'm using the following site: https://nitzani1.wixsite.com/marketing-automation/3rd-page
The site has a request to https://api.fixer.io/1latest, which returns a status code of 404,
also the page contains thw following js error:
"Uncaught (in promise) Fetch did not succeed"
I've tried to code bellow to catch the 404 and js error but couldn't.
Not sure what I'm doing wrong, any idea as to how to solve it?
const puppeteer = require('puppeteer');
function wait (ms) {
return new Promise(resolve => setTimeout(() => resolve(), ms));
}
var run = async () => {
const browser = await puppeteer.launch({
headless: false,
args: ['--start-fullscreen']
});
page = await browser.newPage();
page.on('error', err=> {
console.log('err: '+err);
});
page.on('pageerror', pageerr=> {
console.log('pageerr: '+pageerr);
});
page.on('requestfailed', err => console.log('requestfailed: '+err));
collectResponse = [];
await page.on('requestfailed', rf => {
console.log('rf: '+rf);
});
await page.on('response', response => {
const url = response.url();
response.buffer().then(
b => {
// console.log(url+' : '+response.status())
},
e => {
console.log('response err');
}
);
});
await wait(500);
await page.setViewport({ width: 1920, height: 1080 });
await page.goto('https://nitzani1.wixsite.com/marketing-automation/3rd-page', {
});
};
run();
The complete worked answer is:
const puppeteer = require('puppeteer');
const run = async () => {
const browser = await puppeteer.launch({
headless: true
});
const page = await browser.newPage();
// Catch all failed requests like 4xx..5xx status codes
page.on('requestfailed', request => {
console.log(`url: ${request.url()}, errText: ${request.failure().errorText}, method: ${request.method()}`)
});
// Catch console log errors
page.on("pageerror", err => {
console.log(`Page error: ${err.toString()}`);
});
// Catch all console messages
page.on('console', msg => {
console.log('Logger:', msg.type());
console.log('Logger:', msg.text());
console.log('Logger:', msg.location());
});
await page.setViewport({ width: 1920, height: 1080 });
await page.goto('https://nitzani1.wixsite.com/marketing-automation/3rd-page', { waitUntil: 'domcontentloaded' });
await page.waitFor(10000); // To be sure all exceptions logged and handled
await browser.close();
};
run();
Save in .js file and easily run it.
Current puppeteer 8.0.0^ have a very small amount of information in message.text(). So we need to get a description of the error from JSHandle.
Please check this comment with fully descriptive console errors from JSHandle object
Check the link here https://stackoverflow.com/a/66801550/9026103