How to only get one value of child firebase cloud function? - node.js

I want to send notifications that trigger into pengumuman topic.
export const onNotifPengumuman = functions.database.ref('/pengumuman_course/{course_id_p}/{pengumuman_id}')
.onCreate((snapshot,context) =>{
const course_id_p = context.params.course_id_p;
const pengumuman_id = context.params.pengumuman_id;
const nama_matkul = admin.database().ref('/courses/'+course_id_p+'name').once('value').then(snap =>{
return snapshot.val();
}).catch(error =>
{
console.log(error);
})
console.log(`cobacobacoba ${nama_matkul}`);
return admin.database().ref('pengumuman/' + pengumuman_id + '/').once('value').then(snap =>{
const pengumumanData = snap.val();
const notifDataPengumuman = {
data:{
data_type: "pengumuman ",
title: "Pengumuman Baru", // data bebas (key, value)
body: `${nama_matkul}`, // chatId = const chatId
sound: "default"
}
}
return admin.messaging().sendToTopic(course_id_p, notifDataPengumuman)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
}).catch(error => {
console.log(error);
})
});
In the first ref functions.database.ref('/pengumuman_course/{course_id_p}/{pengumuman_id}') I want to access and trigger this child in firebase real time database, the code below :
enter image description here
after that in this code return admin.database().ref('pengumuman/' + pengumuman_id + '/') I'm tring to get all of information about pengumuman and send it into users. The code in below :
enter image description here
But before that I want to get pengumuman name in the courses ref in the database to get value of name ,with this code :
const nama_matkul = admin.database().ref('/courses/'+course_id_p+'name').once('value').then(snap =>{
return snapshot.val();
}).catch(error =>
{
console.log(error);
})
enter image description here
The problem is when I'm using that code to get child name and store it into matkul, when I send/log ,it will return promises object. I want the result showing "REKAYASA PERANGKAT LUNAK".
Thanks and sorry for bad explanation
[FIXED]
Im trying the solution and found this code
export const onNotifPengumuman = functions.database.ref('/pengumuman_course/{course_id_p}/{pengumuman_id}')
.onCreate((snapshot,context) =>{
const course_id_p = context.params.course_id_p;
console.log(`course id pengumuman ${course_id_p}`);
const pengumuman_id = context.params.pengumuman_id;
admin.database().ref('/courses/' + course_id_p + '/').once('value').then(snap2 =>{
const nama_matkul = snap2.child('name').val();
console.log(`nama matkul dari sini ${nama_matkul}`);
admin.database().ref('pengumuman/' + pengumuman_id + '/').once('value').then(snap =>{
const pengumumanData = snap.val();
const notifDataPengumuman = {
data:{
data_type: "pengumuman",
title: "Pengumuman Baru", // data bebas (key, value)
body: `Judul :${nama_matkul}`, // chatId = const chatId
sound: "default"
}
}
return admin.messaging().sendToTopic(course_id_p, notifDataPengumuman)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
}).catch(error => {
console.log(error);
})
}).catch(error =>{
console.log(error);
})
});

You will need to resolve promises in order to get the value returned by them. What you are doing at the moment is assigning nama_matkul the promise but you never wait for it to complete.
Async/Await
You can either use async/await by defining your function as asynchronous:
.onCreate(async (snapshot,context) =>{
// Your asynchronous code here
}
You can then resolve the promise by running
const nama_matkul = (await admin.database().ref('/courses/'+course_id_p+'name').once('value')).val();
If you need to handle exceptions, wrap the promise and await in a try catch block.
After refactoring your code, it might look something like this:
export const onNotifPengumuman = functions.database.ref('/pengumuman_course/{course_id_p}/{pengumuman_id}')
.onCreate(async (snapshot,context) => {
try {
const course_id_p = context.params.course_id_p;
const pengumuman_id = context.params.pengumuman_id;
const nama_matkul = (await admin.database().ref('/courses/'+course_id_p+'name').once('value')).val();
console.log(`cobacobacoba ${nama_matkul}`);
const pengumumanData = (await admin.database().ref('pengumuman/' + pengumuman_id + '/').once('value')).val();
const notifDataPengumuman = {
data: {
data_type: "pengumuman ",
title: "Pengumuman Baru", // data bebas (key, value)
body: `${nama_matkul}`, // chatId = const chatId
sound: "default"
}
}
try {
await admin.messaging().sendToTopic(course_id_p, notifDataPengumuman);
console.log("Successfully sent message:", response);
} catch (messageSendError) {
console.log("Error sending message:", messageSendError);
}
} catch (error) {
console.log(error);
}
});
Then/Catch
If you do want to stick with the current setup you have and work with callbacks, you can instead keep the .then call and handle your application logic in the callback; your code might look something like this:
export const onNotifPengumuman = functions.database.ref('/pengumuman_course/{course_id_p}/{pengumuman_id}')
.onCreate((snapshot,context) => {
const course_id_p = context.params.course_id_p;
const pengumuman_id = context.params.pengumuman_id;
admin.database().ref('/courses/'+course_id_p+'name').once('value')
.then(nameSnapshot => {
const nama_matkul = nameSnapshot.val();
console.log(`cobacobacoba ${nama_matkul}`);
admin.database().ref('pengumuman/' + pengumuman_id + '/').once('value')
.then(dataSnapshot => {
const pengumumanData = dataSnapshot.val();
const notifDataPengumuman = {
data: {
data_type: "pengumuman ",
title: "Pengumuman Baru", // data bebas (key, value)
body: `${nama_matkul}`, // chatId = const chatId
sound: "default"
}
}
return admin.messaging().sendToTopic(course_id_p, notifDataPengumuman)
.then(response => console.log("Successfully sent message:", response))
.catch(error => console.log("Error sending message:", error));
})
.catch(error => console.log(error));
})
.catch(error => console.log(error))
});
You can of course use a combination of then/catch and await if you so wish, whether this is a good practice or when to use which really depends on the situation in which you use it.

Related

When using forEach in a Cloud Function, I can't make .sendToDevice() method work

I can send messages to the iOS device using the second function shown below.
I get the document id in the collection name "users" which is at the first level and send the message using the token stored in the tokens subcollection therefore admin.firestore().collection('users').doc(userId).collection('tokens').
I have to change the way the function looks for the user. Rather than relying on the document id of the user, I now need a query in order to find the user. Being a query, unless I'm wrong, I'm forced to use forEach in order to send the message to the user. The function now looks as shown immediately below. In essence, once I know I have the user that needs to receive the message, I'm using the original function format to send the message but the message is never sent. All I see in the logs is Firebase messaging error and I have yet to figure out where the mistake is.
exports.sendMessage = functions.https.onRequest(async (res, response) => {
const body = res.body;
const orderTotal = body.total;
const orderId = String(body.id);
const query = await usersRef.where('token', '==', token).get();
if (query.empty) {
console.log('No matching documents.');
return;
}
query.forEach(doc => {
const tokens = usersRef.doc(doc.id).collection('tokens');
tokens.get()
.then(snapshot => {
const results = [];
snapshot.forEach(doc => {
const fcmToken = doc.data().fcmToken
console.log("fcmToken =>", fcmToken);
results.push(fcmToken);
})
const payload = {
notification: {
title_loc_key: 'notify_title',
subtitle_loc_key: 'notify_subtitle',
body_loc_key: 'notify_body',
badge: '1',
sound: 'cha-ching.caf',
mutable_content: 'true'
},
data: {
'total': orderTotal,
'orderId': orderId
}
}
response.send([results, , payload])
admin.messaging().sendToDevice(results, payload).then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
return { success: true };
}).catch((error) => {
return { error: error.code };
})
})
.catch(err => {
console.log("Error getting documents", err);
});
});
});
This is the original function which I used when using the document id.
exports.sendMessage = functions.https.onRequest(async (res, response) => {
const body = res.body
const orderTotal = body.total
const orderId = String(body.id)
const tokenReference = admin.firestore().collection('users').doc(userId).collection('tokens')
const tokenSnapshots = await tokenReference.get()
const results = []
tokenSnapshots.forEach(tokenSnapshot => {
const fcmToken = tokenSnapshot.data().fcmToken
results.push(fcmToken)
})
const payload = {
notification: {
title_loc_key: 'notify_title',
subtitle_loc_key: 'notify_subtitle',
body_loc_key: 'notify_body',
badge: '1',
sound: 'cha-ching.caf',
mutable_content: 'true'
},
data: {
'total': orderTotal,
'orderId': orderId
}
}
response.send([results, , payload])
admin.messaging().sendToDevice(results, payload).then((response) => {
console.log('Successfully sent message:', response);
return { success: true };
}).catch((error) => {
return { error: error.code };
})
})
Screenshot of the error:
The onRequest() function terminates when you return a response. You are using sendToDevice() after response.send(). Also make sure you are handling all the promises correctly. Try refactoring the using async-await syntax as shown below:
exports.sendMessage = functions.https.onRequest(async (res, response) => {
try {
const body = res.body;
const orderTotal = body.total;
const orderId = String(body.id);
const query = await usersRef.where("token", "==", "TOKEN").get();
if (query.empty) {
console.log("No matching documents.");
return;
}
// Query tokens of all users at once
const tokenSnapshots = await Promise.all(
query.docs.map((user) => usersRef.doc(user.id).collection("tokens").get())
);
// Array of all fcmTokens
const results = tokenSnapshots.reduce((acc, snapshot) => {
acc = [...acc, ...snapshot.docs.map((doc) => doc.data().fcmToken)];
return acc;
}, []);
const payload = { ...FCM_PAYLOAD };
const fcmResponse = await getMessaging().sendToDevice(results, payload);
console.log("Successfully sent message:", fcmResponse);
response.send([results, , payload]);
} catch (error) {
console.log(error);
response.json({ error: "An error occured" });
}
});
Also checkout Terminating HTTP Cloud Functions.
After days of working on this, it turns out there wasn't anything wrong with the function. I don't know how VPN works but the fact that I had it enabled on my iPhone was the reason I wasn't getting the notification.
I paused the VPN and the notification was received.

Fluent-FFMPEG redirects to home page when recording is finished

I am using fluent-FFmpeg with my node.js and express server to record videos from an RTSP stream. The issue I am encountering is that once the command to record the video is finished, my React client-side always redirects to the home page of my application, even though this is not the behavior I want. I want the user to remain on the page with the RTSP stream and just receive a toast notification indicating that the recording is finished. With this issue, the page redirects before the notification has a chance to display. Is this an issue with my server-side or client-side code?
Node.js
export const startRecording = async (req, res) => {
const camera = req.params;
if (camera.id in runningCommands) { return res.json({ "status": "failure", "error": "Recording already in progress" }) }
const { recordTime, uid } = req.body;
let conn = createConnection(config);
conn.connect();
let query = 'SELECT * FROM cameras WHERE id = ?';
conn.query(query, [camera.id], (error, rows) => {
if (error) { return res.json({ "status": "failure", "error": error }) }
const camera = rows[0];
const { ip, fname } = camera;
const currentDate = new Date().toLocaleString().replace(/[:/\s]/g, '-').replace(',', '');
const filename = `${fname}-${currentDate}`;
try {
// FFmpeg command to start recording
const command = ffmpeg(`rtsp://${ip}/axis-media/media.amp`)
.videoCodec('libx264')
.size('1280x720')
.duration(recordTime)
.on('start', commandLine => {
runningCommands[camera.id] = command
console.log(`Spawned Ffmpeg with command: ${commandLine}`)
})
.on('error', err => console.error(err))
.on('end', () => {
delete runningCommands[camera.id]
console.log('Recording Complete')
takeScreenshot(filename, `./public/recordings/mp4/${filename}.mp4`)
conn.query('INSERT INTO recordings (uid, cid, filename) VALUES (?, ?, ?)', [uid, camera.id, filename], () => conn.end())
res.json({ "status": "success", "message": "Recording ended" })
})
.save(`./public/recordings/mp4/${filename}.mp4`);
} catch (error) { console.error(error)}
})
}
React:
const handleRecording = async () => {
try {
setIsRecording(true)
const futureTime = new Date().getTime() + recordTime * 1000
const finishedTime = new Date(futureTime).toLocaleTimeString()
setTimeRemaining(finishedTime)
const { data } = await publicRequest.post(`record/startRecording/${id}`, { recordTime, uid: user.id })
window.location.reload(false)
if (data.status === 'success') {
setIsRecording(false)
toast('Recording finished!', { type: 'success' })
} else {
setIsRecording(true)
toast('Recording already in progress!', { type: 'error' })
}
} catch (error) {
console.error(error)
}
}

Fetch in vue 3 stops backend and does nothing after working fine one time

So, my problem is when I try to login in my vue app, the backend automatically stops when I try to fetch from it an array of objects.
To be more specific.
This is my fetch "attempt" to retrieve the objects from the database.
let url = utils.url;
let requestParam = utils.globalRequestParameters;
requestParam.method = "GET";
requestParam.body = null;
if (cars.value.length == 0) {
fetch(url + "cars", requestParam).then((res) =>
res.json().then(async (res) => {
store.dispatch("Car/fetchCars", res);
fetch(url + "users", requestParam).then((users) =>
users.json().then((users) => {
for (let car of res) {
let userCar = Object.values(users).find(
(a) => a.id == car.userId
);
car.userName = userCar.lastName + " " + userCar.firstName;
}
})
);
})
);
}
And login in view Login.vue
let requestParameters = utils.globalRequestParameters;
requestParameters.method = "POST";
requestParameters.body = JSON.stringify(data);
fetch(utils.url + "login", requestParameters).then((res) => {
res.json().then((res) => {
this.mesaj = res.message;
console.log("token:" + res.token);
if (res.token) {
localStorage.setItem("token", res.token);
console.log("token:" + res.token);
console.log("id:" + res.id);
let id = res.id;
requestParameters.method = "GET";
requestParameters.body = null;
this.$store.dispatch("login", true);
fetch(utils.url + "users/" + id, requestParameters).then(
(res) => {
res.json().then((res) => {
console.log("Jos de tot");
this.$store.dispatch("User/setUser", res);
console.log(this.$store.state.User.user);
this.$router.push("/");
});
}
);
}
});
});
}
},
Note.
cars is a computed value that return store.state.cars
and utils is
let url = "http://127.0.0.1:3000/";
let globalRequestParameters = {
method: "GET",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
redirect: "follow",
referrerPolicy: "no-referrer",
};
module.exports.globalRequestParameters = globalRequestParameters;
module.exports.url = url;
Here at the first fetch the backend stops and also the fetch it is not done.
And the backend route is
router.get('/cars', async (req, res) => {
res.json(await functions.getAllCars(req,res));
})
getAllCars = async (req, res) => {
const snapshot = await db.collection("Cars").get();
let cars = [];
snapshot.forEach((doc) => {
let car = {
id: doc.id,
userId: doc.data().userId,
manufacturer: doc.data().manufacturer,
model: doc.data().model,
color: doc.data().color,
plate: doc.data().plate,
price: doc.data().price,
description: doc.data().description
};
cars.push(car);
});
res.status(200).send(cars);
return
};
router.get("/users/:id", async (req, res) => {
res.json(await functions.getUserById(req.params.id, res));
});
getUserById = (id, res) => {
db
.collection("Users")
.doc(id)
.get()
.then((response) => {
let user = {};
user.id = response.id;
user.firstName = response.data().firstName;
user.lastName = response.data().lastName;
user.gender = response.data().gender;
user.jobTitle = response.data().jobTitle;
user.phone = response.data().phone;
user.email = response.data().email;
user.isAdmin = response.data().isAdmin;
res.status(200).send(user);
return
})
.catch((err) => {
res.status(404).send({ message: "User not found" });
return
});
};
The user is retrieved correctly, I see it in console through a console log, but the messages that I get in the terminal and console are:
*As a final note. I use vue 3, node.js version 16.13.0 and Firestore as Database. And yesterday everything was working perfectly fine on my other computer but I had to go somewhere and use my laptop. Maybe there is something about my laptop. All I did was just to install the modules for the front and back
I think this has nothing to do with Vue - it is simply the problem of your Express backend code
ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client
As described here:
That particular error occurs whenever you try to send more than one response to the same request and is usually caused by improper asynchronous code.
getAllCars
getAllCars is async function with await inside - as soon as this await is hit (together with db.collection("Cars").get() call), function returns Promise which is awaited at res.json(await functions.getAllCars(req,res));
When the DB call finishes, the rest of the method is executed including res.status(200).send(cars) - this will send the cars array to the client and returns undefined (this is what simple return does) and res.json(undefined) is executed causing the error above (you are trying to send second response)
getUserById
You say that this handler works fine but I really doubt it - from what I see, this should NOT work either
You are calling it with res.json(await functions.getUserById(req.params.id, res));. To await actually doing something, the awaited function must return a Promise (either implicitly by using await inside or explicitly) or general "thenable" object. The getUserById function returns nothing (return statements inside then() or catch() does not count! ...those are different functions)
This problem can be fixed by doing return db.collection("Users").doc(id).get().then() but then you will get same error as in getAllCars case
Correct pattern
Do not use res.status(200).send() and res.json() together
For the sake of sanity (at least until you really know what you are doing) do not mix promises with async/await
async functions should return the data (do not use return without "argument")
Following code shows both Promise based and async/await style (it "pseudo code" in the sense I did not tested it but hopefully you get the idea)
router.get('/cars', async (req, res) => {
try {
const response = await functions.getAllCars()
res.status(200).json(response);
} catch() {
res.sendStatus(500)
}
})
getAllCars = async () => {
const snapshot = await db.collection("Cars").get();
let cars = [];
snapshot.forEach((doc) => {
let car = {
id: doc.id,
userId: doc.data().userId,
manufacturer: doc.data().manufacturer,
model: doc.data().model,
color: doc.data().color,
plate: doc.data().plate,
price: doc.data().price,
description: doc.data().description
};
cars.push(car);
});
// res.status(200).send(cars); //* should be handled by caller
return cars //* return the data
};
router.get("/users/:id", async (req, res) => {
functions.getUserById(req.params.id)
.then((response) => {
if(response === null)
res.status(404).json({ message: "User not found" });
else
res.status(200).json(response);
})
.catch(er) {
res.status(500).send(er.message)
}
});
getUserById = (id) => {
return db //* return the promise
.collection("Users")
.doc(id)
.get()
.then((response) => {
let user = {};
user.id = response.id;
user.firstName = response.data().firstName;
user.lastName = response.data().lastName;
user.gender = response.data().gender;
user.jobTitle = response.data().jobTitle;
user.phone = response.data().phone;
user.email = response.data().email;
user.isAdmin = response.data().isAdmin;
// res.status(200).send(user); //* should be handled by caller
return user //* return the data
})
.catch((err) => {
return null
});
};

one of my friend is trying to automate a process in which the bot will post instagram stories as a video from a specific folder

below is the working code in which it can post images but is there any way i can also share videos as instagram story?
the error i get when i try to post video instead of image are:**
error image
PS D:\Softwares\programming\Insta Bot\story> node index.js
18:45:11 - info: Dry Run Activated
18:45:11 - info: Post() called! ======================
18:45:11 - debug: 1 files found in ./images/
18:45:11 - warn: Record file not found, saying yes to D:\Softwares\programming\Insta Bot\story\images\meme.mp4
18:45:11 - debug: Read File Success
18:45:11 - error: undefined
(MAIN CODE)
index.js
const logger = require("./logger.js")
const { random, sleep } = require('./utils')
require('dotenv').config();
const { IgApiClient, IgLoginTwoFactorRequiredError } = require("instagram-private-api");
const ig = new IgApiClient();
const Bluebird = require('bluebird');
const inquirer = require('inquirer');
const { CronJob } = require('cron');
const path = require("path");
const fs = require("fs");
const fsp = fs.promises;
const sharp = require("sharp");
//==================================================================================
const statePath = "./etc/state.conf";
const recordPath = "./etc/usedfiles.jsonl";
const imgFolderPath = "./images/";
const dryrun = true;
const runOnStart = true;
//==================================================================================
(async () => { // FOR AWAIT
// LOGIN TO INSTAGRAM
if (!dryrun) {
await login();
logger.info("Log In Successful");
} else {
logger.info("Dry Run Activated");
}
// SCHEDULER
// logger.silly("I'm a schedule, and I'm running!! :)");
const job = new CronJob('38 43 * * * *', post, null, true); //https://crontab.guru/
if (!runOnStart) logger.info(`Next few posts scheduled for: \n${job.nextDates(3).join("\n")}\n`);
else post();
// MAIN POST COMMAND
async function post() {
logger.info("Post() called! ======================");
let postPromise = fsp.readdir(imgFolderPath)
.then(filenames => {
if (filenames.length < 1) throw new Error(`Folder ${imgFolderPath} is empty...`)
logger.debug(`${filenames.length} files found in ${imgFolderPath}`);
return filenames;
})
.then(filenames => filenames.map(file => path.resolve(imgFolderPath + file)))
.then(filenames => pickUnusedFileFrom(filenames, filenames.length))
.then(filename => {
if (!dryrun) registerFileUsed(filename)
return filename
})
.then(fsp.readFile)
.then(async buffer => {
logger.debug("Read File Success "); //TODO move this to previous then?
return sharp(buffer).jpeg().toBuffer()
.then(file => {
logger.debug("Sharp JPEG Success");
return file
})
})
.then(async file => {
if (!dryrun) {
// await sleep(random(1000, 60000)) //TODO is this necessary?
return ig.publish.story({ file })
.then(fb => logger.info("Posting successful!?"))
}
else return logger.info("Data not sent, dryrun = true")
})
.then(() => logger.info(`Next post scheduled for ${job.nextDates()}\n`))
.catch(logger.error)
}
})();
//=================================================================================
async function login() {
ig.state.generateDevice(process.env.IG_USERNAME);
// ig.state.proxyUrl = process.env.IG_PROXY;
//register callback?
ig.request.end$.subscribe(async () => {
const serialized = await ig.state.serialize();
delete serialized.constants; // this deletes the version info, so you'll always use the version provided by the library
await stateSave(serialized);
});
if (await stateExists()) {
// import state accepts both a string as well as an object
// the string should be a JSON object
const stateObj = await stateLoad();
await ig.state.deserialize(stateObj)
.catch(err => logger.debug("deserialize: " + err));
} else {
let standardLogin = async function() {
// login like normal
await ig.simulate.preLoginFlow();
logger.debug("preLoginFlow finished");
await ig.account.login(process.env.IG_USERNAME, process.env.IG_PASSWORD);
logger.info("Logged in as " + process.env.IG_USERNAME);
process.nextTick(async () => await ig.simulate.postLoginFlow());
logger.debug("postLoginFlow finished");
}
// Perform usual login
// If 2FA is enabled, IgLoginTwoFactorRequiredError will be thrown
return Bluebird.try(standardLogin)
.catch(
IgLoginTwoFactorRequiredError,
async err => {
logger.info("Two Factor Auth Required");
const {username, totp_two_factor_on, two_factor_identifier} = err.response.body.two_factor_info;
// decide which method to use
const verificationMethod = totp_two_factor_on ? '0' : '1'; // default to 1 for SMS
// At this point a code should have been sent
// Get the code
const { code } = await inquirer.prompt([
{
type: 'input',
name: 'code',
message: `Enter code received via ${verificationMethod === '1' ? 'SMS' : 'TOTP'}`,
},
]);
// Use the code to finish the login process
return ig.account.twoFactorLogin({
username,
verificationCode: code,
twoFactorIdentifier: two_factor_identifier,
verificationMethod, // '1' = SMS (default), '0' = TOTP (google auth for example)
trustThisDevice: '1', // Can be omitted as '1' is used by default
});
},
)
.catch(e => logger.error('An error occurred while processing two factor auth', e, e.stack));
}
return
//================================================================================
async function stateSave(data) {
// here you would save it to a file/database etc.
await fsp.mkdir(path.dirname(statePath), { recursive: true }).catch(logger.error);
return fsp.writeFile(statePath, JSON.stringify(data))
// .then(() => logger.info('state saved, daddy-o'))
.catch(err => logger.error("Write error" + err));
}
async function stateExists() {
return fsp.access(statePath, fs.constants.F_OK)
.then(() => {
logger.debug('Can access state info')
return true
})
.catch(() => {
logger.warn('Cannot access state info')
return false
});
}
async function stateLoad() {
// here you would load the data
return fsp.readFile(statePath, 'utf-8')
.then(data => JSON.parse(data))
.then(data => {
logger.info("State load successful");
return data
})
.catch(logger.error)
}
}
async function registerFileUsed( filepath ) {
let data = JSON.stringify({
path: filepath,
time: new Date().toISOString()
}) + '\n';
return fsp.appendFile(recordPath, data, { encoding: 'utf8', flag: 'a+' } )
.then(() => {
logger.debug("Writing filename to record file");
return filepath
})
}
function pickUnusedFileFrom( filenames, iMax = 1000) {
return new Promise((resolve, reject) => {
let checkFileUsed = async function ( filepath ) {
return fsp.readFile(recordPath, 'utf8')
.then(data => data.split('\n'))
.then(arr => arr.filter(Boolean))
.then(arr => arr.map(JSON.parse))
.then(arr => arr.some(entry => entry.path === filepath))
}
let trythis = function( iMax, i = 1) {
let file = random(filenames);
checkFileUsed(file)
.then(async used => {
if (!used) {
logger.info(`Unused file found! ${file}`);
resolve(file);
} else if (i < iMax) {
logger.debug(`Try #${i}: File ${file} used already`);
await sleep(50);
trythis(iMax, ++i)
} else {
reject(`I tried ${iMax} times and all the files I tried were previously used`)
}
})
.catch(err => {
logger.warn("Record file not found, saying yes to " + file);
resolve(file);
})
}( iMax );
})
}

JS: ERROR: "Promise { <pending> }" with Sockets

I'm having a problem with a Promise, when I try to retrieve the data it says Promise { <pending> } I already looked for some information about that but I cannot understand how to end it.
If anyone can help me I would be appreciated.
Thanks in advance
/bucket.js
'use strict'
const connection = require('../server/models'),
oracledb = require('oracledb'),
conexion = oracledb.getConnection(connection)
oracledb.outFormat = oracledb.OBJECT
module.exports = (data) => {
console.log("RES: ", filter(data));
return filter(data)
}
const filter = (value) => {
return conexion
.then(con => {
return con.execute(
`SELECT id_application, name, description, creation_date ` +
`FROM application `
).then(bucket => {
return con.execute(
`SELECT id_definition, id_application, field_name_original,
field_name_new, column_name, position, id_type_data,
field_size, creation_date, description, filter, visible ` +
`FROM definition ` +
`WHERE id_application in (${getApp(value.data)}) ` +
`AND ${value['search']} = '${value['value']}' `
).then(definitions => { return creaJSON(bucket, definitions) } )
.catch(error => { return {"error": error} })
})
.catch(error => { return {"error": error} })
})
.catch(error => { return {"error": error} })
}
const getApp = (value) => {
return value.map(obj => {
return `'${obj.ID_APPLICATION}'`
})
}
const creaJSON = (buckets, definitions) => {
var df = new Array()
buckets['rows'].map(obj => {
definitions['rows'].map(def => {
if(obj['ID_APPLICATION'] == def['ID_APPLICATION']) df.push(def)
})
obj['Definitions'] = df
df = []
})
return buckets.rows
}
UPDATED
My error wasnt only in the code above. I'm using sockets and also with the Bergi answer I couldn't had my response in the client. I had the next code:
socket.on('bucketVisibleT', (data) => {
buckets = {data:data,search:'VISIBLE',value:'T'}
io.sockets.emit('bucketVisibleFs', require('./bucket')(buckets))
})
so I had to change with the next one, and now I have my response in my client.
socket.on('bucketVisibleT', (data) => {
buckets = {data:data,search:'VISIBLE',value:'T'}
require('./bucket')(buckets).then(res => {
io.sockets.emit('bucketVisibleTs', res)
})
})
I apologise because I didn't give a good explanation of my problem but I thought it was in my first code
filter returns a promise, so like with the other promise-returning functions you need to chain a then call to it if you want to do something with the result:
module.exports = (data) =>
filter(data).then(res => {
console.log("RES: ", res);
return res;
});

Resources