I made a simple web app with node.js and hosted it with heroku. The main process does many operations, one of which is reading and writing a text file with ids. However, when I try to send this file from a different process to my email with nodemailer it is sent as blank. The file is initially blank but then is written by the main process; the main process read text from it too so I know the problem is not there. Can you tell me why it isn't working?
Edit: I know for sure that when I send the file is not empty (i do console.log with the content of the file)
Main process code:
function handleSubscriptions(event){
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var timeOfPostback = event.timestamp;
var payload = event.postback.payload;
console.log("Received postback for user %d and page %d with payload '%s' " +
"at %d", senderID, recipientID, payload, timeOfPostback);
if(payload == "iscrizione"){
fs.appendFile("./users.txt", senderID + ",", function (err) {
if (err) throw err;
console.log('The id was appended to file!');
});
var data = fs.readFile('./users.txt', function(err, data) {
if (err) throw err;
processData(String(data));
});
function processData(data){
var arr = data.split(",");
for(i = 0; i < arr.length - 1; i++){
var val = parseInt(arr[i]);
msg = "user number " + i + " :"+ val ;
console.log(msg)
}
}
sendMessage(senderID, "Complimenti, sei iscritto!");
}
}
Sender code:
fs.readFile("./users.txt", function (err, data) {
var message = {
sender: email,
to: email,
subject: 'File user',
body: 'File in allegato',
attachments: [{'filename': 'users.txt', 'content': data}]
};
transporter.sendMail(message, function(error, info){
if (error) {
console.log('Error occurred');
console.log(error.message);
return;
}
console.log('Message 2 sent successfully!');
transporter.close();
});
});
It sounds like a problem with concurrency - you are probably reading the file before it is written to.
You need to make sure that you are not reading the values before they are written. Without seeing a single line of code it is impossible to give you any more specific advice than that.
Related
Working with NodeJS for the first time, trying to build a public endpoint that an accept an XML file, convert it to JSON, save it to MongoDB, then send a 200 HTTP status code, if everything went well. But the Express route completes and sends a response long before the code writing to the database completes.
A slightly simplified version:
app.post('/ams', function (req, res) {
try {
if (Object.keys(req.body).length === 0) {
console.log("request body was empty");
// throw new EmptyBodyException(req.body);
message = message + "Request body was empty \n";
}
let body_keys = Object.keys(req.body);
let body_values = Object.values(req.body);
let xml_string = body_keys[0] + ":" + body_values[0];
let xml = xml_string.trim();
console.log("The trimmed XML:");
console.log(xml);
// convert XML to JSON
xml2js.parseString(xml, (err, json) => {
if(err) {
message = "xml2js.parseString failed, xml was:." + xml + "\n\n" + err;
console.log(message);
res.status(500);
res.send(message);
}
const documentType = json.Document.DocumentType;
if (documentType == 945) {
const shipment = json.Document.Shipment[0];
const shipment_header = shipment.ShipmentHeader[0];
const addresses = shipment.Addresses[0].Address;
const order_header = shipment.Orders[0].Order[0].OrderHeader[0];
const cartons = shipment.Orders[0].Order[0].Cartons[0].Carton;
const unique_id = shipment_header.ShipmentID[0];
found_document_promise = document_is_redundant(AMS_945, unique_id);
found_document_promise.then(function (found_document) {
if (found_document != null) {
console.log("Redundant document. Perhaps a Pair Eyewear engineer was running a test?");
res.status(200);
message = "Redundant document. Perhaps a Pair Eyewear engineer was running a test? documentType: " + documentType;
res.send(message);
} else {
new AMS_945({
shipment_header : shipment_header,
addresses : addresses,
order_header : order_header,
cartons : cartons,
unique_id : unique_id
})
.save()
.then(function () {
// console.log("saved AMS_945");
message = "saved AMS_945";
res.status(200);
res.send(message);
})
.catch(function (err) {
message = "error when saving AMS_945 to database: " + "\n\n" + err;
console.log(message);
res.status(500);
res.send(message);
});
}
})
.catch(function(err) {
message = "error when checking for a redundant AMS_945 document: " + "\n\n" + err;
console.log(message);
res.status(500);
res.send(message);
});
// down at the bottom I have some generic catch-all:
res.status(200);
res.send("Catch all response.")_;
If I don't have the catch all response at the end then the connection simply hangs until the 30 second timeout is hit, and then I get 504 Bad Gateway.
With the catch-all response at the bottom, thankfully I don't get the timeout error, but I do get an error "Sending headers after response was sent" because at some point the database code returns and tries to send its response, but this is long after the Express route function has completed and sent that generic catch-all code that I have at the bottom.
I'd be happy to get rid of the catch-all res.send() and just have the res.send() inside the database code, but that never seems to return.
So how to I get the Express route function to wait till the database code has returned?
I updated the function to create the CSV file but now I'm getting an error:
In upload function
internal/streams/legacy.js:57
throw er; // Unhandled stream error in pipe.
^
Error: ENOENT: no such file or directory, open 'C:\Users\shiv\WebstormProjects\slackAPIProject\billingData\CSV\1548963844106output.csv'
var csvFilePath = '';
var JSONFilePath = '';
function sendBillingData(){
var message = '';
axios.get(url, {
params: {
token: myToken
}
}).then(function (response) {
message = response.data;
fields = billingDataFields;
// saveFiles(message, fields, 'billingData/');
saveFilesNew(message, fields, 'billingData/');
var file = fs.createReadStream(__dirname + '/' + csvFilePath); // <--make sure this path is correct
console.log(__dirname + '/' + csvFilePath);
uploadFile(file);
})
.catch(function (error) {
console.log(error);
});
}
The saveFilesNew function is:
function saveFilesNew(message, options, folder){
try {
const passedData = message;
var relevantData='';
if (folder == 'accessLogs/'){
const loginsJSON = message.logins;
relevantData = loginsJSON;
console.log(loginsJSON);
}
if(folder == 'billingData/'){
relevantData = passedData.members;
const profile = passedData.members[0].profile;
}
//Save JSON to the output folder
var date = Date.now();
var directoryPath = folder + 'JSON/' + date + "output";
JSONFilePath = directoryPath + '.json';
fs.writeFileSync(JSONFilePath, JSON.stringify(message, null, 4), function(err) {
if (err) {
console.log(err);
}
});
//parse JSON onto the CSV
const json2csvParser = new Json2csvParser({ fields });
const csv = json2csvParser.parse(relevantData);
// console.log(csv);
//function to process the CSV onto the file
var directoryPath = folder + 'CSV/' + date + "output";
csvFilePath = directoryPath + '.csv';
let data = [];
let columns = {
real_name: 'real_name',
display_name: 'display_name',
email: 'email',
account_type: 'account_type'
};
var id = passedData.members[0].real_name;
console.log(id);
console.log("messageLength is" +Object.keys(message.members).length);
for (var i = 0; i < Object.keys(message.members).length; i++) {
console.log("value of i is" + i);
var display_name = passedData.members[i].profile.display_name;
var real_name = passedData.members[i].profile.real_name_normalized;
var email = passedData.members[i].profile.email;
var account_type = 'undefined';
console.log("name: " + real_name);
if(passedData.members[i].is_owner){
account_type = 'Org Owner';
}
else if(passedData.members[i].is_admin){
account_type = 'Org Admin';
}
else if(passedData.members[i].is_bot){
account_type = 'Bot'
}
else account_type = 'User';
data.push([real_name, display_name, email, account_type]);
}
console.log(data);
stringify(data, { header: true, columns: columns }, (err, output) => {
if (err) throw err;
fs.writeFileSync(csvFilePath, output, function(err) {
console.log(output);
if (err) {
console.log(err);
}
console.log('my.csv saved.');
});
});
} catch (err) {
console.error(err);
}
}
The upload file function is:
function uploadFile(file){
console.log("In upload function");
const form = new FormData();
form.append('token', botToken);
form.append('channels', 'testing');
form.append('file', file);
axios.post('https://slack.com/api/files.upload', form, {
headers: form.getHeaders()
}).then(function (response) {
var serverMessage = response.data;
console.log(serverMessage);
});
}
So I think the error is getting caused because node is trying to upload the file before its being created. I feel like this has something to do with the asynchronous nature of Node.js but I fail to comprehend how to rectify the code. Please let me know how to correct this and mention any improvements to the code structure/design too.
Thanks!
You don't wait for the callback provided to stringify to be executed, and it's where you create the file. (Assuming this stringify function really does acccept a callback.)
Using callbacks (you can make this cleaner with promises and these neat async/await controls, but let's just stick to callbacks here), it should be more like:
function sendBillingData() {
...
// this callback we'll use to know when the file writing is done, and to get the file path
saveFilesNew(message, fields, 'billingData/', function(err, csvFilePathArgument) {
// this we will execute when saveFilesNew calls it, not when saveFilesNew returns, see below
uploadFile(fs.createReadStream(__dirname + '/' + csvFilePathArgument))
});
}
// let's name this callback... "callback".
function saveFilesNew(message, options, folder, callback) {
...
var csvFilePath = ...; // local variable only instead of your global
...
stringify(data, { header: true, columns: columns }, (err, output) => {
if (err) throw err; // or return callbcack(err);
fs.writeFile(csvFilePath , output, function(err) { // NOT writeFileSync, or no callback needed
console.log(output);
if (err) {
console.log(err);
// callback(err); may be a useful approach for error-handling at a higher level
}
console.log('my.csv saved.'); // yes, NOW the CSV is saved, not before this executes! Hence:
callback(null, csvFilePath); // no error, clean process, pass the file path
});
});
console.log("This line is executed before stringify's callback is called!");
return; // implicitly, yes, yet still synchronous and that's why your version crashes
}
Using callbacks that are called only when the expected events happen (a file is done writing, a buffer/string is done transforming...) allows JS to keep executing code in the meantime. And it does keep executing code, so when you need data from an async code, you need to tell JS you need it done before executing your piece.
Also, since you can pass data when calling back (it's just a function), here I could avoid relying on a global csvFilePath. Using higher level variables makes things monolithic, like you could not transfer saveFilesNew to a dedicated file where you keep your toolkit of file-related functions.
Finally, if your global process is like:
function aDayAtTheOffice() {
sendBillingData();
getCoffee();
}
then you don't need to wait for the billing data to be processed before starting making coffee. However, if your boss told you that you could NOT get a coffee until the billing data was settled, then your process would look like:
function aDayAtTheOffice() {
sendBillingData(function (err) {
// if (err) let's do nothing here: you wanted a coffee anyway, right?
getCoffee();
});
}
(Note that callbacks having potential error as first arg and data as second arg is a convention, nothing mandatory.)
IMHO you should read about scope (the argument callback could be accessed at a time where the call to saveFilesNew was already done and forgotten!), and about the asynchronous nature of No... JavaScript. ;) (Sorry, probably not the best links but they contain the meaningful keywords, and then Google is your buddy, your friend, your Big Brother.)
I have an async.eachSeries() function which process a list of objects. After the list I want a res.send() function so I can send the result back to the frontend.
But I'm getting a
'Can't set headers after they are sent'
error on the res.send() line, which it's looks that the function is called before the list is completely processed.
module.exports.createOrder = function(req,res){
console.log("CreateOrder");
var orderDescription = "";
var payId = new ObjectId(); //create one id, to pay multiple orders at one time
var shopList = groupByShop(req.body.cart);
var orders = [];
var result = {};
console.log("before async");
//the cart is now sorted by shop, now we can make orders for each shop
async.eachSeries(Object.keys(shopList), function(key, callback){
console.log("in async");
var shop = shopList[key];
console.log("before saveOrder");
saveOrder(payId, shop, key, req.body, req.user, function(err, newOrder){
console.log("in saveorder");
if(err){
console.log("Err", err);
callback(err);
}else{
console.log("order saved");
orders.push(newOrder);
callback();
}
})
}, function(err){
if(err){
console.log("One or more orders are not saved:", err);
return res.status(400).json(err);
}else{
console.log("All orders are processed");
result = {
message: 'OK',
order: {
payId: orders[0].payId
}
};
return res.send(200).json(result);
}
})
}
What is going wrong here? Currently testing with one object in the 'shopList', and all log lines are visible in the server console.
When I remove the line, the function is working fine, but, of course, he is not sending any results. I also tried to move the line outside the function, but that cause, of course again, in a empty result{} and a sending before the function is done.
res.send(200) will send a HTML response with content '200' - what you want to do is res.status(200).json(result) although res.json(result) should also work fine.
In below code am I in callbackhell? How to overcome such scenario without using any async modules in pure javascript?
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
The above code is copied in multiple location to make code work as expected.
function processInviteEmails(email_list, user_id, emailCallBack, completionCallback){
function checkEmail(email){
try {
check(email).isEmail();
//is valid email
checkConnected(email, user_id, function(connect_status, user_row, user_meta_row, connect_row){
var e_data;
//insert to connect and send msg to queue
if(connect_status === 'not connected'){
var cur_date = moment().format('YYYY-MM-DD');
var dbData = {
"first_name": '',
"last_name": '',
"email": email,
"user_id": user_id,
"status": "invited",
"unsubscribe_token": crypto.randomBytes(6).toString('base64'),
"created": cur_date,
"modified": cur_date
};
ConnectModel.insert(dbData, function(result){
if (result.insertId > 0) {
//send to email queue
//Queue Email
MailTemplateModel.getTemplateData('invitation', function(res_data){
if(res_data.status === 'success'){
var unsubscribe_hash = crypto.createHash("md5")
.update(dbData.unsubscribe_token + email)
.digest('hex');
var unsubscribe_link = app.locals.SITE_URL+'/unsubscribe/' + result.insertId + '/' + unsubscribe_hash;
var template_row = res_data.template_row;
var user_full_name = user_row.user_firstname+' '+ user_row.user_lastname;
var invitation_link = 'http://'+user_row.url_alias+'.'+ app.locals.SITE_DOMAIN;
var mailOptions = {
"type": 'invitation',
"to": dbData.email,
"from_name" : user_full_name,
"subject": template_row.message_subject
.replace('[[USER]]', user_full_name),
"text": template_row.message_text_body
.replace('[[USER]]', user_full_name)
.replace('[[INVITATION_LINK]]', invitation_link)
.replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link),
"html": template_row.message_body
.replace('[[USER]]', user_full_name)
.replace('[[INVITATION_LINK]]', invitation_link)
.replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link)
};
mailOptions = JSON.stringify(mailOptions);
//send email to queue
sqsHelper.addToQueue(cfg.sqs_invitation_url, mailOptions, function(data){
if(data){
e_data = null;
}
else{
e_data = new Error('Unable to Queue ');
}
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
});
}
else{
e_data = new Error('Unable to get email template');
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
}
});
}
else{
e_data = new Error('Unable to Insert connect');
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
}
});
}
else{
e_data = new Error('Already connected');
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
}
});
} catch (e) {
//invalid email
emailCallBack(e, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
}
}
checkEmail(email_list.pop());
}
Yes you are in callback hell. The solution assuming you don't want to use async (which I doubt you can justify other than prejudice) consists of:
1) Make more top-level functions. Each function should perform either 1 or 2 IO operations as a rule of thumb.
2) Call those functions, making your code follow a pattern of a long list of short core functions organized into business logic by a small list of control flow "glue" functions.
Instead of:
saveDb1 //lots of code
saveDb2 //lots of code
sendEmail //lots of code
Aim for:
function saveDb1(arg1, arg2, callback) {//top-level code}
function saveDb2(arg1, arg2, callback) {//top-level code}
function sendEmail(arg1, arg2, callback) {//top-level code}
function businessLogic(){//uses the above to get the work done}
3) Use more function arguments instead of relying so much on closures
4) Emit events and DECOUPLE YOUR CODE! See how you have nested code writing stuff to the database and then building an email and adding it to a queue? Don't you see how those two do not need to exist one on top of the other? Emails lend themselves very well to a core business logic emitting events and an email module listening to those events and queueing the mail.
5) Decouple application-level service connection code from specific transaction business logic. Dealing with connections to network services should be handled more broadly and not embedded with a specific set of business logic.
6) Read other modules for examples
As to should you use an async library, you can and should make up your own mind about that but AFTER you know, and know pretty well, each and every one of these approaches:
callbacks and basic functional javascript techniques
events
promises
Helper libraries (async, step, nimble, etc)
Any serious node.js developer knows how to use and work within ALL of those paradigms. Yes, everyone has their favored approach and maybe some nerd rage about the non-favored approaches, but none of these are difficult and it's bad to get set in your decision without being able to point to some non-trivial code you wrote from scratch in each paradigm. Also, you should try several helper libraries and understand how they work and why they are going to save you boilerplate. Studying the work of Tim Caswell's Step or Caolan McMahon's async is going to be very enlightening. Have you seen the everyauth source code's use of promises? I don't like it personally but I surely have to admit that the author has squeezed damn near every last bit of repetition out of that library, and the way he uses promises will turn your brain into a pretzel. These people are wizards with much to teach. Don't scoff at those libraries just for hipster points or whatever.
Also a good external resource is callbackhell.com.
"If you try to code bussiness db login using pure node.js, you go straight to callback hell"
I've recently created a simple abstraction named WaitFor to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor
check the database example:
Database example (pseudocode)
pure node.js (mild callback hell):
var db = require("some-db-abstraction");
function handleWithdrawal(req,res){
try {
var amount=req.param("amount");
db.select("* from sessions where session_id=?",req.param("session_id"),function(err,sessiondata) {
if (err) throw err;
db.select("* from accounts where user_id=?",sessiondata.user_ID),function(err,accountdata) {
if (err) throw err;
if (accountdata.balance < amount) throw new Error('insufficient funds');
db.execute("withdrawal(?,?),accountdata.ID,req.param("amount"), function(err,data) {
if (err) throw err;
res.write("withdrawal OK, amount: "+ req.param("amount"));
db.select("balance from accounts where account_id=?", accountdata.ID,function(err,balance) {
if (err) throw err;
res.end("your current balance is " + balance.amount);
});
});
});
});
}
catch(err) {
res.end("Withdrawal error: " + err.message);
}
Note: The above code, although it looks like it will catch the exceptions, it will not.
Catching exceptions with callback hell adds a lot of pain, and i'm not sure if you will have the 'res' parameter
to respond to the user. If somebody like to fix this example... be my guest.
using wait.for:
var db = require("some-db-abstraction"), wait=require('wait.for');
function handleWithdrawal(req,res){
try {
var amount=req.param("amount");
sessiondata = wait.forMethod(db,"select","* from session where session_id=?",req.param("session_id"));
accountdata= wait.forMethod(db,"select","* from accounts where user_id=?",sessiondata.user_ID);
if (accountdata.balance < amount) throw new Error('insufficient funds');
wait.forMethod(db,"execute","withdrawal(?,?)",accountdata.ID,req.param("amount"));
res.write("withdrawal OK, amount: "+ req.param("amount"));
balance=wait.forMethod(db,"select","balance from accounts where account_id=?", accountdata.ID);
res.end("your current balance is " + balance.amount);
}
catch(err) {
res.end("Withdrawal error: " + err.message);
}
Note: Exceptions will be catched as expected.
db methods (db.select, db.execute) will be called with this=db
Your Code
In order to use wait.for, you'll have to STANDARDIZE YOUR CALLBACKS to function(err,data)
If you STANDARDIZE YOUR CALLBACKS, your code might look like:
//run in a Fiber
function processInviteEmails(email_list, user_id, emailCallBack, completionCallback){
while (email_list.length) {
var email = email_list.pop();
try {
check(email).isEmail(); //is valid email or throw
var connected_data = wait.for(checkConnected,email,user_id);
if(connected_data.connect_status !== 'not connected') throw new Error('Already connected');
//insert to connect and send msg to queue
var cur_date = moment().format('YYYY-MM-DD');
var dbData = {
"first_name": '',
"last_name": '',
"email": email,
"user_id": user_id,
"status": "invited",
"unsubscribe_token": crypto.randomBytes(6).toString('base64'),
"created": cur_date,
"modified": cur_date
};
result = wait.forMethod(ConnectModel,'insert',dbData);
// ConnectModel.insert shuold have a fn(err,data) as callback, and return something in err if (data.insertId <= 0)
//send to email queue
//Queue Email
res_data = wait.forMethod(MailTemplateModel,'getTemplateData','invitation');
// MailTemplateModel.getTemplateData shuold have a fn(err,data) as callback
// inside getTemplateData, callback with err=new Error('Unable to get email template') if (data.status !== 'success')
var unsubscribe_hash = crypto.createHash("md5")
.update(dbData.unsubscribe_token + email)
.digest('hex');
var unsubscribe_link = app.locals.SITE_URL+'/unsubscribe/' + result.insertId + '/' + unsubscribe_hash;
var template_row = res_data.template_row;
var user_full_name = user_row.user_firstname+' '+ user_row.user_lastname;
var invitation_link = 'http://'+user_row.url_alias+'.'+ app.locals.SITE_DOMAIN;
var mailOptions = {
"type": 'invitation',
"to": dbData.email,
"from_name" : user_full_name,
"subject": template_row.message_subject
.replace('[[USER]]', user_full_name),
"text": template_row.message_text_body
.replace('[[USER]]', user_full_name)
.replace('[[INVITATION_LINK]]', invitation_link)
.replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link),
"html": template_row.message_body
.replace('[[USER]]', user_full_name)
.replace('[[INVITATION_LINK]]', invitation_link)
.replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link)
};
mailOptions = JSON.stringify(mailOptions);
//send email to queue ... callback(err,data)
wait.forMethod(sqsHelper,'addToQueue',cfg.sqs_invitation_url, mailOptions);
} catch (e) {
// one of the callback returned err!==null
emailCallBack(e, email);
}
} // loop while length>0
completionCallback();
}
// run the loop in a Fiber (keep node spinning)
wait.launchFiber(processInviteEmails,email_list, user_id, emailCallBack, completionCallback);
see? no callback hell
I've put another solution in my blog. It is ugly but it is the most readable thing I could do with pure javascript.
var flow1 = new Flow1(
{
execute_next_step: function(err) {
if (err) {
console.log(err);
};
}
}
);
flow1.execute_next_step();
function Flow1(parent_flow) {
this.execute_next_step = function(err) {
if (err) return parent_flow.execute_next_step(err);
if (!this.next_step) this.next_step = 'START';
console.log('Flow1:', this.next_step);
switch (this.next_step) {
case 'START':
this.next_step = 'FIRST_ASYNC_TASK_FINISHED';
firstAsyncTask(this.execute_next_step.bind(this));
break;
case 'FIRST_ASYNC_TASK_FINISHED':
this.firstAsyncTaskReturn = arguments[1];
this.next_step = 'ANOTHER_FLOW_FINISHED';
this.another_flow = new AnotherFlow(this);
this.another_flow.execute_next_step();
break;
case 'ANOTHER_FLOW_FINISHED':
this.another_flow_return = arguments[1];
this.next_step = 'FINISH';
this.execute_next_step();
break;
case 'FINISH':
parent_flow.execute_next_step();
break;
}
}
}
function AnotherFlow(parent_flow) {
this.execute_next_step = function(err) {
if (err) return parent_flow.execute_next_step(err);
if (!this.next_step) this.next_step = 'START';
console.log('AnotherFlow:', this.next_step);
switch (this.next_step) {
case 'START':
console.log('I dont want to do anything!. Calling parent');
parent_flow.execute_next_step();
break;
}
}
}
I've started looking at socket.io and some MongoDB with mongojs.
Summary: Client doesn't send data to server through socket.io so mongojs doesn't have anything to look for and just returns first document in collection, I'd like it to return null or false so I can take appropriate action.
Any help appreciated, very new to node.js and this.
I need a log in function, but when I click the link I've made to log in this should run from the client:
<script>
var socket = io.connect('http://localhost:13163');
socket.on('connect', function () {
socket.emit(console.log('Client connected'));
});
socket.on('queryResponse', function (res, err) {
if (res == "[object Object]") {
console.log('EMPTY OBJ SERVER: ' + res + ' ' + err);
}
else{
console.log('IF NOT EXEC' + res[0].email)
}
});
//socket.send('client hello');
//pageload
$(function () {
$('#login').click(function () {
var username = $('#username').val();
var password = $('#password').val();
if (!username || !password) {
event.preventDefault();
console.log('Need data in both fields');
}
else {
event.preventDefault();
socket.emit('querydata', function (username, password) {
console.log("CLIENT: Querying server for data...");
});
}
});
});
</script>
This should send the username and password to the server which should then run this:
socket.on('querydata', function (user_username, user_password) {
db.users.find({email: user_username, pass: user_password}, function (err, docs) {
if (err || !docs) {
socket.emit('queryResponse', 'No users found', err);
console.log('if - ' + docs[0].email);
}
else {
socket.emit('queryResponse', docs);
console.log('else - ' + docs[0].email + 'user_password' + user_password + 'user_username' + user_username);
}
});
});
What's weird about this is that, it finds only the first document of the collection.
I've just found out that the 'user_username' and 'user_password' overloads are undefined, is this just some retarded mistake from my side?
You are doing it wrong. In a first look, i see couple of mistakes in your code.
The first one here
if (res == "[object Object]")
You can not control response content in that way. You probably see [object Object] string in your javascript debugger. You have to do this comparison according to the server response as a json data. If it will lead you a trouble you can use JSON.parse(response).
The second one, you do not send username and password to the server actually. You have to use
socket.emit('querydata', { username: username, password: password }, function (data) {
// Server Ack here
}
instead of
socket.emit('querydata', function (username, password) ...
And try this
socket.emit('queryResponse', {err: 'No User Found'});
instad of
socket.emit('queryResponse', 'No User Found', err);
And in your client check the response as
if(response.hasOwnProperty('err')) / /Handle error
In you client side queryResponse listener, try this;
socket.on('queryResponse', function (res) {
if(res.hasOwnProperty('err')) / Handle Error
else // You have an array in `res`
});