use async - await with socket.io nodejs - node.js

I'm developing a web application using nodejs socket.io and angular 9. In my backend code I have written sockets in socket.connect.service.
Follows is a socket I'm using
socket.on('request-to-sit-on-the-table', async function (data, callback) { //Previously Register
let table = persistence.getTable(tableToken);
if (typeof table === 'undefined') {
let errMsg = 'This table does not exists or already closed.'
callback(prepareResponse({}, errMsg, new Error(errMsg)));
return;
}
//TODO: Get the displayName from the token.
let guest = await guestUserService.getGuestUserByPlayerToken(JSON.parse(data.userToken));***//Here is the issue***
// let displayName = 'DisplayName-' + guest;
let displayName = 'DisplayName-' + Math.random();
//TODO: Check whether the seat is available
// If the new screen name is not an empty string
let isPlayerInCurrentTable = persistence.isPlayerInCurrentTable(tableToken, userToken);
if (displayName && !isPlayerInCurrentTable) {
var nameExists = false;
let currentPlayersTokenArr = persistence.getTableObjectPlayersToken(table)
for (var token in currentPlayersTokenArr) {
let gamePlayer = persistence.getPlayerPlayer(currentPlayersTokenArr[token])
if (typeof gamePlayer !== "undefined" && gamePlayer.public.name === displayName) {
nameExists = true;
break;
}
}
if (!nameExists) {
//Emit event to inform the admin for requesting to sit on the table.
let ownerToken = persistence.getTableObjectOwnerToken(table);
let ownerSocket = persistence.getPlayerSocket(ownerToken);
ownerSocket.emit('requested-to-sit', {
seat: data.seat,
secondaryUserToken: userToken,
displayName,
numberOfChips: envConfig.defaultNumberOfChips
});
callback(prepareResponse({userToken}, 'Player connected successfully.'));
} else {
callback(prepareResponse({}, 'This name is already taken'));
}
} else {
callback(prepareResponse({}, 'This user has already joined to a game. Try clear caching'));
}
});
In my code I'm getting data from another code in guest.user.service. But I get undefined to the value of "guest"
Follows are the methods I have used in guest.user.service
exports.findById = (id) => {
return new Promise(function(resolve, reject) {
guestUserModel.findById(id, (err, data) =>{
if(err){
reject(err);
} else {
resolve(data);
}
});
});
};
exports.getGuestUserByPlayerToken = (playerToken) => {
var player = playerService.findOne({ token: playerToken })
.then(function (data) {
return self.findById(data.guestUser._id.toString());
})
.then(function (guestUser) {
return guestUser.displayName;
})
.catch(function (err) {
throw new Error(err);
})
};
Although I get my displayName for the return value It is not passed to the "guest" in my socket.Is there any syntax issue to get data as I'm using promises.please help

exports.getGuestUserByPlayerToken = async playerToken => {
try {
let player = await playerService.findOne({token:playerToken});
return playerService.findById(player.guestUser._id)
} catch(error) {
console.log(error);
return null;
}
};
This is just handle error on awaited promise not returned one. You need to handle that in caller side.

Related

Get and return value outside function - Nodejs

I'm working on some method that have a callback with value, that I need to return and response, but value is null outside callback funciton
How can I solve?
async function createChannel(req) {
let user_id = req.query.user_id;
let chat_name = req.query.chat_name;
var chimesdkmessaging = new AWS.ChimeSDKMessaging({region: region});
var channel = null;
try {
let dateNow = new Date();
const params = {
Name: chat_name,
AppInstanceArn: config.aws_chime_app_istance,
ClientRequestToken: dateNow.getHours().toString() + dateNow.getMinutes().toString(),
ChimeBearer: await AppInstanceUserArn(user_id),
AppInstanceUserArn of the user making the API call.
Mode: 'RESTRICTED',
Privacy: 'PRIVATE'
};
chimesdkmessaging.createChannel(params, function (err, data) {
if (err) {
console.log(err, err.stack);
} // an error occurred
else {
console.log(data); // successful response
console.log('Assegno il canale: ' + data.ChannelArn);
channel = data.ChannelArn; // <----- VALUE I WANT TO RETURN OUTSIDE
}
});
} catch (e) {
return response({error: e}, 500);
}
return response({data: channel},200); // <---- but this channel is null
}
wrap with Promise
let user_id = req.query.user_id;
let chat_name = req.query.chat_name;
var chimesdkmessaging = new AWS.ChimeSDKMessaging({region: region});
let channel = null;
try {
let dateNow = new Date();
const params = {
Name: chat_name,
AppInstanceArn: config.aws_chime_app_istance,
ClientRequestToken: dateNow.getHours().toString() + dateNow.getMinutes().toString(),
ChimeBearer: await AppInstanceUserArn(user_id),
AppInstanceUserArn of the user making the API call.
Mode: 'RESTRICTED',
Privacy: 'PRIVATE'
};
channel = await new Promise((resolve,reject)=>{
chimesdkmessaging.createChannel(params, function (err, data) {
if (err) {
console.log(err, err.stack);
reject(err)
} // an error occurred
else {
console.log(data); // successful response
console.log('Assegno il canale: ' + data.ChannelArn);
resolve(data.ChannelArn)// <----- VALUE I WANT TO RETURN OUTSIDE
}
});
})
} catch (e) {
return response({error: e}, 500);
}
return response({data: channel},200); // <---- but this channel is null
}

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'roleId' of undefined

I have a requirement that requires me to validate if a user is selecting a correct manager. The association between them is the group id each belongs to. A user can be associated to one group id and a manager can be associated to more than one group id. When allowing a user to select his manager, I need to validate if the user's group id exists in the manager's list of group ids. Here is the code i have implemented below but I get UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'roleId' of undefined
My route file account.ts has the following codeblock
let promise = accountController.update(user);
promise.then(function(data) {
if (data.IsSuccessful == true)
{
result.IsSuccessful = true;
result.SuccessMessage = process.env.USER_UPDATED || "User changed";
return res.status(200).json(result);
}
else
{
result.IsSuccessful = false;
result.ReasonForFailure = data.ReasonForFailure;
res.status(200).json(result);
}
}).catch(function(err){
result.IsSuccessful = false;
result.ReasonForFailure = err.message;
res.status(200).json(result);
});
My controller file account.ts has the following code block for the update method
update = (account: Account) : Promise<Result<Account>> => {
var thisObj = this;
return new Promise<Result<Account>>(function (resolve, reject){
let result = new Result<Account>();
result.Data = account;
MongoClient.connect(config.database.uri, { useUnifiedTopology: true } , async function(err: any, db: any) {
if (err) {
// throw err;
result.IsSuccessful = false;
result.ReasonForFailure = err.message;
reject(result);
}
var dbo = db.db(config.database.name);
var newvalues = { $set:
{
name: account.name,
title: account.title,
organization: account.organization,
reportingTo: account.reportingTo,
workNumber: account.workNumber,
mobileNumber: account.mobileNumber,
allowNotification: account.allowNotification,
allowEmail: account.allowEmail,
groups: account.groups,
updatedDate: account.updatedDate,
isProfileSetupComplete: true,
photo:account.photo
}
};
let existingUser: any;
var query = {email:account.email};
var resultArray = await dbo.collection("users").find(query).toArray();
if (resultArray.length > 0) {
existingUser = resultArray[0];
} else {
db.close();
result.ReasonForFailure = process.env.INVALID_USER_ID || "Invalid User Id";
result.IsSuccessful = false;
reject(result);
}
console.log(existingUser);
if (existingUser.roleId == "1") { //roleId="1" means user
//validate manager id. reportingTo id must be a manager
var queryReporting = { _id: account.reportingTo };
let managerUser: any;
var resultManagerArray = await dbo.collection("users").find(queryReporting).toArray();
if (resultManagerArray.length > 0) {
console.log("managerUser in");//<--This is not printing in the console log
managerUser = resultManagerArray[0];
} else {
db.close();
result.ReasonForFailure = "Invalid reporting id.";// process.env.INVALID_USER_ID || "Invalid User Id";
result.IsSuccessful = false;
resolve(result);
}
//validate manager user
console.log("managerUser out");
console.log(managerUser);
if (managerUser.roleId !== "2"){//<--UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'roleId' of undefined
result.IsSuccessful = false;
result.ReasonForFailure = "Reporting to must be a Manager";
reject(result);
}
//manager and user must be associated with same group
if (!managerUser.groups.includes(account.groups)) {
result.IsSuccessful = false;
result.ReasonForFailure = "Incorrect Manager selection. Employee must be associated with a group the manager is associated with."
reject(result);
}
}
dbo.collection("users").updateOne(query, newvalues, function(err: any, resultSet: any) {
if (err) {
//throw err;
db.close();
result.IsSuccessful = false;
result.ReasonForFailure = err.message;
reject(result);
} else {
result.SuccessMessage = oldImage;
result.IsSuccessful = true;
db.close();
resolve(result);
}
});
});
});
}
managerUser.roleId !== "2" in the above code is the place where I get the UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'roleId' of undefined
I have put await in first call to the find query and it worked as expected waiting for the call to finish but the next await has no effect it seems. The execution didn't wait for the call to finish.
Can you please assist what I'm missing here?
Thanks,
Hemant.
You're probably missing return statements after all the resolve(result);/reject(result); calls. Unlike return and throw, they're ordinary function calls and do not terminate the execution of the function.
Additionally you shouldn't pass an async function as a callback to a function that doesn't handle the returned promise. You should only promisify the connect call alone, wait for its result, and continue the rest of your function after await or in a then callback to ensure errors are handled appropriately.
update = async (account: Account) : Promise<Result<Account>> => {
let result = new Result<Account>();
result.Data = account;
try {
const db = await MongoClient.connect(config.database.uri, { useUnifiedTopology: true });
try {
const dbo = db.db(config.database.name);
const newvalues = {
$set: {
name: account.name,
title: account.title,
organization: account.organization,
reportingTo: account.reportingTo,
workNumber: account.workNumber,
mobileNumber: account.mobileNumber,
allowNotification: account.allowNotification,
allowEmail: account.allowEmail,
groups: account.groups,
updatedDate: account.updatedDate,
isProfileSetupComplete: true,
photo:account.photo
}
};
var resultArray = await dbo.collection("users").find({email: account.email}).toArray();
if (resultArray.length == 0) {
result.ReasonForFailure = process.env.INVALID_USER_ID || "Invalid User Id";
result.IsSuccessful = false;
return result;
}
const existingUser = resultArray[0];
console.log(existingUser);
if (existingUser.roleId == "1") {
var resultManagerArray = await dbo.collection("users").find({ _id: account.reportingTo }).toArray();
if (resultManagerArray.length == 0) {
result.ReasonForFailure = "Invalid reporting id.";// process.env.INVALID_USER_ID || "Invalid User Id";
result.IsSuccessful = false;
return result;
}
console.log("managerUser in");
const managerUser = resultManagerArray[0];
console.log("managerUser out");
console.log(managerUser);
if (managerUser.roleId !== "2") {
result.IsSuccessful = false;
result.ReasonForFailure = "Reporting to must be a Manager";
return result;
}
//manager and user must be associated with same group
if (!managerUser.groups.includes(account.groups)) {
result.IsSuccessful = false;
result.ReasonForFailure = "Incorrect Manager selection. Employee must be associated with a group the manager is associated with."
return result;
}
}
const resultSet = await dbo.collection("users").updateOne(query, newvalues);
result.SuccessMessage = oldImage;
result.IsSuccessful = true;
return result;
} finally {
db.close()
}
} catch(err) {
result.IsSuccessful = false;
result.ReasonForFailure = err.message;
return result;
}
};

pass mysql value from node js to angular

Hi i have this post function to call create function which will insert to database
router.post('/', async (req, res, next) =>
{
const body = req.body;
console.log("tu sam todo_task",req.body);
try
{
const todo_task = await TodoTaskService.create(body);
console.log(todo_task, "function")
// created the todo_task!
return res.status(201).json({ todo_task: todo_task });
}
catch(err)
{
}
});
Then in second snippet i have this create function in service class where i want to return result from mysql query
class TodoTaskService
{
static create(data)
{
console.log("tu sam service todo_task create");
var vres = todoTaskValidator.validate(data, todo_taskVSchema);
/* validation failed */
if(!(vres === true))
{
let errors = {}, item;
for(const index in vres)
{
item = vres[index];
errors[item.field] = item.message;
}
throw {
name: "ValidationError",
message: errors
};
}
console.log("tu sam service todo_task validation passed");
let todo_task = new TodoTaskModel(data.todo_task_name, data.todo_task_complete_f);
let connection = mysql.createConnection(dev);
// insert statment
let sql = `INSERT INTO todo_task (todo_task_name,todo_task_complete_f) VALUES (?);`
let values = [data.todo_task_name, data.todo_task_complete_f];
// execute the insert statment
connection.query(sql, [values], (err, results, fields) => {
if (err) {
global.query = "Database error";
console.log(err.message + "zasto");
return err
}
else{
// get inserted rows
global.query = "OK";
todo_task.todo_task_id = results.insertId
console.log("rows inserted",todo_task);
return todo_task;
}
});
}
}
How can i pass return todo_task from connection.query back to the first post function and send it to angular?
I've found a solution on my own, don't know how if it's the best practice but here is my solution, I'm using callback to pass the value
router.post('/', async (req, res, next) =>
{
const body = req.body;
try
{
return await TodoTaskService.create(body,function (result){
console.log(result, "function result")
todo_task = result;
return res.status(201).json({ todo_task: todo_task });
});
// created the todo_task!
//return res.status(201).json({ todo_task: todo_task });
}
returning callback with result
class TodoTaskService
{
static create(data,callback)
{
var vres = todoTaskValidator.validate(data, todo_taskVSchema);
/* validation failed */
if(!(vres === true))
{
let errors = {}, item;
for(const index in vres)
{
item = vres[index];
errors[item.field] = item.message;
}
throw {
name: "ValidationError",
message: errors
};
}
console.log("tu sam service todo_task validation passed");
let todo_task = new TodoTaskModel(data.todo_task_name, data.todo_task_complete_f);
/* todo_task.uid = 'c' + counter++;
todo_tasks[todo_task.uid] = todo_task; */
let connection = mysql.createConnection(dev);
// insert statment
let sql = `INSERT INTO todo_task (todo_task_name,todo_task_complete_f) VALUES (?);`
let values = [data.todo_task_name, data.todo_task_complete_f];
// execute the insert statment
connection.query(sql, [values], (err, results, fields) => {
if (err) {
global.query = "Database error";
console.log(err.message + "zasto");
return err
}
else{
// get inserted rows
global.query = "OK";
todo_task.todo_task_id = results.insertId
console.log("rows inserted",todo_task);
return callback(todo_task);
}
});
}

how to handle array of 'promis'

I built a database that contains a list of users who receive messages from firebase with a request key. Every time a new request with status 'open' inserted, I am trying to sort them all by the value of 'Timestamp' and send it by this order to the receivers(each receiver will get one message).
if the list of receivers is empty I want to hold it, until another receiver will be added to the list and continue to the next request.
I am not sure how to send each 'promise' separately one after another-
exports.notificationListener=functions.database.ref('requests')
.onWrite(event=>{
const ref = event.data.ref;
let requests= [];
var query=ref.orderByChild('TimeStamp');
query.once('value',function(snap){
snap.forEach(request=>{
if(request.val().Status==OPEN)
requests.push(request.key);
});
});
for (let key of requests) {
return getOnlinReceiversToken().then(token=>{
let msg = {
data: {
source: key
}
};
return admin.messaging().sendToDevice(token, msg);
)};
}
});
function getOnlinReceiversToken() {
let result = new Promise((resolve, reject) => {
receiverRef.once('value', (snap) => {
resolve(snap);
},
(err) => {
reject(err);
});
});
return result.then(snap => {
snap.forEach(child => {
if(child.Status == ONLINE){
let token = helper.getToken(child.key,db);
break;
}
});
return token;
});
}
try something like this
var promisesArray = [];
for (let key of requests) {
var currentPromise = getOnlinReceiversToken().then(token=>{
let msg = {
data: {
source: key
}
};
return admin.messaging().sendToDevice(token, msg);
});
promisesArray.push(currentPromise);
}
return Promise.all(promisesArray);
You could use a function that calls itself to iterate through the promises sequentially to send them one after the other
function runPromise(index) {
// jump out of loop if there are no more requests
if (index >= requests.length) {
return console.log('finished!');
}
return getOnlinReceiversToken().then((token) => {
let msg = {
data: { source: key }
};
admin.messaging().sendToDevice(token, msg);
// iterate to the next item
return runPromise(index + 1);
}).catch((err) => {
// break out of loop when an error occurs
console.log(err);
});
}
runPromise(0);

wit.ai : sessionid undefined in my runActions function

I am writing my first apps with wit.ai using a node.js backend. I found some posts here similar to my question, but not really the answer :
I use a socket.io to communicate with my node script.
The two relevant parts of my node are :
io.sockets.on('connection', function (socket) {
socket.on('message',
function(data) {
var json = JSON.parse(data);
var sid = json['sessionid'];
console.log("Received on sid " + sid);
if (_sessions[sid] == undefined) {
_sessions[sid] = {};
_sessions[sid].context = {};
}
_sessions[sid].socket = socket;
client.runActions(sid, json['text'], _sessions[sid].context, 30)
.then((context) => {
_sessions[sid].context = context;
}
)
.catch((err) =>
{
console.error('Oops! Got an error from Wit: ', err.stack || err);
}
);
}
);
}
);
========
const actions = {
send(request, response) {
const {sessionId, context, entities} = request;
const {text, quickreplies} = response;
return new Promise(function(resolve, reject) {
var session = _sessions[sessionId];
console.log("-------------------------------");
console.dir(context);
console.log("-------------------------------");
session.socket.emit("message", JSON.stringify(response));
return resolve();
});
},
gettaxi ({sessionid, context, text, entities}) {
return new Promise(function(resolve, reject) {
console.log(`Session ${sessionid} received ${text}`);
var quand = firstEntityValue(entities, "quand");
if (!quand && context['quand'] != undefined) quand = context['quand'];
var depart = firstEntityValue(entities, "depart");
var arrivee = firstEntityValue(entities, "arrivee");
if (depart) {
console.log("Found depart");
context.depart = depart;
delete context.missing_depart;
}
else {
context.missing_depart = true;
}
if (arrivee) {
console.log("Found arrivee");
context.arrivee = arrivee;
delete context.missing_arrivee;
}
else {
context.missing_arrivee = true;
}
console.dir(context);
if (quand) {
console.log("Found quand");
context.quand = quand;
delete context.missing_quand;
}
else {
context.missing_quand = true;
}
return resolve(context);
}
);
},
};
All is working rather good, except than my gettaxi receives a undefined sessionid.
It's not the case for the send function that receives the correct sessionid.
What am I doing wrong ?

Resources