Getting list of clients using WebSockets - javascript

I'm building a multiuser sketchpad and having some issues getting and keeping an updated list of all the currently connected users. I'm trying to find the best way to notify all existing clients of a new client, and passing the existing clients to the newly connected one. The reason I'm trying to do this is so when one client draws a line, all the other clients find that client in the list, and add the line coords to the respective array.
Server.js
var sys = require("sys");
var ws = require('websocket-server');
var server = ws.createServer({debug: true});
server.addListener("connection", function(conn) {
// When a message is received, broadcast it too all the clients
// that are currently connected.
conn.send('NEW_SERVER_MESSAGE:Welcome!');
conn.send('USER_CONNECTED:' + conn.id);
conn.addListener("message", function( msg ){
switch(msg) {
case 'GET_ALL_ACTIVE_USERS':
server.manager.forEach(function(con) {
conn.broadcast('USER_CONNECTED:' + con.id);
});
break;
case 'UPDATE_CURSOR':
conn.broadcast( msg + '_' + conn.id );
break;
default:
conn.broadcast( msg );
break;
}
});
conn.addListener('close', function( msg ) {
conn.broadcast('USER_DISCONNECTED:' + conn.id);
});
});
server.addListener("error", function(){
console.log(Array.prototype.join.call(arguments, ", "));
});
server.addListener("listening", function(){
console.log("Listening for connections...");
});
server.addListener("disconnected", function(conn){
console.log("<"+conn.id+"> disconnected.");
});
server.listen(8002);</code>
My JS network code:
sketchPadNet = function (b,s) {
var self = this;
this.host = "ws://localhost:8002/server.js";
this.id = null;
this.users = [];
this.heightOffset = 53;
this.scene = s;
this.connected = b;
var User = function(id) {
this.id = id;
this.nickname = id;
this.lines = [];
this.position = "";
};
this.init = function () {
try {
socket = new WebSocket(self.host);
socket.onopen = function (msg) {
socket.send('GET_ALL_ACTIVE_USERS');
};
socket.onmessage = function (msg) {
var m = msg.data.split(':');
switch(m[0]) {
case 'USER_CONNECTED':
console.log('USER_CONNECTED');
var u = new User(m[1]);
u.lines = [];
u.nickname = u.id;
self.users.push(u);
console.log(self.users.length);
console.log(self.users);
break;
case 'USER_DISCONNECTED':
console.log('USER_DISCONNECTED');
for(var i = 0; i < self.users.length; ++i) {
console.log(self.users[i]);
if(m[1] == self.users[i].id) {
self.users.splice(i, 1);
}
}
break;
case 'DRAW_LINE':
var tmpMsg = m[1].split('_');
var id = tmpMsg[8];
var userIndex = '';
for(var i = 0; i < self.users.length; ++i) {
if(self.users[i].id == id) userIndex = i;
}
var p1 = (self.users[userIndex].lines.length < 1) ? new BLUR.Vertex3(tmpMsg[0], tmpMsg[1], tmpMsg[2]) : self.users[userIndex].lines[self.users[userIndex].lines.length - 1].point2;
var p2 = new BLUR.Vertex3(tmpMsg[3], tmpMsg[4], tmpMsg[5]);
var line = new BLUR.Line3D(p1, p2, tmpMsg[7]);
line.material = tmpMsg[6];
// add the newly created line to the scene.
self.scene.addObject(line);
self.users[userIndex].lines.push(line);
break;
case 'UPDATE_CURSOR':
for(var i = 0; i < self.scene.objects.length; ++i) {
if(self.scene.objects[i].type == 'BLUR.Particle')
self.scene.removeObject(scene.objects[i]);
}
var coords = m[1].split('_');
var id = coords[2];
var userIndex = 0;
for(var i = 0; i < self.users.length; ++i) {
if(self.users[i].id == id)
userIndex = i;
}
self.users[userIndex].position = new BLUR.Vertex3(coords[0], coords[1], 1);
var p = new BLUR.Particle( self.users[userIndex].position, 4 );
p.material = new BLUR.RGBColour(176,23,31,0.3);
self.scene.addObject(p);
break;
case 'RECEIVE_ID':
self.id = m[1];
self.connected.nicknameObj.text = self.id;
console.log(self.id);
break;
break;
}
};
socket.onclose = function (msg) {
// feck!
self.connected.addServerError('Server disconnected, try refreshing.');
};
}
catch (ex) {
console.log('EXCEPTION: ' + ex);
}
};
At the moment, when a new client connected it sends out a message and is added to an array, the the reverse when a client disconnects. For some reason though this isn't staying update? For example when a client draws a line, some of the others report this error:
Uncaught TypeError: Cannot read property 'lines' of undefined
Sorry if i'm being incredibly stupid here, but any help is appreciated!!
Cheers :)

I tried to figure it out by looking at the code but without even a line number on which the error appears, it's pretty hard, anyways.
I suppose this is the problem here:
conn.send('USER_CONNECTED:' + conn.id); // send the connect message to ONE user
conn.broadcast('USER_DISCONNECTED:' + conn.id); // send the disconnect to ALL users
So it seems that you're simply missing a broadcast call when a user connects.

Ok the real issue seems to be in 'DRAW_LINE' on the client side. Are you sure that you are broadcasting the message to all users and not just sending back the message to the client?
The error points to this line in your client code:
var p1 = (self.users[userIndex].lines.length < 1) ? new BLUR.Vertex3(tmpMsg[0], tmpMsg[1], tmpMsg[2]) : self.users[userIndex].lines[self.users[userIndex].lines.length - 1].point2;
Please provide the server code for 'DRAW_LINE'. The issue is definitely cropping up in there and not in any of the others.
Also, self.users[userIndex] is undefined. Maybe that user does not exist?
Why do u need that for loop? Why not just:
if(self.users[id] != undefined) {
var p1 = (self.users[id].lines.length < 1) ? new BLUR.Vertex3(tmpMsg[0], tmpMsg[1], tmpMsg[2]) : self.users[id].lines[self.users[id].lines.length - 1].point2;
}

I'm trying to find the best way to
notify all existing clients of a new
client, and passing the existing
clients to the newly connected one
I would advice you to have a look at socket.io instead. It can do this easily and fail back to other available transports if websockets aren't supported by the browser.

you might want to consider using an existing server that has things like rooms and user lists built in. for comparison, here's a tutorial for a multiuser sketchpad written in javascript that uses Union Server:
http://www.unionplatform.com/?page_id=2762
and here's Union Server's documented protocol, which includes a description of the messaging system for rooms and clients joining/leaving rooms:
http://unionplatform.com/specs/upc/
might give you some ideas.
colin

Related

Functions Rerunning in GAS

I'm using GAS to send and receive texts. There is one function that send texts (sendTexts.gs) and one that receives (receiveTexts.gs). I have both of these functions linked to individual buttons on the sheet, but when I run one function, both are running (texts get sent every time). Is there a cache or something that needs to be cleared? The receiveTexts has no commands in the code that could send messages in it, and based on logger testing, I know that both are running when I only click one.
EDIT: This also occurs in the GAS "terminal". If I click run in the script editor both run.
Here is the code with personal/individual info (codes/phone numbers edited out):
function sendSms(to, body) {
var playerArray = getMeta();
Logger.log(playerArray);
var messages_url = "https://api.twilio.com/2010-04-01/Accounts/EDIT/Messages.json";
var payload = {
"To": to,
"Body" : body,
"From" : "EDIT"
};
var options = {
"method" : "post",
"payload" : payload
};
options.headers = {
"Authorization" : "Basic " + Utilities.base64Encode("EDIT")
};
UrlFetchApp.fetch(messages_url, options);
}
function sendAll() {
var spreadsheet = SpreadsheetApp.getActive();
var text = SpreadsheetApp.setActiveSheet(spreadsheet.getSheetByName('Meta')).getRange('B4').getValue();
var playerArray = getMeta();
Logger.log(text);
for (i=0; i<playerArray.length;i++) {
try {
var number = playerArray[i][1];
Logger.log(number);
response_data = sendSms(number, text);
status = "sent";
} catch(err) {
Logger.log(err);
status = "error";
}
Logger.log(status);
}
}
function sendTexts() {
sendAll();
}
Logger.log("ran send texts");
Here is the receive texts code with the same adjustments:
function receiveTexts() {
var spreadsheet = SpreadsheetApp.getActive();
var ACCOUNT_SID = "EDIT";
var ACCOUNT_TOKEN = "EDIT";
var toPhoneNumber = "+EDIT";
var sheet = spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Meta'), true);
var playerArray = getMeta();
var numberToRetrieve = playerArray.length;
var hoursOffset = 0;
var options = {
"method" : "get"
};
options.headers = {
"Authorization" : "Basic " + Utilities.base64Encode(ACCOUNT_SID + ":" + ACCOUNT_TOKEN)
};
var url="https://api.twilio.com/2010-04-01/Accounts/" + ACCOUNT_SID + "/Messages.json?To=" + toPhoneNumber + "&PageSize=" + numberToRetrieve;
var response = UrlFetchApp.fetch(url,options);
// -------------------------------------------
// Parse the JSON data and put it into the spreadsheet's active page.
// Documentation: https://www.twilio.com/docs/api/rest/response
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Meta'), true);
var numRounds = spreadsheet.getRange('B2').getValue();
var theSheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheetByName('Attacks'),true);
var theColumn = (numRounds*2)+1;
var dataAll = JSON.parse(response.getContentText());
for (i=0; i<dataAll.messages.length; i++){
var sentNumber = dataAll.messages[i].from;
Logger.log(sentNumber);
for (k=0; k<playerArray.length;k++){
Logger.log(playerArray[k][1]);
if (playerArray[k][1]==sentNumber){
var player = k;
Logger.log('Success');
Logger.log(player);
break;
}
}
var playerRow = playerArray[player][0];
Logger.log(playerRow);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Attacks'),true);
theSheet.getRange(playerRow, theColumn).setValue(dataAll.messages[i].body);
}
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Meta'), true);
sheet.getRange(2,2).setValue(numRounds +1);
}
Logger.log("texts received ran");
EDIT2: I separated out getMeta into a separate file. Now when I run getMeta, it also runs the other two scripts. Anytime any one script is run, all three run. This makes me think it's not related to the code, but related to some setting or something. Does the order of the scripts in the sidebar matter? I feel like that's not it because running any of the three causes all three to be run.

Why Won't This Firebase Callable Function Return A Value?

I have a callable function that should return a value, but the only thing ever returned is null. Below is the current version of the function. I have also tried having a return on the first promise (the original once call), and at the end in another then returning the GUID. It actually returned data in that case, but it returned immediately and the GUID was empty.
How can I accomplish my goal and still return the GUID? I don't know when the function is called if I will use a new GUID that I generate, or one that already exists in the database.
There is a similar question here: Receiving returned data from firebase callable functions , but in that case it was because he never returned a promise from the function. I am returning a promise on all code paths. Unless I have to return the initial promise from the once call? In which case, how can I return the GUID when I don't know it yet?
I am also trying to throw an error in a couple of places and the error shows up in the logs for the function, but is never sent to the client that called the function.
I am going off of the examples here: https://firebase.google.com/docs/functions/callable
Sorry for the code bomb.
Calling the function:
var newGame = firebase.functions().httpsCallable('findCreateGame');
newGame({}).then(function(result) {
// Read result of the Cloud Function.
//var sGameID = result.data.guid;
console.log(result);
}).catch(function(error) {
console.log(error);
});
Function:
exports.findCreateGame = functions.https.onCall((data, context) => {
console.log("findCurrentGame Called.")
/**
* WHAT NEEDS DONE
*
*
* Pull in user's information
* Determine their win/loss ratio and search for a game using transactions in either low medium or high queue
* If there are no open games in their bracket, search the one above, then below
* If no open games anywhere, create a new game in their bracket
* If an open game is found, write the UID to the game and add the game's ID to the user's profile
*
*/
var uid = context.auth.uid;
var section = "";
var sUsername = "";
var sProfilePic = "";
var currentGames = null;
var sGUID = "";
//Get the user's info
var userref = admin.database().ref('users/' + uid);
userref.once("value", function(data) {
var ratio = 0;
var wins = parseInt(data.val().wins);
var losses = parseInt(data.val().losses);
var lives = parseInt(data.val().lives);
if (lives < 1){
//This user is out of lives, should not have been able to get here
//Throw an exception so that we can see why it failed
throw new functions.https.HttpsError('permission-denied', 'You do not have enough lives to start a new game.');
}
sUsername = data.val().username;
sProfilePic = data.val().profilepicture;
//Handle if they have no losses
if (losses == 0){
ratio = 100;
} else {
ratio = (wins / losses) * 100;
}
//If they have played less than 5 games, put them in noob tier
if (wins + losses < 5){
ratio = 0;
}
if (ratio <= 33){
section = "noob";
} else if (ratio > 33 && ratio <= 66){
section = "average";
} else {
section = "expert";
}
}).then(() => {
//Get all of the games this user is currently in
admin.database().ref('games').orderByChild(uid).once('value', function(data) {
currentGames = data.val();
}).then(() => {
//Generate a new GUID in case we need to set up a new game
sGUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
var queueref = admin.database().ref('gamequeue/' + section);
queueref.transaction(function(currentGUID) {
if (currentGUID == null){
//Write our GUID in the queue
return sGUID;
} else {
//Get the id of the game we just got
sGUID = currentGUID
return null;
}
}).then((res) => {
if (res.snapshot.val() != null){
//This means we are creating the game lobby
//Generate a new answer
var newAnswer = "";
while (newAnswer.length < 4){
var temp = Math.floor(Math.random() * 9) + 1;
temp = temp.toString();
if (!newAnswer.includes(temp)){
newAnswer += temp;
}
}
var obj = {username: sUsername, score: 0, profilepicture: sProfilePic};
return admin.database().ref('games/' + sGUID).set({id: sGUID, requestor: uid, [uid]: obj, answer: newAnswer, turn: uid, status: 'pending'}).then(() => {
return {guid: sGUID};
});
} else {
//We found a game to join
//If we are in a duplicate request situation, make sure the GUID is a string
if (typeof(sGUID) != 'string'){
sGUID = Object.keys(sGUID)[0];
}
//Make sure we didn't find our own game request
if (currentGames[sGUID] != null){
//Add this GUID back to the queue, we shouldn't have removed it
return admin.database().ref('gamequeue/' + section + '/' + sGUID).set('');
//Throw an exception that says you can only have one open game at a time
throw new functions.https.HttpsError('already-exists', 'We are still finding a match for your last request. You are only allowed one open request at a time.');
} else {
//Get the current game info
admin.database().ref('games/' + sGUID).once('value', function(data) {
var sRequestor = data.val().requestor;
var sOpponentUsername = data.val()[sRequestor].username;
var sOpponentProfilePic = data.val()[sRequestor].profilepicture;
//Write all of our info to the game
return admin.database().ref('games/' + sGUID).update({[sRequestor]: {opponentusername: sUsername, opponentprofilepicture: sProfilePic}, [uid]: {username: sUsername, score: 0, opponentusername: sOpponentUsername, opponentprofilepicture: sOpponentProfilePic}, status: 'active'}).then(() => {
return {guid: sGUID};
});
});
}
}
});
});
})
});
The documentation for callable functions explains:
To return data after an asynchronous operation, return a promise. The
data returned by the promise is sent back to the client.
You have many asynchronous operations that must be chained together. A return needs to be added to each of these statements (as shown):
return userref.once("value", function(data) {...
return admin.database().ref('games').orderByChild(uid).once('value', function(data) {...
return queueref.transaction(function(currentGUID) {...
return admin.database().ref('games/' + sGUID).once('value', function(data) {...

Using Multple Asyncronous Xmlhttprequests to Create/Update Microsoft Dynamics CRM Order Detail Records Not Working

I am trying to send multiple asyncronous xmlhttprequest's using the oData endpoint. Some of them are creating Order details and are updating Order details in Microsoft Dynamics CRM 2013.
If I use the developer tools and manually trace through the code it works fine. However, if I run it from my web resource I constantly get 500 responses from the server. Some of the requests complete correctly, while the others fail.
I am looking for a purely javascript solution. I have tried Googling it and looking at multiple posts on stackoverflow but to no avail. I have used Fiddler2 but the response text is 'Generic SQL Error'. If I run the request again in the composer, it works just fine. Could it be a db locking issue?
Thanks in advance and I can provide more info if need be.
Here is my code with the for-loop:
var updateDetails = function (data) {
var table = document.getElementById("selectedItemTable");
var tbody = table.getElementsByTagName("tbody")[0];
var upsaleQty, qty;
var salesOrderDetailId;
for (var i = 0; i < tbody.childElementCount; i++) {
var prodName = tbody.rows[i].cells[0].innerHTML;
var match = false;
for (var j = 0; j < data.length; j++) {
if (prodName === data[j].product_order_details.tf_ShortName) {
match = true;
upsaleQty = data[j].tf_UpsaleQty ? parseFloat(data[j].tf_UpsaleQty) : 0;
qty = parseFloat(data[j].Quantity) + parseFloat(tbody.rows[i].cells[1].innerHTML);
salesOrderDetailId = data[j].SalesOrderDetailId;
}
}
if (!match) {
var productQuery = odataBaseUrl + "/ProductSet?$filter=tf_ShortName eq '" + prodName + "'&$select=Name,tf_ShortName,ProductId,DefaultUoMId";
performRequest(productQuery, createDetail);
} else {
upsaleQty = upsaleQty + parseFloat(tbody.rows[i].cells[1].innerHTML);
// Update Order Detail
var updateObj = {};
updateObj.tf_UpsaleQty = upsaleQty.toFixed(5);
updateObj.Quantity = qty.toFixed(5);
var updateDetail = JSON.stringify(updateObj);
console.dir("Update " + prodName + ":" + updateDetail);
createUpdateDetail(true, salesOrderDetailId, updateDetail);
}
}
makePdf();
document.getElementById("save").style.visibility = "hidden";
}
Here is the code that sends the create/update request:
var createUpdateDetail = function (update, orderDetailGuid, json) {
var odataReq = odataBaseUrl + "/SalesOrderDetailSet";
if (update) {
odataReq += "(guid'" + orderDetailGuid + "')";
}
var oReq = getXMLHttpRequest();
if (oReq != null) {
oReq.open("POST", encodeURI(odataReq), true);
oReq.setRequestHeader("Accept", "application/json");
oReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
if (update) {
oReq.setRequestHeader("X-HTTP-Method", "MERGE");
}
oReq.send(json);
} else {
alert('Error in creating request.');
}
}
Here is the perform request function:
var performRequest = function (odataUrl, onReadyFunction, concatResults) {
console.dir(odataUrl);
var oReq = getXMLHttpRequest();
if (oReq != null) {
oReq.open("GET", encodeURI(odataUrl), true);
oReq.setRequestHeader("Accept", "application/json");
oReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
oReq.onreadystatechange = function () {
if (oReq.readyState == 4 && oReq.status == 200) {
// Parse the result
if (!concatResults) {
concatResults = new Object();
concatResults.results = new Array();
}
oReq.onreadystatechange = null; //avoids memory leaks
console.dir(oReq.responseText);
var result = window.JSON.parse(oReq.responseText).d;
for (var i = 0; i < result.results.length; i++) {
concatResults.results.push(result.results[i])
}
if (result.__next != null)
performRequest(decodeURI(result.__next), onReadyFunction, concatResults);
else
onReadyFunction(concatResults.results);
}
};
oReq.send();
} else {
alert('Error in creating request.');
}
}
Create Detail function:
var createDetail = function (data) {
// Create Order Detail
var table = document.getElementById("selectedItemTable");
var tbody = table.getElementsByTagName("tbody")[0];
var qty = 0;
for (var i = 0; i < tbody.childElementCount; i++) {
if (data[0].tf_ShortName === tbody.rows[i].cells[0].innerHTML) {
qty = parseFloat(tbody.rows[i].cells[1].innerHTML).toFixed(5);
}
}
var createObj = {};
createObj.SalesOrderId = { Id: orderGuid, LogicalName: "salesorder" };
createObj.ProductId = { Id: data[0].ProductId, LogicalName: "product" };
createObj.Quantity = qty;
createObj.tf_UpsaleQty = qty;
createObj.UoMId = { Id: data[0].DefaultUoMId.Id, LogicalName: data[0].DefaultUoMId.LogicalName };
var createDet = JSON.stringify(createObj);
console.dir("Create:" + createDet);
createUpdateDetail(false, "", createDet);
}
I think ExecuteMultipleRequest to SOAP endpoint it's your solution. As a result you get only one service call instead making multiple service call which is currently implemented in your solution.
In case you avoid generating request string to soap endpoint in your code I would like to recommend you this JS library.
I ended up creating an array and treated it like a queue. I put all of the odata requests to create and update the Order Details in the array and then processed them sequentially. The onreadystatechange would trigger the next request. Granted, it's not as efficient as running the processed in parallel, but it worked for my needs and resolved the 500 errors. Thanks for your help.

Sort out all messages that have 'unread = true'

Hi i need to sort out messages that are not read in Gmail. But i can't pull out the body, sender and attachments properties when im adding the 'isUnread'.
var firstThread = GmailApp.getInboxThreads(0,1)[0];
var unread = firstThread.isUnread();
var message = unread.getMessages()[0];
If i do it like this it works, but i do not get the unread messages.
var firstThread = GmailApp.getInboxThreads(0,1)[0];
var message = firstThread.getMessages()[0];
Any tips?
Maybe is just a matter of order, you can try
var firstThread = GmailApp.getInboxThreads(0,1)[0];
var messages = firstThread.getMessages();
var unread = [];
for (var i=0; i<messages.length; i++){
if (messages[i].isUnread()) unread.push(messages[i]);
}
sailens approach works as expected, search is also an easy way to get what you want.
Below 2 small functions to demonstrate:
function getUnreadMessages() {
var unreadThreads = GmailApp.getInboxThreads(0,100);
if(unreadThreads.length==0){Logger.log('no unread messages');return};
var unreads = [];unreads.push('\n\n');
for(var n in unreadThreads){
if(unreadThreads[n].isUnread()){unreads.push(unreadThreads[n].getFirstMessageSubject()+' has '+unreadThreads[n].getMessageCount()+' message(s)\n')};
}
Logger.log(unreads);//shows the unread threads with their subjects and number of messages
}
function searchUnreads() {
var unreadThreads = GmailApp.search('label:unread');
if(unreadThreads.length==0){Logger.log('no unread messages');return};
var unreads = [];unreads.push('\n\n');
for(var n in unreadThreads){
unreads.push(unreadThreads[n].getFirstMessageSubject()+' has '+unreadThreads[n].getMessageCount()+' message(s)\n');
}
Logger.log(unreads);//shows the unread threads with their subjects and number of messages
}
UPDATE :
a version that gets some details from every message in the threads, build in another function for ease of use
function getUnreadMessages() {
var unreadThreads = GmailApp.getInboxThreads(0,100);
if(unreadThreads.length==0){Logger.log('no unread messages');return};
var unreads = [];unreads.push('\n\n');
for(var n in unreadThreads){
if(unreadThreads[n].isUnread()){unreads.push(unreadThreads[n].getFirstMessageSubject()+' has '+unreadThreads[n].getMessages()[n].getDate()
.getMessageCount()+' message(s)\n');getDetails(unreadThreads[n])};
}
Logger.log(unreads);//shows the unread threads with their subjects and number of messages
}
function searchUnreads() {
var unreadThreads = GmailApp.search('label:unread');
if(unreadThreads.length==0){Logger.log('no unread messages');return};
var unreads = [];unreads.push('\n\n');
for(var n in unreadThreads){
unreads.push(unreadThreads[n].getFirstMessageSubject()+' has '+unreadThreads[n].getMessageCount()+' message(s)\n');
}
Logger.log(unreads);//shows the unread threads with their subjects and number of messages
}
function getDetails(thread){
for(var n=0;n<thread.getMessageCount();n++){
Logger.log(thread[n].getMessages()[n].getBody()+' on '+thread[n].getMessages()[n].getDate())
Logger.log(thread[n].getMessages()[n].getAttachments());
}
}
I got it to work and simple as it could be:
function myFunction() {
var firstThread = GmailApp.getInboxThreads(0,1)[0];
var message = firstThread.getMessages()[0];
var unread = message.isUnread();
var sender = message.getFrom();
var body = "Detta mail är ursprungligen skickat från" + " " + sender + '\n' + message.getBody();
var subject = message.getSubject();
var attachment = message.getAttachments();
if (unread == true){
GmailApp.sendEmail("user.name#compay.com", subject, "", {htmlBody: body, attachments: attachment});
}

Javascript verticle : Cannot find function setperiodic

As a C++/C# programmer I'm pretty new in Javascript (not my choice, lame course at my university) and I've to dev a small programme using vert.x creating childs wich will count words contains in a text file.
I want to use point-to-point method.
Here's what I've actually done for the parent:
var vertx = require ('vertx');
var console = require('vertx/console');
var container = require('vertx/container')
var eb = require('vertx/event_bus');
vertx.fileSystem.OPEN_READ = 1
vertx.fileSystem.OPEN_WRITE = 2
vertx.fileSystem.CREATE_NEW = 4
vertx.createHttpServer().requestHandler(function(req)
{
vertx.fileSystem.readFile('dataset.txt', function(err, res)
{
if (!err)
{
var str = res.toString();
var myarray = str.split(' ');
for (var i = 0; i < myarray.length; i++)
{
myarray[i] = myarray[i].replace(".", "");
myarray[i] = myarray[i].replace(",", "");
}
var config = {adresse: 'boap'}
var id = container.deployVerticle('child.js', config, 1);
var reply;
vertx.setperiodic(1000, function sendmessage()
{
eb.send('lama', 'ping!', function(reply)
{
console.log("received reply: " + reply);
});
});
}
});
}).listen(1234, 'localhost');
Here's the child :
var eb = require('vertx/event_bus');
var console = require('vertx/console');
var container = require('vertx/container')
var log = container.logger;
log.info("in child.js, config is " + container.config.adresse);
eb.registerHandler('lama', function(message, replier) {
console.log('Received message ' + message);
// Now reply to it
replier('pong!');
});
The problem is when I launch it I get the following error :
Succeeded in deploying verticle
Exception in JavaScript verticle:
TypeError: Cannot find function setperiodic in object [object Object].
at file:/C:/Users/3wic/Documents/vert.x-2.1M2/bin/lama.js:30 (anonymous)
at file:/C:/Users/3wic/Documents/vert.x-2.1M2/sys-mods/io.vertx~lang-rhi
no~2.0.0-final/vertx/file_system.js:47 (anonymous)
in child.js, config is boap
Anyone know why this function isn't recognized ?
Answered by tim_yates, check the comments

Categories