Im having a problem using Socket.io on Internet Explorer.
After some seconds conected i got this error message:
cannot connect to Web Socket server at ws://example.com.br:80/socket.io/... (SecurityError) make sure the server is running and Flash socket policy file is correctly placed.
I have done some researchs about what is a policy file, but any of those could help me.
Any thoughts?
Thanks!
/*** IO ***/
var
options = { retry_max_delay: config.app.redis.retryMaxDelay },
redis = require('redis'),
client = redis.createClient(config.app.redis.port, config.app.redis.host, options),
Connector = require('./lib/Connector'),
Helper = require('./lib/Helper'),
io = require('socket.io').listen(server),
Social = require('./lib/service/Social'),
Terms = require('./lib/service/Terms'),
UserChecker = require('./lib/service/UserChecker'),
users = {};
io.configure(function() {
'use strict';
io.set('browser client gzip' , false);
io.set('browser client minification' , false);
io.set('close timeout' , 60);
io.set('heartbeat interval' , 25);
io.set('heartbeat timeout' , 60);
io.set('log level' , config.socket.logLevel);
});
io.set('transports', [
'websocket',
'flashsocket',
'htmlfile',
'xhr-polling',
'jsonp-polling'
]);
io.on('connection', function(socket) {
'use strict';
logger.debug('Socket (' + socket.id + ') connected.');
client.incr('chat:connection');
var
connector = new Connector(socket),
social = new Social(config),
terms = new Terms(config),
userChecker = new UserChecker(connector, socket);
function send(response, bind, callback) {
if (bind) {
connector.addEventListeners();
}
if (callback) {
callback(response);
}
}
socket.on('join', function(message, callback) {
var
json = Helper.toJSON(message),
skip = userChecker.shouldSkip(json, config);
if (skip) {
var data = userChecker.skip(users, json);
users = data.users;
return send(data.response, true, callback);
}
social.check(json, function(response, access) {
if (!access) {
return send(response, false, callback);
}
terms.check(json, function(response) {
send(response, true, callback);
});
});
});
socket.on('disconnect', function() {
users = userChecker.disconnect(users);
});
});
module.exports = app;
Related
I am not sure if this is the correct way to implement a websocket connection in NodeJS, but the problem I am having is not with WebSockets but with class variables.
This is my WebSocketClass:
class WebSocketCalss {
constructor ( httpserver )
{
console.log("Initializing WebSocketCalss");
this.httpServer = httpserver;
this.connection = null;
this.client = null;
this.initializeWebSocket();
}
initializeWebSocket()
{
var WebSocketServer = require('websocket').server;
var wsServer = new WebSocketServer({
httpServer: this.httpServer
});
wsServer.on('request', function(request) {
console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
this.connection = request.accept(null, request.origin);
console.log((new Date()) + ' Connection accepted.');
this.connection.sendUTF(JSON.stringify({ type: "history", data: "data"} ));
var t = 0;
/* ---- Client ---- */
var W3CWebSocket = require('websocket').w3cwebsocket;
this.client = new W3CWebSocket('wss://ws.bitstamp.net');
this.client.onerror = function() {
console.log('Connection Error');
};
this.client.onopen = function() {
console.log('WebSocket Client Connected');
var subscribeMsg = {
"event": "bts:subscribe",
"data": {
"channel": "live_trades_btcusd"
}
};
this.client.send(JSON.stringify(subscribeMsg));
};
this.client.onclose = function() {
console.log('echo-protocol Client Closed');
};
this.client.onmessage = function(e) {
if (typeof e.data === 'string') {
var bitstampPrice = JSON.parse(e.data).data.price;
console.log(bitstampPrice);
this.connection.sendUTF(bitstampPrice);
}
};
});
//this.connection.sendUTF(JSON.stringify({ type: "history", data: "data"} ));
}
}
module.exports = (httpserver) => { return new WebSocketCalss(httpserver) }
It maybe hairy, so this is what I am trying to do:
My NodeJS server will open a WebSocket connection to my client (browser)
In this WebSocket, I want to send a value that is received from another WebSocket (that is, my NodeJS will connect as a client)
Things seem to work fine individually, however, when I try to send the value (that I received as a client), to my own client (as I am the server), I get
Cannot read property 'send' of undefined
Basically, inside the callback, the this variable are not defined. It is as if this is a new object.
I am not familiar with ES6 so I believe I am doing something fundamentally wrong.
If anyone could shed some light in to this that'd be very much appreciated.
When you use this inside a function(), the context of the this is bound to the function and not the outside class.
this.client.onopen = () => {
console.log('WebSocket Client Connected');
var subscribeMsg = {
"event": "bts:subscribe",
"data": {
"channel": "live_trades_btcusd"
}
};
this.client.send(JSON.stringify(subscribeMsg));
};
My app has three modules:
WebSocket Module: resides on the remote server (internet) and it acts as a Websocket
server that entertain the connection between Client Module and
Webhook module.
Webhook Module: resides on the remote server (internet) and it acts as
a webhook to answer the HTTP post request from the user. It is connected to Websocket Module via websocket as well.
Client Module: resides on my local machine and it is connected to
the
Webhook model via websocket. This client responsible to get query
from my local backend.
When a user call Webhook Module through HTTP Post request, Webhook module initiate a connection to WebSocket module via websocket. Then, the WebSocket module initiate the connection to Client module and response back with the necessary information. Actually I have to do this to eliminate the HTTP tunnel that is blocked in my company.
The problem is, when I open two browser windows to perform the HTTP Post request at the same time with different parameter, for example, param "A", I would expect to get return "A", with param "B", I expect to get "B" not "A". But There is something wrong with my codes/design. If I executed at the same time, I throw "A" then I got "B" which is wrong. How do I overcome this.
This is a simple diagram to illustrate it.
WebSocket Module:
'use strict'
//This is WebSocket Server
const clients = {};
const SocketIO = require('socket.io');
const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);
const ws = SocketIO(server);
const port = 3000;
var clientid;
ws.on('connection', (client) => {
clients[client.id] = client;
console.log('new connection', client.id);
clientid = client.id;
client.emit('message', { message: 'welc' })
client.on('disconnect', () => {
delete clients[client.id];
console.log('Client ' + client.id + ' disconnected. Deleted');
});
client.on('WH', function (from, msg) {
console.log('Message from Webhook', from, ' : ', msg);
client.broadcast.emit('message', { message: msg });
//console.log('send to: ' + clientid);
//ws.to(clientid).emit('hey', { message: msg });
//client.emit('message', { message: msg })
});
client.on('CL', function (from, msg) {
console.log('Message from Client', from, ' : ', msg);
client.broadcast.emit('message', 'me', msg);
//ws.to(client.id).emit('message', 'me', msg);
//client.emit('message', 'me', msg);
});
});
server.listen(process.env.PORT || port);
console.log('WebSocket Server is running on port ' + port);
Webhook Module
'use strict'
//This is WebHook Server
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const http = require('http');
const io = require('socket.io-client');
const app = express()
app.use(bodyParser.json())
const clients = {};
const SocketIO = require('socket.io');
const server = http.createServer(app);
const ws = SocketIO(server);
const port = 5000;
let Res;
let httpreq = false;
let nctid;
let ts;
const socket = io.connect('http://localhost:3000', {reconnect: true});
// Add a connect listener
socket.on('connect', function() {
console.log('Connected to WebSocket server!');
});
socket.on('message', function(from, msg) {
//console.log('Message from ', from, ' : ', msg);
console.log('nctid: ' + nctid + ', ts: ' + ts);
//Get the message from Client
if (httpreq) {
Res.send({
replies: [{
type: 'text',
content: msg,
}],
conversation: {
memory: {
key: msg
}
}
})
httpreq = false;
}
});
app.listen(process.env.PORT || port, () => {
console.log('Webhook server is running on port ' + port);
})
app.post('/', (req, res) => {
//console.log(req.body)
let query = req.body.nlp.entities.query[0].value;
nctid = req.body.nlp.entities.nctid[0].value;
ts = Math.floor(Date.now() / 1000);
console.log("query: " + query + '|' + nctid + '|' + ts);
//Send message to WebSocket server with parameter query and NCTID
socket.emit('WH', 'me', query + '|' + nctid);
Res = res;
httpreq = true;
})
app.post('/errors', (req, res) => {
console.log(req.body);
res.send();
})
Client Module
'use strict'
//This is client app running on client premise
const request = require('request');
const parser = require('xml2json');
const io = require('socket.io-client');
const socket = io.connect('http://localhost:3000', {reconnect: true});
// Add a connect listener
socket.on('connect', function(socket) {
console.log('Connected to WebSocket server!');
});
socket.on('message', function(from, msg) {
//console.log('MSG', from, ' : ', msg);
console.log(from);
let param = from.message.split('|');
let query = param[0];
let nctid = param[1];
if (typeof nctid != 'undefined') {
getNCTID(nctid, function(returnValue) {
//console.log(returnValue);
try {
let json = parser.toJson(returnValue);
json = JSON.parse(json);
if (query == 'title')
socket.emit('CL', 'me', 'Title is ' + json.clinical_study.brief_title);
else
socket.emit('CL', 'me', 'Status is ' + json.clinical_study.overall_status);
} catch (e) {
console.log(e);
socket.emit('CL', 'me', 'No NCTID ' + nctid);
}
});
}
});
function getNCTID(nctid, callback) {
let url = "https://clinicaltrials.gov/ct2/show/" + nctid + "?displayxml=true";
let options = {
url: url,
method: 'GET'
}
//console.log(options);
let requestWithEncoding = function(options, callback) {
let req = request.get(options);
req.on('response', function(res) {
let chunks = [];
res.on('data', function(chunk) {
chunks.push(chunk);
});
res.on('end', function() {
let buffer = Buffer.concat(chunks);
let encoding = res.headers['content-encoding'];
if (encoding == 'gzip') {
zlib.gunzip(buffer, function(err, decoded) {
callback(err, decoded && decoded.toString());
});
} else if (encoding == 'deflate') {
zlib.inflate(buffer, function(err, decoded) {
callback(err, decoded && decoded.toString());
})
} else {
callback(null, buffer.toString());
}
});
});
req.on('error', function(err) {
callback(err);
});
}
requestWithEncoding(options, function(err, data) {
if (err) {
console.log('err:' + err);
callback('error');
} else
//console.log(data);
callback(data);
})
}
I am having some issues using socket.io is modules. I have changed the way I do it quite drastically, however everything seems to be working, except being able to send userdata back to my socket connection:
Here is my io.js file: /config/io
/*jshint esversion: 6*/
var io = require('socket.io')();
const moment = require('moment');
// Socket stuff
io.on('connection', function (socket) {
socket.on('login', function (userdata) {
socket.handshake.session.userdata = userdata;
socket.handshake.session.save();
console.log(socket.handshake.session.userdata);
});
// Server Time
var interval = setInterval(function () {
var momentNow = moment();
var data = momentNow.format('LT');
socket.emit('time', data);
}, 60000);
// Chat - Needs work
socket.on('chat', function (msg) {
console.log(msg);
var username = 'Message'; //socket.handshake.session.userdata.username;
var message = '[' + moment().format('LT') + '] ' + username + ': ' + msg;
io.emit('message', message, username);
});
socket.on('disconnect', function () {
if (socket.handshake.session.userdata) {
delete socket.handshake.session.userdata;
socket.handshake.session.save();
}
console.log('user disconnected');
});
});
module.exports = io;
Here is where I'm trying to emit the data /config/passport: (please note that userdata does indeed contain the right information!)
/*jshint esversion: 6 */
const LocalStrategy = require('passport-local').Strategy;
const db = require('../config/db');
const bcrypt = require('bcryptjs');
var io = require('./io');
module.exports = function(passport) {
// Local Strategy login
passport.use(new LocalStrategy(function(username, password, done) {
// Match Username
let sql = 'SELECT * FROM users WHERE username = ?';
db.query(sql, [username], function(err, rows) {
if (err)
return done(err);
if (!rows.length) {
return done(null, false, {
type: 'loginMessage',
message: 'Wrong Login',
});
}
// Match Password
bcrypt.compare(password, rows[0].password, function(err, isMatch) {
if (err)
return done(err);
if (isMatch) {
var userdata = rows[0];
io.emit('login', userdata); // HERE IS WHERE I TRY TO EMIT IT
// console.log(rows[0]);
return done(null, rows[0]);
} else {
return done(null, false, {
type: 'loginMessage',
message: 'Wrong Login',
});
}
});
});
}));
Now here is my main app file: (leaving out a bunch of stuff)
var io = require('./config/io');
// Init App
const app = express();
// Init http server
const server = http.createServer(app);
// Attach IO
io.attach(server);
// Listen
server.listen(8080, function () {
console.log('Server listening on port 8080...');
});
Now, everything seems to be working fine, except being able to emit the data. Now I tried logging it client side as well (just in case it was emitting on client-side and not server-side) but it is not doing that as well.
Okay, so here is an actual working answer. It s a work-around, and I completely abandoned trying to do it from the passport login handler itself. But here is how I did it:
IO code:
var session = socket.handshake.session;
socket.on('login', function () {
if (socket.handshake.session.passport === undefined) {
var destination = '/';
socket.emit('not logged', destination);
} else {
console.log('user logged in');
var userId = session.passport.user;
var sql = 'SELECT * FROM users WHERE id = ?';
var query = db.query(sql, userId, function (err, rows) {
session.userdata = rows[0];
session.save();
var dataObj = session.userdata;
socket.emit('sart up', dataObj);
});
}
});
And jQuery:
// Connection Successful
socket.on('connect', function () {
connected = true;
socket.emit('login');
});
socket.on('disconnect', function () {
connected = false;
});
socket.on('not logged', function (destination) {
window.location.href = destination;
});
socket.on('start up', function (dataObj) {
});
I'm not a huge fan of having to do it this way, I would have liked to handle everything sever-sided, but for now this is working, and will use until I figure out how to do it the way I'd like to.
I have a little problem with my socket.io chat app. When I'm starting it, it uses 1% RAM and when it runs 2 days, it goes up to 10%+ and stop working and I have to restart it again and again.... Here is my code, how can I fix it?
Thanks for the answers!
var https = require('https');
var fs = require('fs');
var mysql = require('mysql');
var mysqlInfo;
mysqlInfo = {
host : 'localhost',
user : 'user',
password : 'pass',
database : 'user',
charset : 'utf8_general_ci'
};
var mysqlConnection = mysql.createConnection(mysqlInfo);
var options = {
key: fs.readFileSync('ssl/server.key'),
cert: fs.readFileSync('ssl/server.crt'),
ca: fs.readFileSync('ssl/ca.crt')
};
var app = https.createServer(options);
io = require('socket.io').listen(app);
app.listen(3000);
var login_users = {};
var channels = ['english'];
io.on('connection', function(socket){
setTimeout(function(){
socket.emit('login', '');
}, 1000);
socket.join('english');
socket.channel='english';
socket.on('login', function(login){
var login_json = JSON.parse(login);
mysqlConnection.query("SELECT id FROM users WHERE id=? and token=?", [login_json.id,login_json.token], function(err, results) {
if(results.length==1){
login_users[socket.id] = socket;
login_users[socket.id]["id"] = login_json.id;
login_users[socket.id]["token"] = login_json.token;
socket.join(login_json.id);
}
});
});
socket.on('chat', function(message){
if(typeof socket.id !== 'undefined'){
mysqlConnection.query("SELECT * FROM users WHERE id=? and token=?", [socket.id,socket.token], function(err, results) {
io.in(socket.channel).emit('chat', '{"message":"'+message+'"}');
}
});
}
});
socket.on('channel_change', function(channel){
if (channels.indexOf(channel) > -1 && socket.channel!=channel) {
socket.leave(socket.channel);
socket.join(channel);
socket.channel=channel;
}
});
});
setInterval(function () {
mysqlConnection.query('SELECT 1');
}, 5000);
You need to close your mysql connections after you use them.
Basically whats happening is that you keep making these queries and keep the connections object open. Chances are the connections periodically drops but your node script is still maintaining resources to keep the connections open and creating a new connection for the subsequent connections. This is where the memory leak is comming from. You should always create a new connections for each query and close it when you get the results.
var https = require('https');
var fs = require('fs');
var mysql = require('mysql');
var mysqlInfo;
mysqlInfo = {
host : 'localhost',
user : 'user',
password : 'pass',
database : 'user',
charset : 'utf8_general_ci'
};
var options = {
key: fs.readFileSync('ssl/server.key'),
cert: fs.readFileSync('ssl/server.crt'),
ca: fs.readFileSync('ssl/ca.crt')
};
var app = https.createServer(options);
io = require('socket.io').listen(app);
app.listen(3000);
var login_users = {};
var channels = ['english'];
io.on('connection', function(socket){
setTimeout(function(){
socket.emit('login', '');
}, 1000);
socket.join('english');
socket.channel='english';
socket.on('login', function(login){
var login_json = JSON.parse(login);
var mysqlConnection = mysql.createConnection(mysqlInfo);
mysqlConnection.query("SELECT id FROM users WHERE id=? and token=?", [login_json.id,login_json.token], function(err, results) {
if(results.length==1){
login_users[socket.id] = socket;
login_users[socket.id]["id"] = login_json.id;
login_users[socket.id]["token"] = login_json.token;
socket.join(login_json.id);
}
mysqlConnection.end()
});
});
socket.on('chat', function(message){
if(typeof socket.id !== 'undefined'){
var mysqlConnection = mysql.createConnection(mysqlInfo);
mysqlConnection.query("SELECT * FROM users WHERE id=? and token=?", [socket.id,socket.token],
function(err, results) {
mysqlConnection.end();
io.in(socket.channel).emit('chat', '{"message":"'+message+'"}');
}
});
}
});
socket.on('channel_change', function(channel){
if (channels.indexOf(channel) > -1 && socket.channel!=channel) {
socket.leave(socket.channel);
socket.join(channel);
socket.channel=channel;
}
});
});
What can I do to keep ram at a reasonable level?
Before i start the server I have about 140mb ram free.
After 16 hours i have about 4mb free ram left.
I'm running this on a rackspace cloud with 256mb ram.
var maxMsgs = 50;
var express = require('express'), sio = require('socket.io'), redis = require('redis'), RedisStore = require('socket.io/lib/stores/redis');
var app = express.createServer(), pub = redis.createClient(), sub = redis.createClient(), client = redis.createClient();
app.configure(function () {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.static(__dirname + '/public'));
app.use(app.router);
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
app.listen(8002, function () {
var addr = app.address();
console.log('app listening on http://' + addr.address + ':' + addr.port);
});
var io = sio.listen(app, {log: false}), nicknames = {}, history = [], user_count = 0, topic = {topic: '', setBy: 'Server'}, ytvid = {vid: '', setBy: 'Server'};
io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('store', new RedisStore({redisPub : pub, redisSub : sub, redisClient : client}));
//io.set('resource', 'socket');
io.sockets.on('connection', function(socket) {
socket.on('join', function(cu) {
if(cu.username && cu.username != 'Guest') {
socket.nickname = cu.username;
socket.emit('connected', nicknames, history, topic, ytvid);
nicknames[cu.username] = cu;
socket.broadcast.emit('nicknames', nicknames);
user_count++;
//socket.broadcast.emit('announcement', {msg: socket.nickname + ' connected'});
}
});
socket.on('message', function(msg, cb) {
if(msg.msg && msg.msg != '') {
msg.time = Date.now() / 1000;
history.push(msg);
while(history.length > maxMsgs) history.shift();
cb(true, msg.time);
socket.broadcast.emit('message', msg);
}
});
socket.on('stopic', function(t) {
if(t.topic && t.setBy && t.topic != '') {
topic = t;
io.sockets.emit('topic', t);
} else {
topic = {topic: 'No topic set', setBy: 'Admin'};
io.sockets.emit('topic', topic);
}
});
socket.on('sytvid', function(v) {
if(v.vid && v.setBy && v.vid != '') {
ytvid = v;
io.sockets.emit('ytvid', v);
} else {
ytvid = {vid: false, setBy: 'Admin'};
io.sockets.emit('ytvid', ytvid);
}
});
socket.on('get debug', function() {
socket.emit('debug', {users: nicknames, history: history, user_count: user_count, topic: topic});
});
socket.on('send command', function(c) {
if(c.type == 'empty') history = [];
io.sockets.emit('command', c);
});
socket.on('disconnect', function() {
if(!socket.nickname) return;
if(!nicknames[socket.nickname]) return;
//nicknames[socket.nickname].status = 'offline';
delete nicknames[socket.nickname];
//socket.broadcast.emit('announcement', {msg: socket.nickname + ' disconnected'});
socket.broadcast.emit('nicknames', nicknames);
user_count--;
});
});
function inArray(needle,haystack){for(var key in haystack){if(needle===haystack[key]){return true;}}return false;}
function zeroPad(digits,n){n=n.toString();while(n.length<digits){n='0'+n;}return n;}
function time(time){if(time==null)time=new Date();else if((time instanceof Date)===false)time=new Date(time);return time;}
Looks like problem in socket.on('join') point.
I recommend you to start using
var profiler = require('v8-profiler');
setInterval(function() {
profiler.takeSnapshot('snappy');
},1000);
like described here http://code.google.com/p/v8/wiki/V8Profiler
So you will now where is your leak starts.
Also carefully check allocation and deallocation of each variable, object and scope.
Let me know if you have questions.
Some people think that socket.io leaks memory when using websockets transport. Try to disable it. Something along the lines of:
io.configure('production', function(){
io.enable('browser client etag');
io.set('log level', 1);
io.set('transports', [
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
});
Also heroku has to say the following