I created a simple chatroom using socket.io. I have these scripts in my index.html :
var socket = io.connect('http://imageworkz.asia:8080');
// on connection to server, ask for user's name with an anonymous callback
socket.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
socket.emit('adduser', prompt("What's your name?"));
});
// listener, whenever the server emits 'updatechat', this updates the chat body
socket.on('updatechat', function (username, data) {
$('#conversation').append('<b>'+username + ':</b> ' + data + '<br>');
});
// listener, whenever the server emits 'updateusers', this updates the username list
socket.on('updateusers', function(data) {
$('#users').empty();
$.each(data, function(key, value) {
$('#users').append('<div>' + key + '</div>');
});
});
// on load of page
$(function(){
// when the client clicks SEND
$('#datasend').click( function() {
var message = $('#data').val();
$('#data').val('');
// tell server to execute 'sendchat' and send along one parameter
socket.emit('sendchat', message);
});
// when the client hits ENTER on their keyboard
$('#data').keypress(function(e) {
if(e.which == 13) {
$(this).blur();
$('#datasend').focus().click();
}
});
});
when i change the connection to http://localhost:8080 and start it using 'node app.js' command in console, it works fine but when I upload it and change it to http://imageworkz.asia:8080, it is not working whenever I go to url: http://imageworkz.asia:8080. Am I missing something or are there still things I should do to make it work when it is uploaded? or am I going to the wrong url? Thanks!
Try updating your node.js version to the latest one on the net (http://imageworkz.asia:8080).
Also check whether all necessary node modules are installed on the net, and if needed, change the logic such that you dont require prompt() to transmit a message.
I'm not completely sure, but I think this should work:
var socket = io.connect('http://imageworkz.asia');
// on connection to server, ask for user's name with an anonymous callback
socket.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
socket.emit('adduser', prompt("What's your name?"));
});
// listener, whenever the server emits 'updatechat', this updates the chat body
socket.on('updatechat', function (username, data) {
$('#conversation').append(''+username + ': ' + data + '');
});
// listener, whenever the server emits 'updateusers', this updates the username list
socket.on('updateusers', function(data) {
$('#users').empty();
$.each(data, function(key, value) {
$('#users').append('' + key + '');
});
});
// on load of page
$(function(){
// when the client clicks SEND
$('#datasend').click( function() {
var message = $('#data').val();
$('#data').val('');
// tell server to execute 'sendchat' and send along one parameter
socket.emit('sendchat', message);
});
// when the client hits ENTER on their keyboard
$('#data').keypress(function(e) {
if(e.which == 13) {
$(this).blur();
$('#datasend').focus().click();
}
});
});
it just removes :8080
Related
I am connection through Vertx eventbus (SockJS to my Java based backend. Everything work fine, However, I cannot find a way to send an initial message.
Is there a way to send back data when SockJS bridge receives SOCKET_CREATED to the sockjs browser side?
Thank you.
Taken from their documentation:
if (event.type() == SOCKET_CREATED || event.type() == SOCKET_CLOSED)
{
//...
vertx.eventBus().publish("fromServer", jmsg.toJSONString());
}
Your event instantiation may be different, but that would be how you check for the specific event and run code after it has occurred
You can check this code , where I'm using EventBus.
Here is the Reference code
this.eventBus = new EventBus(this.URL);
this.eventBus.onopen = (e) => {
this._opened = true;
console.log("open connection");
this.callHandlers('open', e);
this.eventBus.publish("http://localhost:8082", "USER LOGIN INFO");
this.eventBus.registerHandler("http://localhost:8081/pushNotification", function (error, message) {
console.log(message.body);
//$("<div title='Basic dialog'>Test message</div>").dialog();
});
}
this.eventBus.onclose = (e) => {
this.callHandlers('close', e);
}
}
I have node.js and socket.io performing real-time updates on a DataTables table. When a row is edited, other clients see the updates to the row without refreshing.
This all works well, but I'm at a loss regarding how to automatically refresh the table when node/socket reconnect to the server after a disconnect.
Currently, this is what happens:
Go to page containing table
Let device sleep/disconnect from
server
Power on device and see page containing table
socket.io reconnects to the server, but the table doesn't refresh to get the latest changes.
How can I get socket.io to refresh the table upon reconnect to the server? Ideally, the process would look like this:
Power on device
socket.io reconnects to server, triggers CSS "Loading..." overlay to prevent user from making changes to table
socket.io refreshes the table to show latest content
CSS "Loading..." overlay closes
Server-side script:
console.log('Starting the server');
var app = require('express')();
var express = require('express');
var fs = require("fs");
var server = require('https').createServer(SSL, app);
var io = require('socket.io')(server);
server.listen(100);
io.on('connection', function (socket) {
/*socket.emit('news', { hello: 'world' });
/socket.on('my other event', function (data) {
console.log(data);
});*/
});
io.set('authorization', function(handshakeData, accept) {
console.log('io.authorization called');
accept(null, true);
} );
var lockedRowIDs = [];
io.sockets.on('connection', function(socket) {
console.log('io.connection called');
socket.on('lock', function(rowID) {
console.log('Lock event for rowID: '+rowID);
lock(socket, rowID);
lockedRowIDs.push(rowID);
} );
socket.on('clientJoin', function(username) {
console.log('clientJoin event received');
socket.join('clients');
if (typeof lockedRowIDs !== 'undefined' && lockedRowIDs.length > 0) {
socket.emit('lockedRows', lockedRowIDs);
}
} );
socket.on('unlock', function(rowID) {
console.log('Unlock event for rowID: '+rowID);
unlock(socket, rowID);
removeItemFromArray(lockedRowIDs, rowID);
} );
socket.on('updateData', function(json, action, id) {
if (action == "edit" || action == "create") {
console.log('updateData event for rowID: '+json.row['DT_RowId']);
}
updateData(socket, json, action, id);
} );
} );
function lock(socket, rowID) {
socket.broadcast.to('clients').emit('lock', rowID);
setTimeout(function() {
io.sockets.in('clients').emit('timeout', rowID);
removeItemFromArray(lockedRowIDs, rowID);
},
180000);
}
function unlock(socket, rowID) {
socket.broadcast.to('clients').emit('unlock', rowID);
}
function removeItemFromArray(array, item) {
console.log('removeItemFromArray called with item: '+item);
for(var i = array.length - 1; i >= 0; i--) {
if(array[i] === item) {
array.splice(i, 1);
}
}
}
function updateData(socket, json, action, id) {
if (action == "edit" || action == "create") {
console.log('updateData called with rowID:'+json.row['DT_RowId']);
}
socket.broadcast.to('clients').emit('updateData', json, action, id);
}
Client-side script:
var socket = io('https://www.***.com:100');
socket.on('connect', function() {
console.log('Connected');
socket.emit('clientJoin');
} );
socket.on('lock', function(rowID) {
console.log('Lock event received for rowID: '+rowID);
row = $("tr[id='"+rowID+"']");
row.addClass('locked');
/* Pagenation fix Start */
var table = $('#example').DataTable();
table.row('#'+rowID).nodes().to$().addClass('locked');
/* Pagenation fix End */
} );
socket.on('unlock', function(rowID) {
console.log('Unlock event received for rowID: '+rowID);
row = $("tr[id='"+rowID+"']");
row.removeClass('locked');
/* Pagenation fix Start */
var table = $('#example').DataTable();
table.row('#'+rowID).nodes().to$().removeClass('locked');
/* Pagenation fix End */
} );
socket.on('timeout', function(rowID) {
console.log('Time out event received for rowID: '+rowID);
row = $("tr[id='"+rowID+"']");
row.removeClass('locked');
/* Pagenation fix Start */
var table = $('#example').DataTable();
table.row('#'+rowID).nodes().to$().removeClass('locked');
/* Pagenation fix End */
/* Check if the editor corresponds to the timed out rowID - start */
var modifier = editor.modifier();
if (modifier) {
var data = table.row(modifier).data();
console.log('rowID is '+data.DT_RowId);
if (data.DT_RowId == rowID) {
console.log('Timed out rowID: '+rowID+' matches Editor rowID: '+data.DT_RowId+'. Closing Editor now.');
editor.close();
}
else {
console.log('Timed out rowID: '+rowID+' does not match Editor rowID: '+data.DT_RowId+'. Keeping Editor open.');
}
}
/* Check if the editor corresponds to the timed out rowID - end */
} );
socket.on('lockedRows', function (rowIDs) {
console.log('Iterate through the list of rows and mark it as locked');
table = $('#example').DataTable();
rowCount = rowIDs.length;
console.log('Row count: '+rowCount);
for (var i=0; i<rowCount; i++) {
console.log(rowIDs[i]);
row = $("tr[id='"+rowIDs[i]+"']");
row.addClass('locked');
table.row('#'+rowIDs[i]).nodes().to$().addClass('locked');
}
} );
socket.on('updateData', function(json, action, id) {
if (action == "create" || action == "edit") {
var DT_RowId = json.row['DT_RowId'];
console.log('updateData socket event for rowID: '+DT_RowId+' and action: '+action);
}
var table = $('table#example').DataTable();
if (action == "edit") {
var editedRow = table.row('#'+DT_RowId).nodes().to$();
table.row(editedRow).data(json.row).draw();
console.log('Row updated');
}
if (action == "create") {
console.log('Row created');
table.row.add(json.row).draw();
}
if (action == "remove") {
var removedRow = table.row('#'+id).nodes().to$();
table.row(removedRow).remove().draw();
console.log('Row removed with id '+id);
}
} );
/* Ajax request has been completed, data retrieved from the server */
editor.on('postSubmit', function(e,json, data, action) {
console.log('Post submit');
console.log(data);
console.log('With JSON:');
console.log(json);
console.log('With action:');
console.log(action);
if (action == "create" || action== "edit") {
if (json.row){
console.log('rowID from JSON: '+json.row['DT_RowId']);
socket.emit('updateData', json, action);
}
}
if (action == "remove") {
console.log('rowID from JSON: '+data.id[0]);
socket.emit('updateData', null, action, data.id[0]);
}
} );
editor.on('close', function(e) {
console.log('Close event');
console.log(e);
var modifier = editor.modifier();
console.log(modifier)
if (modifier !== null) {
console.log('Inside modifier')
table = $('#example').DataTable();
if (table.row(modifier).node()) {
rowID = table.row(modifier).node().id;
console.log('rowID='+rowID);
row = $("tr[id='"+rowID+"']");
row.removeClass('locked');
table.row('#'+rowID).nodes().to$().removeClass('locked');
socket.emit('unlock', rowID);
}
}
} );
As I think you know, when you're connected, you're keeping the data up-to-date, but if you have a momentary disconnect and then reconnect, you might have missed some data updates.
There are a number of possible strategies for dealing with this.
Brute-force. Upon a reconnect, get a fresh copy of all the data as if the device had just been turned on. Less efficient, but easy to implement.
Transaction ID or Transaction Time. Each time the server sends an update, it sends either a transaction ID or a transaction server time with that update. The client then keeps track of the last transaction ID or transaction time that it received. When it does a reconnect, it sends an initial message with the last transaction ID or transaction time asking for any updates that have happened since that last transaction. The server can then look through its database to see if there are any newer transactions and, if so, send them to that client. This requires keep track of transactions at your database. It is common that the server can possibly return a "transaction id not supported" type of response which then forces the client back to a brute-force update from scratch. This is a back-stop in case a database rebuild or server crash causes older transaction values to get lost.
True Synchronization. The client reconnects and then does a true synchronization with the server where the client essentially says "this is what I have, do you have anything newer". In the interest of efficiency, many synchronization systems solve this problem by implementing the transaction id described in option 2, but there are certainly many other ways to do synchronization. True synchronization is more useful if the client might also be changing the data while it was disconnected.
As a simplifying way of implementing option 2, if your database does not already support the notion of journaled transactions, then some servers will implement a transaction log in memory where it keeps track of the last N hours of transactions. As long as the server stays up and a disconnect doesn't last longer than N hours, then a request for new data can be satisfied from the in memory transaction log (which is efficient). If the server restarts or the client has been gone longer than N hours, then the client is just forced to do a brute-force update, the same as the client would have done if it was powered off and then powered back on (losing all prior knowledge of the data).
Of course, if there are multiple users of the database, then the transaction log has to be implemented by the database itself in order to make sure it includes all possible transactions.
I'm trying to test different parts of a "mostly" single page application. I'd like to split the tests up, but I really only want to load the page once and then have the tests go through and click the links etc.
Here's my code:
PRE.js
var port = require('system').env.PORT
var tester;
casper.options.viewportSize = {width: 1024, height: 768};
casper.test.begin('Test login', function suite(test) {
var done = false;
casper.on("page.error", function(msg, trace) {
this.echo("Error: " + msg, "ERROR");
this.echo("file: " + trace[0].file, "WARNING");
this.echo("line: " + trace[0].line, "WARNING");
this.echo("function: " + trace[0]["function"], "WARNING");
});
casper.on('remote.message', function(message) {
this.echo('remote message caught: ' + message);
if (message == "done") {
done = true;
}
});
casper.start('http://localhost:' + port, function() {
// Verify that the main menu links are present.
test.assertExists('input[name=username]');
// 10 articles should be listed.
test.assertElementCount('input', 3);
casper.fill("form", {
"username": "username",
"password": "my password goes right here you cant have it"
}, true);
casper.then(function() {
casper.waitFor(function(){
return done;
}, function(){
tester = casper.evaluate(function(){
return tester;
});
test.assert("undefined" != typeof tester);
test.assert(Object.keys(tester).length > 0);
});
});
});
casper.run(function() {
test.done();
});
});
and then I have a second file (and there will be lots more like this):
TEST.js
casper.test.assert(true);
casper.capture('.screenshot.png');
casper.test.done();
I'm hoping to get a screenshot of the browser session from pre.js.
I run it from a specialized program that starts up my program, but in essence it runs:
casperjs test casper_tests --pre=pre.js
casper_tests holds both files above
My Question:
What's the right way to do this? No screenshot is being taken, and perhaps more important (though I haven't tried it yet) I want to be able to click things inside and verify that other pieces are working. The screenshot just verifies that i'm in the right neighborhood.
This will not be easily possible and potentially dangerous. Every action that you do, would need to be reversed to not break the other tests. If you later decide that writing tests in a modular manner is a good thing, you will have a headache writing your tests.
PRE.js will be your start script which you modify to execute your tests in between. In the following fully working example you see how you can schedule multiple test cases for one execution of casper. This is bad, because the canvas test case depends on the proper back execution of the link test case.
casper.start('http://example.com');
casper.then(function() {
this.test.begin("link", function(test){
var url = casper.getCurrentUrl();
test.assertExists("a");
casper.click("a");
casper.then(function(){
test.assert(this.getCurrentUrl() !== url);
this.back(); // this is bad
test.done();
});
});
this.test.begin("canvas", function(test){
test.assertNotExists("canvas");
test.done();
});
});
casper.run();
Of course you can open the root again for the new test case, but then you have the same problem as with your initial code.
var url = 'http://example.com';
casper.start();
casper.thenOpen(url, function() {
this.test.begin("link", function(test){
var url = casper.getCurrentUrl();
test.assertExists("a");
casper.click("a");
casper.then(function(){
test.assert(this.getCurrentUrl() !== url);
test.done();
});
});
});
casper.thenOpen(url, function() {
this.test.begin("canvas", function(test){
test.assertNotExists("canvas");
test.done();
});
});
casper.run();
Now the test cases don't depend on each other, but you also load the page multiple times.
If you need some initial actions for every test case then the PRE.js is not the right place for that.
Create include.js and put the following code there:
function login(suite, username, password){
username = username || "defaultUsername";
password = password || "defaultPassword";
casper.test.begin('Test login', function suite(test) {
var done = false;
// event handlers
casper.start('http://localhost:' + port, function() {
// login if the session expired or it is the first run
if (!loggedIn) {
// login
}
// wait
});
casper.then(function(){
suite.call(casper, test);
});
casper.run(function() {
test.done();
});
});
}
Then you can run it as casperjs test casper_tests --includes=include.js with test files like
login(function(test){
this.click("#something");
this.waitForSelector(".somethingChanged");
this.then(function(){
test.assertExists(".somethingElseAlsoHappened");
});
});
Of course you can have different login functions (with different names) or more lightweight ones.
Building on the previous snippets, you can make a start script and load the test files yourself. Then you have all the flexibility you need to do this.
include.js:
function login(testScript, username, password, next){
// event handlers
casper.start('http://localhost:' + port, function() {
// login if the session expired or it is the first run
// waiting
});
testScript.forEach(function(case){
casper.thenOpen(case.name, function(){
this.test.begin(function suite(test){
case.func.call(casper, test);
casper.then(function(){
test.done();
});
});
});
});
casper.run(next);
}
start.js:
// pass the test file folder to the script and read it with sys.args
// fs.list(path) all files in that path and iterate over them
var filesContents = files.map(function(filename){
return require(filename).testcases;
});
var end = null;
// stack the test cases into the `run` callback of the previous execution
filesContents.forEach(function(case){
var newEnd = end;
var newFunc = function(){ login(case, u, p, newEnd) };
end = newFunc;
});
end(); // run the stack in reverse
each test file would look like this:
exports.testcases = [
{
name: "sometest",
func: function(test){
test.assert(true)
this.echo(this.getCurrenturl());
}
},
{
name: "sometest2",
func: function(test){
test.assert(true)
this.echo(this.getCurrenturl());
}
},
];
This is just a suggestion.
Here is my code
function registerPushNotifications() {
Titanium.Network.registerForPushNotifications({
types : [Titanium.Network.NOTIFICATION_TYPE_BADGE, Titanium.Network.NOTIFICATION_TYPE_ALERT],
success : function(e) {
var deviceToken = e.deviceToken;
Ti.API.info("Push notification device token is: " + deviceToken);
Ti.API.info("Push notification types: " + Titanium.Network.remoteNotificationTypes);
Ti.API.info("Push notification enabled: " + Titanium.Network.remoteNotificationsEnabled);
Ti.API.error("device Token is: " + e.deviceToken);
//return device Token to store in Model.
return e.deviceToken;
},
error : function(e) {
Ti.API.info("Error during registration: " + e.error);
},
callback : function(e) {
// called when a push notification is received.
//var data = JSON.parse(e.data);
var data = e.data;
var badge = data.badge;
if (badge > 0) {
Titanium.UI.iPhone.appBadge = badge;
}
var message = data.message;
if (message != '') {
var my_alert = Ti.UI.createAlertDialog({
title : '',
message : message
});
my_alert.show();
}
Ti.App.addEventListener('resume', function() {
alert('do another event if coming from background');
}
});
};
Depending on whether the push notification comes from the background or foreground I want to run different events.
I have tried
Ti.App.addEventListener('resume', function() {
but this fires EVERYTIME I return to the app from the background (the event handlers will be stacked every time a push notification to sent and fires all of them). As opposed to only executing that part of the callback code for push notifications that have come in from the background.
How do I know if the push notification came from the background or whilst app is running? cheers
Update:
Solved it.
If you check the call back object, you will find IsBackground as a property to check where the push notification came from.
Solution:
Check JSON object of callback for the isBackground boolean event.
If 1 it means that it was called from the background, if 0, this means that it wasn't.
I've got a little app that generates a code and stores it in mongodb(My chrome browser). Another user(My firefox browser) enters the given code and broadcasts it to let my chrome know that he's there.
Now i want my chrome browser to emit an agreement to itself and my firefox browser so they both get parsed by the same function the moment the agreement is emitted.
The point however is that i only get 1 console log in my terminal which leads me to think that only Chrome(or Firefox, which i doubt) is listening to the emit.
Can anyone take a look why not both browsers receive the 'agreement' emit?
My app.js: (The on connection part)
io.sockets.on('connection', function (socket) {
socket.on('code_game', function (data) {
if (codeToUse == data.code) {
//The receiving end received the proper code from the sending end
console.log(data.secondUser + ' is verbonden via de code: ' + data.code);
//Emit to all parties to let everyone know there's a connection
socket.emit('agreement', {
userOne: {
name: 'Timen',
code: codeToUse
},
userTwo: {
name: data.secondUser,
code: data.code
}
});
}
});
});
And the JS file being called in my view: (sendToFirstUser is Firefox in this case)
var receivingUsersCode = false;
var receivingUsersName = false;
var socket = io.connect('http://localhost');
socket.on('agreement', function (data) {
console.log("hooray");
});
function setReceivingData(code, username) {
receivingUsersCode = code;
receivingUsersName = username;
ding = 'drie';
$('#new_game').css('display', 'block');
$('.theCode').html(receivingUsersCode);
}
function sendToFirstUser(code, username) {
socket.emit('code_game', { code: code, secondUser: username});
}
I'm not sure I understand exactly what you're asking. But it seems to me like you're asking why both your Chrome and Firefox browser aren't emitting an 'agreement' event. If that's it, I think you've answered your own question:
"Another user(My firefox browser) enters the given code and broadcasts it to let my chrome know that he's there."
//Starts broadcasting to other clients
io.sockets.on('connection', function (socket) {
socket.broadcast.emit('code_game', { code: req.body.code, secondUser: req.body.secondUser});
});
Your firefox browser only emits to other clients (your chrome browser) through socket.broadcast.emit. So, only the chrome browser receives the 'code_game' event on the browser side. But in your browser side code, the client emits the 'agreement' event when it receives the 'code_game' event:
socket.on('code_game', function (data) {
if (receivingUsersCode == data.code) {
console.log(data.secondUser + ' is is connected via code: ' + data.code);
listenForMutualConnection();
socket.emit('agreement', {
userOne: {
name: receivingUsersName,
code: receivingUsersCode
},
userTwo: {
name: data.secondUser,
code: data.code
}
});
}
});
Since only the chrome browser is receiving the 'code_game' event, it's also the only one emitting the 'agreement' event.