Node.js Websocket chat app: clients receiving duplicate message - javascript

I am new to Node.js. I am trying to implement a chat app using Node.js, websocket. The code I have used on the server side:
var config = require('someconfigure'),
socketServer = require('somewebsocketapi').server;
var clients = [ ];
socketServer( 'example', function ( connection, server ) {
var index;
connection.on('open', function ( id ) {
index = clients.push(connection) - 1;
console.log('[open]');
});
connection.on('message', function ( msg ) {
console.log(msg);
var content = JSON.parse(msg.utf8Data);
var author = content.action.data[0].author;
var channel = content.action.data[0].channel;
var text = content.action.data[0].text;
var time = (new Date()).getTime();
console.log(author+text+channel);
// send messsage to all clients
var obj = JSON.stringify(
{
command:"messages",
data: [
{
timestamp: time,
text: text,
author: author,
channel: channel
}
]
}
);
console.log("Number of clients "+clients.length);
for (var i=0; i < clients.length; i++) {
if(clients[i]!= connection)
clients[i].send(obj);
}
});
connection.on('error', function ( err ) {
console.log(err);
});
connection.on('close', function(){
console.log((new Date()) + " Peer "
+ index + " disconnected.");
// remove user from the list of connected clients
clients.splice(index, 1);
});
}).config( config );
The problem I am facing is, The clients are getting duplicate messgae. For Example, If 5 clients are connected, then all the client will get the same message 5 times.
I know I am missing up something, But how I can fix this? Thank you in advance for help.

Related

UDP pinger timeout in javascript dgram node

So, for a course i'm taking, we're coding a UDP pinger in Javascript, using Node.js and Dgram. We've been given the following assignment:
Create the client code for an application. Your client should send 10 ping messages to the target UDP server. For each message, your client should calculate the round trip time from when the package is sent to when the response is received. Should a package be dropped along the way, the client is to handle this as well. This should be done by having the client wait 1 second for a response after sending each package. If no reply is received, the client should log accordingly (package lost, no response, timeout, etc.) and send a new package to try again. However, the total amount of packages sent should still only be 10. The client should also calculate a percentage of packages lost/no response received, and log this before connection is closed.
THis if course seems rather straight forward, and I thought so. I've been coding it for a while, and I'm almost finished, but I'm having issues with the aspect of making the client send a package, await response, and then act accordingly.
So far, what my code does is basically to send a ping, and when a pong is received, it sends another ping. What I can't figure out is how to make it log that a response wasn't received before sending the next package. In other words, I know how to make it react to a received response, I just don't know how to make it respond if no response is given within a set timeframe. I've tried playing around with if-statements and loops, as well as async functions, but I haven't made it work yet, so now I'm asking for help.
Code is here:
const dgram = require("dgram");
const ms = require("ms");
var client = dgram.createSocket("udp4");
const PORT = 8000;
const HOST = "localhost";
let today = "";
let t0 = "";
let t1 = "";
let RTT = "";
let sentPackages = "";
let receivedPackages = "";
const messageOutbound = Buffer.from("You Up?");
sendPackage();
const x = setInterval(sendPackage, 1000);
client.on("message", (message, remote) => {
receivedPackages++
today = new Date();
t1 = today.getTime();
console.log(
`Message from: ${remote.address}:${remote.port} saying: ${message}`
);
RTT = ms(t1 - t0, { long: true });
console.log(RTT);
const x = setInterval(sendPackage, 1000);
});
client.on('error', (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
});
async function sendPackage() {
if (sentPackages < 10) {
client.send(messageOutbound, 0, messageOutbound.length, PORT, HOST, () => {
sentPackages++
let today = new Date();
t0 = today.getTime();
console.log(
`message has been sent to ${HOST}:${PORT}. Message sent at: ${t0}`
);
});
} else {
calculateLoss();
client.close();
}
};
function calculateLoss() {
let amountLost = sentPackages - receivedPackages;
let percentageLoss = amountLost / sentPackages * 100
console.log(amountLost);
console.log(percentageLoss +"% of packages lost");
};
I would use async / await to simply wait 1000ms / 1s between messages, then keep track of all messages in an array.
We identify messages with a uuid, so we can ensure that messages we receive can be matched to those we send.
We can then log all the required statistics afterwards:
const dgram = require("dgram");
const uuid = require('uuid');
const PORT = 8000;
const HOST = "localhost";
const client = dgram.createSocket("udp4");
// Array that keeps track of the messages we send
let messages = [];
// When we get a message, decode it and update our message list accordingly...
client.on("message", (messageBuffer, remote) => {
let receivedMessage = bufferToMessage(messageBuffer);
// Find the message we sent and set the response time accordingly.
let message = messages.find(message => message.uuid === (receivedMessage ||{}).uuid);
if (message) {
message.responseTimestamp = new Date().getTime();
}
});
client.on('error', (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
});
function createMessage() {
return { uuid: uuid.v4() };
}
function messageToBuffer(message) {
return Buffer.from(JSON.stringify(message), "utf-8");
}
function bufferToMessage(buffer) {
try {
return JSON.parse(buffer.toString("utf-8"));
} catch (error) {
return null;
}
}
// Wait for timeout milliseconds
function wait(timeout) {
return new Promise(resolve => setTimeout(resolve, timeout));
}
function sendMessage(message, port, host) {
// Save the messages to our list...
messages.push(message);
console.log(`Sending message #${messages.length}...`);
// Set the time we send out message...
message.sentTimestamp = new Date().getTime();
let messageBuffer = messageToBuffer(message);
return new Promise((resolve, reject) => {
client.send(messageBuffer, 0, messageBuffer.length, port, host, (error, bytes) => {
if (error) {
reject(error);
} else {
resolve(bytes);
}
})
});
}
async function sendMessages(messageCount, port, host, timeout) {
for(let messageIndex = 0; messageIndex < messageCount; messageIndex++) {
let message = createMessage();
await sendMessage(message, port, host);
await wait(timeout);
if (message.responseTimestamp) {
console.log(`Response received after ${message.responseTimestamp - message.sentTimestamp} ms...`);
} else {
console.log(`No response received after ${timeout} ms...`);
}
}
logStatistics(messages);
}
function logStatistics(messages) {
let messagesSent = messages.length;
let messagesReceived = messages.filter(m => m.responseTimestamp).length;
let messagesLost = messagesSent - messagesReceived;
console.log(`Total messages sent: ${messagesSent}`);
console.log(`Total messages received: ${messagesReceived}`);
console.log(`Total messages lost: ${messagesLost} / ${(100*messagesLost / (messages.length || 1) ).toFixed(2)}%`);
if (messagesReceived > 0) {
console.log(`Average response interval:`, messages.filter(m => m.responseTimestamp).reduce((averageTime, message) => {
averageTime += (message.responseTimestamp - message.sentTimestamp) / messagesReceived;
return averageTime;
}, 0) + " ms");
}
}
sendMessages(10, PORT, HOST, 1000);

Running node-rdkafka code in server

I'm running the below node-rdkafka code in Eclipse as Node.js application. This is the sample code from https://blizzard.github.io/node-rdkafka/current/tutorial-producer_.html
I want to run this in a test server and call from iOS Mobile application.
I knew about running node.js app in AWS.
Question I: Is there any other options to run in a free test server environment like Tomcat?
Question II: Even If I am able to run this node.js app in a server, how do i call from a mobile application? Do I need to call producer.on('ready', function(arg) (or) What function i need to call from Mobile app?
var Kafka = require('node-rdkafka');
//console.log(Kafka.features);
//console.log(Kafka.librdkafkaVersion);
var producer = new Kafka.Producer({
'metadata.broker.list': 'localhost:9092',
'dr_cb': true
});
var topicName = 'MyTest';
//logging debug messages, if debug is enabled
producer.on('event.log', function(log) {
console.log(log);
});
//logging all errors
producer.on('event.error', function(err) {
console.error('Error from producer');
console.error(err);
});
//counter to stop this sample after maxMessages are sent
var counter = 0;
var maxMessages = 10;
producer.on('delivery-report', function(err, report) {
console.log('delivery-report: ' + JSON.stringify(report));
counter++;
});
//Wait for the ready event before producing
producer.on('ready', function(arg) {
console.log('producer ready.' + JSON.stringify(arg));
for (var i = 0; i < maxMessages; i++) {
var value = new Buffer('MyProducerTest - value-' +i);
var key = "key-"+i;
// if partition is set to -1, librdkafka will use the default partitioner
var partition = -1;
producer.produce(topicName, partition, value, key);
}
//need to keep polling for a while to ensure the delivery reports are received
var pollLoop = setInterval(function() {
producer.poll();
if (counter === maxMessages) {
clearInterval(pollLoop);
producer.disconnect();
}
}, 1000);
});
/*
producer.on('disconnected', function(arg) {
console.log('producer disconnected. ' + JSON.stringify(arg));
});*/
//starting the producer
producer.connect();
First of all, you need an HTTP server. ExpressJS can be used. Then, just tack on the Express code basically at the end, but move the producer loop into the request route.
So, start with what you had
var Kafka = require('node-rdkafka');
//console.log(Kafka.features);
//console.log(Kafka.librdkafkaVersion);
var producer = new Kafka.Producer({
'metadata.broker.list': 'localhost:9092',
'dr_cb': true
});
var topicName = 'MyTest';
//logging debug messages, if debug is enabled
producer.on('event.log', function(log) {
console.log(log);
});
//logging all errors
producer.on('event.error', function(err) {
console.error('Error from producer');
console.error(err);
});
producer.on('delivery-report', function(err, report) {
console.log('delivery-report: ' + JSON.stringify(report));
counter++;
});
//Wait for the ready event before producing
producer.on('ready', function(arg) {
console.log('producer ready.' + JSON.stringify(arg));
});
producer.on('disconnected', function(arg) {
console.log('producer disconnected. ' + JSON.stringify(arg));
});
//starting the producer
producer.connect();
Then, you can add this in the same file.
var express = require('express')
var app = express()
app.get('/', (req, res) => res.send('Ready to send messages!'))
app.post('/:maxMessages', function (req, res) {
if (req.params.maxMessages) {
var maxMessages = parseInt(req.params.maxMessages);
for (var i = 0; i < maxMessages; i++) {
var value = new Buffer('MyProducerTest - value-' +i);
var key = "key-"+i;
// if partition is set to -1, librdkafka will use the default partitioner
var partition = -1;
producer.produce(topicName, partition, value, key);
} // end for
} // end if
}); // end app.post()
app.listen(3000, () => console.log('Example app listening on port 3000!'))
I don't think the poll loop is necessary since you don't care about the counter anymore.
Now, connect your mobile app to http://<your server IP>:3000/ and send test messages with a POST request to http://<your server IP>:3000/10, for example, and adjust to change the number of messages to send
I might be late on this but this is how I did using promises and found it better than have a time out etc.
const postMessageToPublisher = (req, res) => {
return new Promise((resolve, reject) => {
producer.connect();
producer.setPollInterval(globalConfigs.producerPollingTime);
const actualBody = requestBody.data;
const requestBody = req.body;
const topicName = req.body.topicName;
const key = requestBody.key || uuid();
const partition = requestBody.partition || undefined;
const data = Buffer.from(JSON.stringify(udpatedBody));
/**
* Actual messages are sent here when the producer is ready
*/
producer.on(kafkaEvents.READY, () => {
try {
producer.produce(
topic,
partition,
message,
key // setting key user provided or UUID
);
} catch (error) {
reject(error);
}
});
// Register listener for debug information; only invoked if debug option set in driver_options
producer.on(kafkaEvents.LOG, log => {
logger.info('Producer event log notification for debugging:', log);
});
// Register error listener
producer.on(kafkaEvents.ERROR, err => {
logger.error('Error from producer:' + JSON.stringify(err));
reject(err);
});
// Register delivery report listener
producer.on(kafkaEvents.PUBLISH_ACKNOWLEDGMENT, (err, ackMessage) => {
if (err) {
logger.error(
'Delivery report: Failed sending message ' + ackMessage.value
);
logger.error('and the error is :', err);
reject({ value: ackMessage.value, error: err });
} else {
resolve({
teamName: globalConfigs.TeamNameService,
topicName: ackMessage.topic,
key: ackMessage.key.toString()
});
}
});
});
};
Please note that kafkaEvents contains my constants for the events we listen to and it is just a reference such as kafkaEvents.LOG is same as event.log
and also the calling function is expecting this to a promise and accordingly we user .then(data => 'send your response to user from here') and .catch(error => 'send error response to user
this is how I achieved it using promises

Websockets: send messages and notifications to all clients except sender

I am developing chat based on websockets and webrtc. I would like to send messages to all connected users except sender but I cannot find suitable solution. To be more specific, I would like to send notifications to other connected users that new user has joined to the chat.
I am trying to give a unique ID to every connected user, but the first assigned ID is re-writed by every new user and I cannot diferentiate users.
Server:
// list of users
var CLIENTS=[];
var id;
// web server is using 8081 port
var webSocketServer = new WebSocketServer.Server({ port: 8081 });
// check if connection is established
webSocketServer.on('connection', function(ws) {
id = Math.random();
CLIENTS[id] = ws;
CLIENTS.push(ws);
ws.on('message', function(message) {
console.log('received: %s', message);
var received = JSON.parse(message);
if(received.type == "login"){
ws.send(message); // send message to itself
/* *********************************************************** */
/* *** Here I trying to check if message comes from sender *** */
sendNotes(JSON.stringify({
user: received.name,
type: "notes"
}), ws, id);
/* *********************************************************** */
}else if(received.type == "message"){
sendAll(message); // broadcast messages to everyone including sender
}
});
ws.on('close', function() {
console.log('user ' + CLIENTS[ws] + ' left chat');
delete CLIENTS[ws];
});
});
function sendNotes(message, ws, id) {
console.log('sendNotes : ', id);
if (CLIENTS[id] !== ws) {
console.log('IF : ', message);
for (var i = 0; i < CLIENTS.length; i++) {
CLIENTS[i].send(message);
}
}else{
console.log('ELSE : ', message);
}
}
function sendAll(message) {
for (var i=0; i < CLIENTS.length; i++) {
CLIENTS[i].send(message); // broadcast messages to everyone including sender
}
}
Client:
loginButton.addEventListener("click", function(){
name = usernameInput.value;
if(name.length > 0){
socket.send(JSON.stringify({
type: "login",
name: name
}));
}
});
function sendData() {
var data = dataChannelSend.value;
var userName = document.getElementById('greetingUser').innerHTML;
socket.send(JSON.stringify({
username : userName, // fetch user name from browser, after login
type : "message",
message : data
}));
}
socket.onmessage = function(message) {
var envelope = JSON.parse(message.data);
switch(envelope.type) {
case "login":
onLogin(envelope);
break;
case "message":
showMessage(envelope);
break;
}
};
I would highly appreciate If you could give me any hint. Thanks
Here is a very simple way of sending to everyone connected except the sender.
Create a broadcast function on your webSocketServer instance that will
take two params.
...
var webSocketServer = new WebSocketServer.Server({ port: 8081 });
...
/*
* method: broadcast
* #data: the data you wanna send
* #sender: which client/ws/socket is sending
*/
webSocketServer.broadcast = function(data, sender) {
webSocketServer.clients.forEach(function(client) {
if (client !== sender) {
client.send(data)
}
})
}
...
// On your message callback.
ws.on('message', function(message) {
...
// Note that we're passing the (ws) here
webSocketServer.broadcast(message, ws);
})
That's it, the broadcast method will send to each connected client
except the one who is sending.
Ok, so we are now storing the CLIENTS in a way that allows us to uniquely identify each client that is connecting, and store arbitrary information about them for later retrieval.
The code below will send the "notes" message to all clients, and THEN add the newly connecting client to the "all clients" list.
SERVER.JS:
var http = require('http'),
Static = require('node-static'),
WebSocketServer = new require('ws'),
// list of users
/*
We are now storing client data like this:
CLIENTS = {
uniqueRandomClientID: {
socket: {}, // The socket that this client is connected on
clientDetails: { // Any details you might wish to store about this client
username: "",
etc: "etc"
}
}
};
So now to get at the socket for a client, it'll be: CLIENTS[uniqueRandomClientID].socket.
Or to show a client's username, it'll be: CLIENTS[uniqueRandomClientID].clientDetails.username.
You might want to write a 'getClientByUsername' function that iterates the CLIENTS array and returns the client with that username.
*/
CLIENTS = {},
// web server is using 8081 port
webSocketServer = new WebSocketServer.Server({ port: 8081 });
// check if connection is established
webSocketServer.on('connection', function(ws) {
console.log('connection is established');
// Now using a randomly generated ID to reference a client. Probably should be better than Math.random :D
var wsID = Math.floor(Math.random() * 1000);
ws.on('message', function(message) {
console.log('received: %s', message);
var received = JSON.parse(message);
if(received.type == "login"){
// If a client with this login name doesnt exist already, its a new client
if(!CLIENTS[wsID]) {
doBroadcast(
{
"newuser": received.name,
type: "notes"
}
);
// Now add this new client to the list
CLIENTS[wsID] = {
socket: ws,
clientDetails: {
username: received.name
}
};
}
} else if(received.type == "message") {
doBroadcast(message); // broadcast messages to everyone including sender
}
});
ws.on('close', function(_event) {
if(CLIENTS[wsID]) {
console.log('user ' + CLIENTS[wsID].clientDetails.username + ' left chat');
delete CLIENTS[wsID];
}
});
/*
* Added this to 'catch' errors rather than just red dump to console. I've never actually done anything with this myself (I *like* red text in my console), but I know this handler should be here :P
*/
ws.on('error', function(_error) {
console.log("error!");
console.log(_error);
});
/*
* Send an object to a client
*
* #param WebSocketClient _to - The client you want to send to (generally an index in the CLIENTS array, i.e CLIENTS["bobsusername123"]
* #param Object _message - A stringifyable JSON object. Complex ones can screw things up, but your basic key/value pairs are usually fine to send.
*/
function doSend(_to, _message) {
_to.send(JSON.stringify(_message));
};
// Added broadcast function to replace sendAll
// Notice how it JSON stringifies the data before sending
/*
* Broadcast a message to all clients
*
* #param Object _message - A stringifyable JSON object. Complex ones can screw things up, but your basic key/value pairs are usually fine to send.
*/
function doBroadcast(_message) {
for(var client in CLIENTS) {
if(!CLIENTS.hasOwnProperty(client)) continue;
doSend(CLIENTS[client].socket, _message);
}
};
});
var fileServer = new Static.Server('.');
http.createServer(function (req, res) {
fileServer.server(req, res);
}).listen(8080, function(){
console.log("Server is listening 8080 port.");
});
console.log("Server is running on 8080 and 8081 ports");
MY CLIENT.JS (for your reference):
var loginButton = document.getElementById("loginbutton"),
usernameInput = document.getElementById("usernameInput");
var SocketClient = function(_uri, _callbacks) {
this.uri = _uri;
this.callbacks = _callbacks;
};
SocketClient.prototype = {
send: function(_message) {
this.socket.send(_message);
},
connect: function() {
try {
this.socket = new WebSocket("ws://" + this.uri);
} catch(e) { return false; }
for(var callback in this.callbacks) {
if(!this.callbacks.hasOwnProperty(callback)) continue;
this.socket["on" + callback] = this.callbacks[callback];
}
return true;
}
};
var socketClient = new SocketClient(
"127.0.0.1:8081",
{
open: function() {
console.log("connected.");
},
message: function(_message) {
console.log("received data:");
console.log(_message);
},
close: function() {
console.log("closed.");
},
error: function(_error) {
console.log("error: ");
console.log(_error);
}
}
);
socketClient.connect();
loginButton.addEventListener("click", function(){
name = usernameInput.value;
if(name.length > 0){
socketClient.send(JSON.stringify({
type: "login",
name: name
}));
}
});
AND THE CLIENT.HTML TO GO WITH IT:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<input type="text" id="usernameInput"/>
<button type="button" id="loginbutton">Login</button>
<script src="client.js"></script>
</body>
</html>
Ive tested this with NWJS v0.12.3 running the server and Firefox on the client.
This should work
const WebSocket = require('ws');
// Websocket variables
const wss = new WebSocket.Server({
port: 3000
});
console.log('Websocket active on port 3000...');
// New WebSocket Connection
wss.on('connection', function connection(ws) {
console.log('new connection')
// On Message Received
ws.on('message', function incoming(message) {
console.log(message)
// Send To Everyone Except Sender
wss.clients.forEach(function(client) {
if (client !== ws) client.send(message);
});
});
});

Why does my websocket close after a few minutes?

I'm using ws with node.js on the server side and the regular WebSocket API on the client side. Opening the connection and messaging a few times back and forth works fine. But the socket always closes after a minute or two. Aren't they supposed to persist? Am I doing something wrong?
My server is node.js hosted on heroku. I just tested locally again using foreman start (the heroku tool to run the server locally) and the socket doesn't close unexpectedly at all, so perhaps it's a misconfiguration on heroku. Anyway, here's a relevant code sample with a few functions omitted for brevity.
I'm testing the application in Chrome on OSX Yosemite but have seen the same behavior in Chrome on Windows 7 when running against production environment.
server:
// Client <-> Host Protocol functions. Move to a different file so that they can be shared.
var C2H_SIGNAL_TYPE_REGISTER = "register";
var H2C_SIGNAL_WELCOME = "welcome";
var H2C_SIGNAL_TYPE_ERROR = "error";
var H2C_SIGNAL_TYPE_PEER_ADDED = "peer_joined";
var H2C_SIGNAL_TYPE_PEER_LEFT = "peer_left";
// Update channel endpoint names.
var UPDATE_ENDPOINT_PEERS = "/peers";
// Create a signal message with all asociated default properties.
// Signal senders should create this object and update it accordingly when
// building a signal message to send to a peer.
function createHostMsg(type)
{
var msg = { signalType: type };
if ( type == H2C_SIGNAL_WELCOME ) {
// Since we're sending a welcome message, we need to provide a list
// of currently connected clients.
msg.peers = {};
for ( var addr in clients ) {
console.log("addr " + addr);
var c = clients[addr].description;
if ( c && c.id ) {
msg.peers[c.id] = c;
}
}
}
return msg;
}
// require modules.
var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');
var multer = require('multer');
// Tracks connected peers.
var clients = { };
// 1. Configure the application context settings.
var app = express();
app.enable('trust proxy');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json()); // parse json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(multer()); // for parsing multipart/form-data
// a. configure http routers. these will handle requests coming from app.
app.set('port', (process.env.PORT || 5000));
app.get('/app', peerApp);
app.get('/script/:name', publicScriptRouter);
// 2. Create the http server itself, passing app to be the request handler.
// app will handle routing and multiplexing of incoming requests to different
// route middleware handlers.
var http = require('http');
var WebSocketServer = require("ws").Server
var httpServer = http.createServer(app);
httpServer.listen( app.get('port') );
// 3. Create one of these for all socket endpoints.
var wss = new WebSocketServer( { server: httpServer, path: UPDATE_ENDPOINT_PEERS } );
wss.on("connection", function(webSocket) {
// 1. Associate the socket with the remote address it came from.
var remoteAddress = webSocket._socket.remoteAddress;
var remotePort = webSocket._socket.remotePort;
var clientConnID = remoteAddress + ":" + remotePort;
var exists = clients[clientConnID] != null;
if ( exists ) {
console.log("socket server connection: associating new connection from %s with registered peer.", clientConnID);
clients[clientConnID].socket = webSocket;
} else {
console.log("socket server connection: associating new connection from %s with unregistered peer.", clientConnID);
clients[clientConnID] = { description: null, socket: webSocket };
}
// 2. Hook up handlers for communication over this particular socket.
webSocket.on("message", function(data, flags) {
processMessage(webSocket, data, flags);
});
webSocket.on("close", function() {
// Praise satin for closures!!
removePeer(clientConnID);
});
});
// Transduce the message and handle it accordingly.
function processMessage(socket, data, flags)
{
var msg = JSON.parse(data);
if ( !msg.signalType ) {
var msg = createHostMsg( H2C_SIGNAL_TYPE_ERROR );
msg.errStr = "message_malformed";
socket.send( JSON.stringify( msg ) );
} else if ( msg.signalType == C2H_SIGNAL_TYPE_REGISTER ) {
handleRegistration(socket, msg);
}
}
client:
function initSignalChannel()
{
rtcPeer.channel = new WebSocket( location.origin.replace(/^http/, 'ws') + "/peers" );
rtcPeer.channel.onmessage = updateChannelMessage;
rtcPeer.channel.onopen = function(event) {
console.log("remote socket opened");
}
rtcPeer.channel.onclose = function(event) {
console.log("host closed remote socket.");
}
}
function updateChannelMessage(event) {
var msgObj = JSON.parse(event.data);
if ( !msgObj || !msgObj.signalType ) {
console.log("updateChannelMessage: malformed response!! %o", msgObj );
} else if ( msgObj.signalType == "welcome" ) {
console.log("updateChannelMessage: received welcome from host.");
handleWelcome(msgObj);
} else if ( msgObj.signalType == "peer_joined" ) {
console.log("updateChannelMessage: received peer_joined from host.");
if ( msgObj.peer.id == rtcPeer.description.id ) {
console.log("updateChannelMessage: peer_joined: received notification that I've been added to the room. " + msgObj.peer.id);
console.log(msgObj);
} else {
console.log("updateChannelMessage: peer_joined: peer %s is now online.", msgObj.peer.id);
console.log(msgObj);
addRemotePeer( msgObj.peer );
}
}
}
function addRemotePeer(peerObj)
{
remotePeers[peerObj.id] = peerObj;
var ui = createPeerUIObj(peerObj);
$("#connectedPeerList").append( ui );
}
function createPeerUIObj(peerObj)
{
var ui = null;
if ( peerObj ) {
ui = $("<li></li>");
var a = $("<a></a>");
a.append("peer " + peerObj.id);
ui.append(a);
ui.click(function(event) { console.log("clicked");});
}
return ui;
}
function handleWelcome(msgObj)
{
if ( msgObj.id ) {
console.log("updateChannelMessage: welcome: received id from host. " + msgObj.id);
console.log(msgObj);
rtcPeer.description.id = msgObj.id;
for ( var p in msgObj.peers ) {
addRemotePeer(msgObj.peers[p]);
}
} else {
console.log("updateChannelMessage: malformed response. no id.");
}
}
Thanks for the comments everyone. It turns out that jfriend00 had the right answer, I just didn't realize that the hosting service I was using wouldn't allow for the connection to be kept open.
From the below forum posting, the solution is
you'll need to make your clients ping the server periodically to keep the socket alive.
Not the most ideal situation, but indeed doable. Thanks for pointing me in the right direction.

how to prevent new connection on every page refresh in sockjs

So, every time I refresh the page, it seems like sockjs is creating a new connection.
I am saving every message to my mongodb on every channel.onmessage, so if I refresh my page 7 times and send a message, I would save 7 messages of the same content into my mongodb.
This is very problematic because when I retrieve those messages when I go into the chat room, to see the log, I would see bunch of duplicate messages.
I want to keep track of all connections that are 'active', and if a user tries to make another connection, I want to terminate the old one so there is only one connection listening to each message at a time.
How do I do this ?
var connections = {};
//creating the sockjs server
var chat = sockjs.createServer();
//installing handlers for sockjs server instance, with the same url as client
chat.installHandlers(server, {prefix:'/chat/private'});
var multiplexer = new multiplexServer.MultiplexServer(chat);
var configChannel = function (channelId, userId, userName){
var channel = multiplexer.registerChannel(channelId);
channel.on('connection', function (conn) {
// console.log('connection');
console.log(connections);
connections[channelId] = connections[channelId] || {};
if (connections[channelId][userId]) {
//want to close the extra connection
} else {
connections[channelId][userId] = conn;
}
// }
// if (channels[channelId][userId]) {
// conn = channels[channelId][userId];
// } else {
// channels[channelId][userId] = conn;
// }
// console.log('accessing channel! ', channels[channelId]);
conn.on('new user', function (data, message) {
console.log('new user! ', data, message);
});
// var number = connections.length;
conn.on('data', function(message) {
var messageObj = JSON.parse(message);
handler.saveMessage(messageObj.channelId, messageObj.user, messageObj.message);
console.log('received the message, ', messageObj.message);
conn.write(JSON.stringify({channelId: messageObj.channelId, user: messageObj.user, message: messageObj.message }));
});
conn.on('close', function() {
conn.write(userName + ' has disconnected');
});
});
return channel;
};
The way I resolve a problem like yours was with a Closure and Promises, I don't know if that could help you. I let you the code that help me, this is with EventBus from Vertx:
window.Events = (function NewEvents() {
var eventBusUrl = $('#eventBusUrl').val();
var eventBus = null;
return new RSVP.Promise(function(resolve, reject) {
if(!eventBus) {
eventBus = new vertx.EventBus(eventBusUrl);
eventBus.onopen = function eventBusOpened() {
console.log('Event bus online');
resolve(eventBus);
}
eventBus.onclose = function() {
eventBus = null;
};
}
});
}());
And then in other script I call it in this way:
Events.then(function(eventBus) {
console.log("registering handlers for comments");
eventBus.registerHandler(address, function(incomingMessage) {
console.log(incomingMessage);
});
});
I hope this can help you.
Regards.

Categories