How to send data to socket.io from react? - node.js

I've never used Socket.IO before so this is very new for me.
I have a taxi app in react which will send a new order as an event through Socket.IO but I don't see any error or response.
Server Side it looks like this:
client.on('newOrder', function(data){
socketController.newOrder(data, io, client);
});
newOrder: function(data, io, client) {
order.create(data, io, client, function(response){});
}
Order.prototype.create = function (data, io, client, callback) {
console.log("ORDER DATA = " + JSON.stringify(data));
let luggage = 0;
if (typeof data.luggage !== 'undefined')
luggage = data.luggage;
let insertData = {
client_id: data.id_client,
start_address: data.origin.name,
start_lat: data.origin.latitude,
start_lng: data.origin.longitude,
end_address: data.destination.name,
end_lat: data.destination.latitude,
end_lng: data.destination.longitude,
options: JSON.stringify(data.options),
car_options: JSON.stringify(data.car_options),
car_type: data.car_type,
passengers: data.passengers,
luggage: luggage,
payment_method: data.payment_method,
profile_id: data.profile,
profile_type: data.profile_type
};
if (data.schedule_time != null && data.schedule_time.length > 0) {
insertData.schedule_time = data.schedule_time
}
db.query("INSERT INTO orders SET ?", insertData,
function (err, results, fields) {
if (err) {
console.log("Order.create [ERROR: " + err + "]");
return callback({ error: true, message: err });
}
data.id_order = results.insertId;
const timeInsert = {
order_id: data.id_order,
new: new Date().toISOString().slice(0, 19).replace('T', ' ')
};
db.query("INSERT INTO orders_timestamps SET ?", timeInsert, function (err, results, fields) { });
client.emit("orderSaved", { "id_order": data.id_order });
getOrder(data.id_order, function (order) {
sendOrdersToDriver(data, order, io, function (data) {
console.log("Order.create [SUCCESS]");
return callback(data);
});
});
}
);
};
Client Side it looks like this
const data = {
id_client: user.id,
car_type: "executive",
car_options: [],
passengers: 1,
luggage: 2,
payment_method: "cash",
options: [],
origin: { name: pickUp, latitude: pickUpCoordinates.lat, longitude: pickUpCoordinates.lng },
destination: { name: dropOff, latitude: dropOffCoordinates.lat, longitude: dropOffCoordinates.lng },
schedule_time: new Date(),
profile: "",
profile_type: "owner"
}
socket.emit("newOrder", data, function (response) {
console.log('emit response', response);
});

Edit 1:
Let me try to explain how does this callback stuff working,
// here we are at the client-side
// so here from client side i'm sending a data and a callback
// socket.emit('event-name', data, callback); signature
socket.emit('some-event', { a: true }, function(dataFromServer) {
console.log(dataFromServer);
});
// here we are at server-side
socket.on('some-event', function(data, callback) {
// we are getting the data first argument and callback second
// let's say we are testing if data has a === true;
if(data.a) { // same as data.a === true
// here we are gonna send 'hi' to callback
return callback('hi the data was valid for me');
}
// otherwise we are assuming that data wasn't valid
return callback('your data is not okey mate!');
});
So from client-side if you send a data contains { a: true } as prop you should see that callback consoling 'hi the data was valid for me' this.
Otherwise if it doesn't contain a or a: false then you should see 'your data is not okey mate!' from your client's callback.
Consedering this senario; go for your code and check =)
First please check if you socket.connected === true on your frontend.
Second here you are sending data and a callback through your emit
socket.emit("newOrder", data, /*this is your callback*/function (response) {
console.log('emit response', response);
});
And here on your server you are only getting data from client.
// needs to be like this
client.on('newOrder', function(data, callback) {
socketController.newOrder(data, callback, io, client);
});
// same with
newOrder: function(data, callback, io, client) {
// you probably dont need to send this empty callback cause actualy callback
// coming after `data`, `callback`
order.create(data, callback, io, client); //function(response){});
}
// same with
Order.prototype.create = function (data callback, io, client) {
...
sendOrdersToDriver(data, order, io, function (data) {
console.log("Order.create [SUCCESS]");
// here you are calling it so it needs to work if
// your `sendOrdersToDriver` function actually calls it's
// own callback?
return callback(data);
});
}

Related

Tedious sql query returning empty object (can´t return custom array and callback not working)

Im using Tedious in Node JS to return a simple SQL Query :
var Connection = require('tedious').Connection;
var config = {
server: 'myserver.database.windows.net',
authentication: {
type: 'default',
options: {
userName: 'myusername',
password: 'mypassword',
rowCollectionOnDone: true,
rowCollectionOnRequestCompletion: true
}
},
options: {
encrypt: true,
database: 'mydatabase'
}
};
const connection = new Connection(config);
connection.on('connect', function(err) {
if (err) {
console.log(err);
}else{
console.log("Connected");
}
});
var Request = require('tedious').Request
var TYPES = require('tedious').TYPES;
let results = [];
function checkId(cid) {
request = new Request("SELECT * FROM mytable WHERE id = #cid",function(err, rowCount, rows) {
if (err) {
console.log(err);
}
});
request.addParameter('cid', TYPES.NVarChar, cid);
request.on('row', function(row) {
results.push(row);
});
console.log(results) // I can see results array perfectly here
connection.execSql(request);
//return callback(null, results); // Tried setting callback as parameter too in this function but got error "callback is not a function"
}
When I call the statement function outside like this:
var sqlquery = new checkId(passid);
console.log(sqlquery);
I get:
"sqlquery {}"
I other words, an [object Object] but empty (obviously, JSON.strinfigy in empty it's useless). I already tried to use callback as a workaround as commented in the code above but got error, how can I see results array when I call the function ?
Knowing that Tedious it's async and results won´t process on time to get them outside (reason why it´s empty object) and since there´s no specific answer to this anywhere (a lot of theory yes, but not a clear explanation due that some code it´s outdated like curiosly where you use callback as a set function, there´s no guidance of how to mix promises with Tedious properly, answers only show results in console.log or some people may be beginners with the sync/async concept), I post here a commented way that worked for me in case anyone may need it:
///Connection
var Connection = require('tedious').Connection;
var config = {
server: 'myserver.database.windows.net',
authentication: {
type: 'default',
options: {
userName: 'myusername',
password: 'mypassword',
rowCollectionOnDone: true,
rowCollectionOnRequestCompletion: true
}
},
options: {
encrypt: true,
database: 'mydatabase'
}
};
const connection = new Connection(config);
connection.on('connect', function(err) {
if (err) {
console.log(err);
}else{
console.log("Connected");
}
});
var Request = require('tedious').Request
var TYPES = require('tedious').TYPES;
Now , inside an async function you can call this example query with params (must be inside async function in order to use 'return await' and that everything syncs to avoid empty data :
async your_function(){
var id = 'id you want or user inputs';
const allData = [];
// We now set the promise awaiting it gets results
await new Promise((resolve,reject) => {
const request = new Request("SELECT * FROM table WHERE field = #id", function(err, rowCount) {
if (err) {
return reject(err);
} else {
console.log(rowCount + ' rows');
}
});
request.addParameter('id', TYPES.NVarChar, id); //Param id declaration
request.on('row', function(columns) {
columns.forEach(function(column) {
allData.push(column.value); //Push the result to array
});
});
request.on('doneProc', function (rowCount, more, returnStatus, rows) {
console.log('onDoneProc');
return resolve(allData); //Here we resolve allData using promise in order to get it´s content later
});
connection.execSql(request);
});
var mydata = allData; // Now You can assign it or use the same object as well
}
Hope it helps someone as it did to me.

How to use async/await in a single function

I am using google places api to get a list off cafes nearby. So,the api provides max 60 places but they are present in 3 different pages.To get the list of all 60 places, it provides tokens in the first and second page with the help of which we can access remaining places. I wrote a function that stores the place ids in an array.The places from first page is storing fine. But, in the first request i am accessing the token for the next page. The problem i am facing is, the request for second page is being called before assigning of the token.So, it results in an error. How can i make the reqeust for second page to wait until the token value is assigned?
const request= require('postman-request');
const nearbycafes = (latitude,longitude,callback) => {
var placeids=[];
let token;
let count=0;
const url='https://maps.googleapis.com/maps/api/place/nearbysearch/json?location='+latitude+','+longitude+'&radius=1500&type=cafe&key=xyz'
request({url: url, json: true},(error,response)=>{
console.log('ssss');
if(error){
callback('Error connecting to the API',undefined)
}
else if(response.body.results.length==0){
callback('No such address exist. Try something else',undefined)
}
else{
let i=0;
//for(i;i<response.body.results.length;i++){
placeids.push(response.body.results[0].place_id)
//}
if(response.body.next_page_token){
token=response.body.next_page_token;
count++;
console.log(count);
}
}
callback(undefined,{
placeids
})
})
console.log(count);
// if(count===1){
// const url2='https://maps.googleapis.com/maps/api/place/nearbysearch/json?location='+latitude+','+longitude+'&radius=1500&type=cafe&key=xyz='+token+''
// request({url: url2, json: true},(error,response)=>{
// console.log('ssss2');
// if(error){
// callback('Error connecting to the API',undefined)
// }
// else if(response.body.results.length==0){
// callback('No such address exist. Try something else',undefined)
// }
// else{
// let i=0;
// for(i;i<response.body.results.length;i++){
// placeids.push(response.body.results[i].place_id)
// }
// if(response.body.next_page_token){
// token=response.body.next_page_token;
// count++;
// }
// }
// callback(undefined,{
// placeids
// })
// })
// }
}
module.exports = nearbyhospitals;
You need to write a recursive function to get all the pages sequentially:
const request = require('postman-request')
function getPage (lat, long, token, cb) {
const url = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${lat},${long}&radius=1500&type=cafe&key=xyz${token ? `&token=${token}` : ''}`
request({ url: url, json: true }, (error, response) => {
if (error) {
cb(new Error('Error connecting to the API'), undefined)
} else if (response.body.results.length === 0) {
cb(null, [])
} else {
if (response.body.next_page_token) {
getPage(lat, long, response.body.next_page_token, (err, res) => {
if (err) {
return cb(err)
}
cb(undefined, res.concat(response.body.results))
})
} else {
cb(undefined, response.body.results)
}
}
})
}
function nearbycafes (latitude, longitude, callback) {
getPage(latitude, longitude, undefined, callback)
}
module.exports = nearbycafes
// just to try
nearbycafes(43.834527, 13.258358, (err, res) => {
console.log({ err, res })
})
Unfortunately, I cannot see the 'second' request in the code above. I assume the second request is being done in the 'callback' function. If you want to be sure that 'token' is not empty when 'callback' is executed, simply call the callback directly after assignment:
else{
let i=0;
//for(i;i<response.body.results.length;i++){
placeids.push(response.body.results[0].place_id)
//}
if(response.body.next_page_token){
token=response.body.next_page_token;
callback(undefined, { placeids: placeids });
count++;
console.log(count);
}
}
It appears that the positive (I assume) 'callback' call is outside of the 'else' clause. You sure you got the braces correct?
Best approach, though, is to avoid such 'global' variables as token in this case. You could parametrize callback and pass the token via function call. The rule of thumb in such chained requests is as follows:
function A(callback) {
$.ajax({
//...
success: function (result) {
//...
$.ajax({
// ...
success: function (result) {
// ...
}
})
}
});
}

Render the results of two separate async.each methods

I am new to nodejs and async. Having trouble understanding how can I wrap the two separate async.each methods to have one res.render...I am trying to display a list of valid account ids, and valid user ids on the front end.
The two separate async.each methods are:
async.each(account_ids, function(accountId, callback) {
console.log('Processing accountId ' + accountId);
callingExternalApi(accountId, callback, function(err, response){
if(err){
console.log("error account");
}
console.log("account response is: ", response);
});
}, function(err) {
if( err ) {
console.log('An account failed to process');
} else {
console.log('All accounts have been processed successfully');
}
});
and
async.each(email_ids, function(emailId, callback) {
console.log('Processing email id ' + emailId);
request({
url: emailIdlookupUrl,
method: 'POST',
json: {
email_address: emailId
}
}, function (err, response, body) {
if (err) {
logger.error(err);
req.flash('error', err.message);
return res.redirect('?');
}
if (response.statusCode !== 200) {
const msg = 'Unable to verify user';
req.flash('error', msg);
return res.redirect('?');
}
console.log("user id is: ", body.user.id);
callback();
});
}, function(err) {
if( err ) {
console.log('An email failed to process');
} else {
console.log('All user emails have been processed successfully');
}
});
Any help is highly appreciated. Please excuse me for any redundant callbacks or error logging. Still learning nodejs.
Thanks!!
The main issue is not that you are invoking both of these async.each calls. The problem is that they will run in parallel, and the fastest one to invoke req.* functions or callback function will return a response to the connection.
Both of these functions return promises if their callback parameters are omitted.
I recommend reading up on both the async library and JS async/await in general:
https://javascript.info/async-await
https://caolan.github.io/async/v3/docs.html#each
https://zellwk.com/blog/async-await-express/
Note that async also accepts native async functions, which many finder cleaner and easier to understand.
Here is what I think you want from the code above, including compiling the results into lists:
var request = require("request-promise");
async function checkAccounts(account_ids) {
const valid_accounts = [];
await async.each(account_ids, async function(accountId) {
console.log("Processing accountId " + accountId);
const extAPIresult = await callingExternalApi(accountId);
console.log("account response is: ", extAPIresult);
});
valid_accounts.push(extAPIresult);
console.log("All accounts have been processed successfully");
return valid_accounts;
}
async function checkEmails(email_ids) {
const valid_emails = [];
await async.each(email_ids, async function(emailId) {
console.log("Processing email id " + emailId);
const reqresult = await request({
url: emailIdlookupUrl,
method: "POST",
json: {
email_address: emailId
}
});
if (reqresult.statusCode !== 200) {
throw new Error("Unable to verify user");
}
valid_emails.push(reqresult.body.user.id);
console.log("user id is: ", reqresult.body.user.id);
});
console.log("All emails have been processed successfully");
return valid_emails;
}
async function doChecks() {
const accounts = checkAccounts(account_ids);
const emails = checkEmails(email_ids);
const responses = await Promises.all([accounts, emails]);
console.log("All checks have been processed successfully");
return responses;
}
function get(req, res) {
doChecks()
.then(responses => {
res.send("All checks have been processed successfully");
res.send(String(responses));
})
.catch(err => {
req.flash("error", err.message);
res.redirect("?");
});
}

Return not stopping function

I have the following code
insertcontact(root, args) {
var finalresult = '';
var soap = require('soap');
var url = 'http://192.168.100.2/setlead/webservice.asmx?wsdl';
var soapargs = {
contacto: args.contacto, token: args.token, PrimeiroNome: args.PrimeiroNome, Apelidos: args.Apelidos, Email: args.Email, Telefone: args.Telefone, Origem: args.Origem
};
soap.createClient(url, function (err, client) {
if (err) {
console.log(err);
finalresult = err
return { contacto: "error cliente" };
}
else {
client.OperationDetail(args, function (err, result) {
console.log(result);
return { token: result };
});
}
});
return {
contacto: args.contacto,
PrimeiroNome: args.PrimeiroNome,
token: args.token,
Apelidos: args.Apelidos,
Email: args.Email,
Telefone: args.Telefone,
Origem: args.Origem
};
}
}
The operation does not trigger any error and I do receive the result in the console log. But I don't receive the return declared right after that part. The function goes on and I receive the last return declared. Shouldn't it stop at the return result?
This is a classic mistake in Javascript.
The function will return even before starting to create the soap client, because of its async behavior.
That function implementation is not very good as it returns the params whatever the result of the client creation process.
It would be much better to do it like this, with embeded soap args in the return statement if needed, and of course without the last return statement:
// ...
soap.createClient(url, function (err, client) {
if (err) {
console.log(err);
finalresult = err
return { contacto: "error cliente" };
} else {
client.OperationDetail(args, function (err, result) {
console.log(result);
return {
token: result,
soapargs: soapargs
};
});
}
});
wrap your returned object in parenthesis like this
return ({
contacto: args.contacto,
PrimeiroNome: args.PrimeiroNome,
token: args.token,
Apelidos: args.Apelidos,
Email: args.Email,
Telefone: args.Telefone,
Origem: args.Origem
});

How can I stack request calls so they don't complete until one is finished?

I have an array of items that I need to post to my server. I've tried the following but i never iterates.
var i = 0;
while (i < numOfItems) {
var item = items[i];
var a;
for(var ik in item){
console.log(item[ik]);
a = item[ik]; // Gets the key
break;
}
var formData = {
ID : ID,
UID : UID,
item : a
}
request.post({url:'http://example.com/a', formData: formData}, function(err, httpResponse, body){
if (err) {
return console.error('Post failed:', err);
}
console.log('Post successful! Server responded with:', body);
i++;
});
}
Your code won't work because request.post is asynchronous. If your objective is to make a call for each element in the array, a working and a more elegant solution would be to use Promises.all().
Here's your code modified with Promises —
function postRequest(url, formData) {
return new Promise((resolve, reject) => {
request.post({ url, formData }, function (err, httpResponse, body) {
if (!error) {
resolve({ message: 'Post successful!', response: body });
} else {
reject(err);
}
});
})
}
// Map your data array to an array of Promises
let promises = yourArray.map(element => {
let formData = {
ID: ID,
UID: UID,
item: element
}
return postRequest({ url: 'http://example.com/a', formData: formData })
});
// Wait for all Promises to complete
Promise.all(promises)
.then(results => {
// Handle results
})
.catch(e => {
// Handle error
});
A few things to note -
I'm reusing the fields ID and UID as-is, as it isn't clear where they come from in your code.
Replace yourArray with the array containing your data items.

Resources