Node js - error state of a callback in a loop - node.js

I am using node js to send push notifications to Android devices using GCM and want to delete the device id if I get an error message from Google. The code snippet is attached and runs in a loop (i is number of device ids).
My issue is that if the call returns an error (err4), all future loops return if(err4) as true and all the ids after the first error are deleted. Why is the err4 not getting reset?
for(var i = 0; i < noofdeviceIds; i++){
// some more code here to create the 'message'.
(function(i) {
gcm.send(message, function(err4, messageId){
if (err4) {
console.log("\nError occured: Notification could not be sent with error: ", err4);//
if(err4 == 'NotRegistered' || err4 == 'InvalidRegistration'){
console.log("\nRemoving the entry from the DB.");
var removeEntryQuery = "DELETE FROM devicereg WHERE deviceregId = '" + deviceregIds[i] + "'";
req._dbConnection.query(removeEntryQuery, function(err5, row) {
if(row!=0){console.log("\nDB returned: ", row);}
});
}
}
else {
console.log("\nMessage sent with message ID: ", messageId);
}
});
})(i);
}

Related

Using Promise in afterSave

I am trying to do the following code in cloud code:
//Code for sending push notifications after an update is created
Parse.Cloud.afterSave('AssignmentMod', function(request){
//Only send if the mod is new
console.log("MOD SAVED. NOTIFICATIONS CHECK.")
if(!request.object.existed()) {
console.log("NEW MOD ADDED. NOTIFICATIONS START.")
var mod = request.object
//Get the users who have these classes
var userType = Parse.Object.extend('User')
var usersQuery = new Parse.Query(userType)
usersQuery.equalTo('currentClasses', mod.get("parentClass"))
//Get the users who removed the assignment
var modsType = Parse.Object.extend('AssignmentMod')
//If if was an assignment and removed at some point
var mods1Query = new Parse.Query(modsType)
mods1Query.notEqualTo("assignment", null)
mods1Query.equalTo("assignment", mod.get("assignment"))
mods1Query.equalTo("type", "remove")
//If it was an assignment mod and was removed at some point
var mods2Query = new Parse.Query(modsType)
mods2Query.notEqualTo("assignmentMod", null)
mods2Query.equalTo("assignmentMod", mod.id)
mods2Query.equalTo("type", "remove")
//Get the remove mods for this particular update
var modsQuery = new Parse.Query.or(mods1Query,mods2Query)
//Run the user and mods queries
Parse.Promise.when(
usersQuery.find(),
modsQuery.find()
).then( function(users, removeMods) {
console.log("QUERY 1 COMPLETE.")
//Get all users that copied this remove mod
var copyType = Parse.Object.extend('ModCopy')
var copyQuery = new Parse.Query(copyType)
copyQuery.containedIn("assignmentMod", removeMods)
copyQuery.find().then(function(copies){
console.log("QUERY 2 COMPLETE.")
var copyUsers = copies.map(function(copy){
return copy.get("user")
})
//Get the devices of users that belong to the class, did not remove the assignment, and have an ios devices
var deviceQuery = new Parse.Query(Parse.Installation)
deviceQuery.equalTo("deviceType", "ios")
deviceQuery.containedIn("user", users)
deviceQuery.notContainedIn("user", copyUsers)
//Send the push notification
console.log("PUSHING NOTIFICATIONS")
Parse.Push.send(
{
where: deviceQuery,
data: {
alert: "You have new updates."
}
},
{userMasterKey: true}
).then(
function(){
console.log("SUCCESSFULLY SEND NOTIFICATIONS.")
},
function(error){
throw "Error sending push notifications:" + error.code + " : " + error.message
console.log("FAILED TO SEND NOTIFICATIONS")
}
)
},
function(reason){
throw "Error: " + reason
print("ERROR: " + reason)
})
},
function(reason){
throw "Error: " + reason
print("ERROR: " + reason)
})
}
})
I can see in my logs that "MOD SAVED. NOTIFICATIONS CHECK." and "NEW MOD ADDED> NOTIFICATIONS START." are both logged out. However, I get no other logs after that and no push notifications are sent. I should at leas see the logs, and see none. Is there an issue with parse server using promises inside an afterSave or something? Why am is my code seemingly halting execution when it hits the first promise?
Your afterSave() cloud code must be ended by a response.success() or response.error(error)
You should wait for all your Promises complete end then finish your code with something like:
promise.then( function(){
console.log("END of afterSave() " ;
response.success();
}, function(error){
console.error("error in afterSave() " + " : " + error.message);
response.error(JSON.stringify({code: error.code, message: error.message}));
});
This turned out to be an issue with Heroku hosting. I have not tracked down passed that. If the same code is hosted on AWS or another hosting platform, these issues do not occur. There is likely some server settings Heroku uses in it's default setup that need changed. If you encounter this issue and have more of a solution beyond "Switch off Heroku hosting" then submit an answer and I will accept.

How do I stop a table script from processing?

I am creating an insert script that does some business logic.
Basically, I want to check to see if a value in the inserted item exists in a table. But, it seems like if I find a problem Request.Send() doesn't stop execution and get an error.
I think there is an async issue here. I'm not 100% sure how to solve.
Is there a way to stop execution of the script?
if (item.memberType === 'Family' && item.primaryFamilyMember) {
table
.where({
memberNumber: item.primaryFamilyMember,
memberType: 'Family',
primaryFamilyMember: null })
.read({
success: function(results) {
if (results.length == 0) {
request.respond(statusCodes.BAD_REQUEST,
'Invalid Primary Family Member specified.');
console.error('Invalid Primary Family Member specified:' + item.primaryFamilyMember);
validInsert = false;
} else {
item.memberType = results[0].memberType;
item.memberLevel = results[0].memberLevel;
item.dateOfExpiry = results[0].dateOfExpiry;
}
}
});
}
if (validInsert) {
var today = new Date();
var prefix = today.getFullYear().toString().substr(2,2) + ('0' + (today.getMonth() + 1)).slice(-2);
table.includeTotalCount().where(function(prefix){
return this.memberNumber.substring(0, 4) === prefix;
}, prefix)
.take(0).read({
success: function (results) {
if (isNaN(results.totalCount)) {
results.totalCount = 0;
}
item.memberNumber = prefix + ('00' + (results.totalCount + 1)).slice(-3);
request.execute();
}
});
}
Yes, validInsert is declared at the top of the insert function.
I assume what's happening is the if(validInsert) runs before the read callback. But if so, i'm not sure why I'm getting "Error: Execute cannot be called after respond has been called." That implies the callback is running first.
Also, the record is being inserted when it shouldn't be even though the 400 error is sent back to the client.
This is an express app right? Should I just call response.end() after the error occurs?
Yes, there are definitely asyn issues in that code. To solve get rid of your validInsert flag and simply move the if (validInsert) section into the success callback (or make it a function called from the success callback). For example:
success: function(results) {
if (results.length == 0) {
request.respond(statusCodes.BAD_REQUEST,
'Invalid Primary Family Member specified.');
console.error('Invalid Primary Family Member specified:' + item.primaryFamilyMember);
} else {
item.memberType = results[0].memberType;
item.memberLevel = results[0].memberLevel;
item.dateOfExpiry = results[0].dateOfExpiry;
var today = new Date();
var prefix = today.getFullYear().toString().substr(2,2) + ('0' + (today.getMonth() + 1)).slice(-2);
...
//respond successfully
}
}

Why is my closure not executing in time with each loop iteration?

buses_near_stops begins as an empty array. Inside the asynchronous calls to the database, it is supposed to be filled. Then after the calls finish, I want to use the data inside of it. When I run this code, the final console log of buses_near_stops executes before the inner database calls, even though I have the looped calls inside of a closure. According to this post, a closure should work, but here it is doing nothing for me.
var buses_near_stops = [];
buses_near_stops.test = "TEST";
// return these fields of each location document in the database
Location.find({}, 'service_name coordinates vehicle_id last_gps_fix', function(err, doc) {
//console.log('location found ' + JSON.stringify(doc));
if(err){return next(err);}
doc.forEach(function(j,k) {
//Find a stop that is near enough to each given bus that we can say the bus is 'at' that stop
//Making sure it returns 1 stop now because I don't know proper distance
(function(buses_near_stops) {
Stop.findOne({coordinates: { $near : j.coordinates, $maxDistance: .0001}
}, function(err, stop){
if(err){return next(err);}
console.log('stop found ' + j.service_name + " " + JSON.stringify(stop));
// service_name is null if bus is out of service (I believe)
if(stop !== null && j.service_name !== null) {
var service_name_of_bus = j.service_name;
console.log('service name of bus ' + service_name_of_bus);
// Find the service document associated with service_name_of_bus
var service_of_name = Service.findOne({name: service_name_of_bus}, function(err, service_of_name){
if(err){return next(err);}
// If the service has 'stop' on its route
if(service_of_name != null && service_of_name.routes[0].stops.indexOf(stop.stop_id) > -1) {
console.log('stop found on service');
// We have now found a bus that is stopped at a stop on its route
console.log('test ' + buses_near_stops.test);
buses_near_stops.push(
{
time: j.last_gps_fix,
bus_coords: j.coordinates,
stop_coords: stop.coordinates,
vehicle_id: j.vehicle_id,
stop_id: stop.stop_id,
service_name: service_name_of_bus
});
console.log('length ' + buses_near_stops.length);
}
});
}
})}(buses_near_stops));
});
console.log('buses near stops ' + JSON.stringify(buses_near_stops));
});

Browsers not updating when sockets get emmited

I'm trying to create a chat system. Here it is:
The top field takes the name of the user while the bottom textarea takes the message. Once the user pressed enter the middle textarea ( which is disabled) updates itself with the new record. This is done using nodejs sockets. My problem is that if I open another instance of google chrome and I type something the other google chrome textarea does not update. I'm puzzled by this since my code should cover this case:
Here is the server.js code that handles the insertion. After it inserts it, it emits a socket with the last insertion so that the index.html can update itself.
io.sockets.on("connection",function(socket){
socket.on("send",function(data){
mongodb.connect("mongodb://127.0.0.1:27017/myDatabase",function(err,db){
if(err) throw err;
var to_be_inserted = {name: data.name,content: data.content};
db.collection("chat").insert(to_be_inserted,function(err,objects){
if(err) throw err;
var cursor = db.collection("chat").find().sort({_id: -1}).limit(1);
cursor.toArray(function(err,docs){
console.log("abc");
socket.emit("data_to_be_printed",docs);
});
});
})
})
})
As you can see once the data is inserted a socket is emitted containing the last row of the db. The index.html should handle this socket by updating itself. Here is the code that handles it:
<script>
var socket = io.connect("127.0.0.1:1337");
socket.on("data_to_be_printed",function(cursor){
var completed = document.getElementById("chatArea").value;
for(var i=0; i < cursor.length; i++)
{
console.log(cursor[i].name + " wrote: " + cursor[i].content);
var name = cursor[i].name;
var content = cursor[i].content;
var name_to_go = name.replace("/\r?\n|\r/g","");
var content_to_go = content.replace("/\r?\n|\r/g","");
completed+="\n" + name_to_go + ": " + content_to_go;
}
document.getElementById("chatArea").value = completed;
});
function keyfunction(e)
{
if((e.keyCode == 13 || e.which == 13) && !e.shiftKey)
{
socketEmitDb();
}
}
function socketEmitDb()
{
var name = document.getElementById("name").value;
var content = document.getElementById("writtenThing").value;
console.log("Name: " + name + " |||| content: " + content);
document.getElementById("name").value="";
document.getElementById("writtenThing").value="";
if(name.length > 0 && content.length > 0)
{
socket.emit("send",{"name": name,"content": content});
}else
{
alert("Make sure that the name and the message is not empty");
}
}
</script>
Should't the socket be emitted towards all opened sockets?
In your server program change socket.emit to io.sockets.emit.
socket.emit will send message to specific socket (client) that got connected. io.sockets.emit will send message to all connected sockets (clients)

Chat on node.js

Require the modules
var net = require("net");
Store the users and the connections number
var count = 0,
users = {};
Creates the server
var server = net.createServer(function (conn){
Stores the current nickname and set the utf8 encoding
var nickname;
conn.setEncoding('utf8');
Shows a message on the shell when you stablish a connection
conn.write(' > welcome to \033[92mnode-chat\033[39m!'
+ '\n > ' + count + ' other people are connected at this time.'
+ '\n > please write your name and press enter: ');
The number of connections++
count++;
When recives data it checks if there is a user in the storage with that name shows a message and return. Else shows a welcome message. Otherwise, if you input a message or any data (after have registered your nickname) shows it on the shell.
conn.on('data', function (data){
data = data.replace('\r\n', '');
if(!nickname) {
if(users[data]) {
conn.write('\033[93m > nickname already in use. Try again:\033[39m ');
return;
} else {
nickname = data;
users[nickname] = conn;
for(var i in users) {
users[i].write('\033[90m > ' + nickname + ' joined the room\033[39m\n');
}
}
} else {
for(var i in users) {
if(i != nickname) {
users[i].write('\033[96m > ' + nickname + ':\033[39m ' + data + '\n');
}
}
}
});
When you close or end the connection deletes your nickname from the storage, number of connections-- and shows a message.
conn.on('close', function(){
count--;
delete users[nickname];
conn.write('\033[90 > ' + nickname + ' left the room\033[39m\n');
});
});
Server on port 3000
server.listen(3000, function (){
console.log('\033[96m server listening on *:3000\033[39m');
});
I have a bug in my chat. I stablish two telnet connections using de shell. But when I close one the other one close two, and shows me a error message. What is wrong with my code?
You're trying to write to a closed connection, which will fail since writing to a closed Writable stream throws an error.
conn.on('close', function(){
count--;
delete users[nickname];
conn.write('\033[90 > ' + nickname + ' left the room\033[39m\n');
});
What you want is to broadcast the message to all other users either using Object.keys or a for-in loop.
conn.on('close', function() {
count --;
delete users[nickname];
Object.keys(users).forEach(function (user) {
users[user].write(nickname + ' left the room');
});
}
You also don't need a separate count variable to track connected users.
Object.keys(users).length;
But when I close one the other one close two, and shows me a error
message
It is because you're not listening for an error event and, by default, an EventEmitter throws an error if an error occurs and no error listener is attached.
conn.on('error', console.log);

Resources