I think what I need to do is reset Socket.io entirely after each test using socket.io.
Any ideas? Here's what I'm doing:
I have a test using Socket.IO's Client library, an angular service (github.com/chrisenytc/ng-socket), requireJS, and a local test server. When using karma's watch feature, it runs fine the first time, but fails subsequent attempts (event listeners aren't triggered, debug logging shows an 'xhr poll error').
the simple version of the test is (full version):
define(['services/serviceModule', 'angular-mocks'], function() {
describe('ILC Server Services', function() {
var socket;
beforeEach(module('ignisLibriColloqui.services', function(Config, $socketProvider) {
$socketProvider.setUrl(Config.ilcTestServerUrl);
Config.ilcServerUrl = Config.ilcTestServerUrl;
url = Config.ilcTestServerUrl;
}));
beforeEach(inject(function(ILCServerService, $socket) {
ilcServerService = ILCServerService;
socket = $socket;
}));
it('expects emit(\'ping\') to trigger on(\'pong\')', function(done) {
socket.emit('ping',{})
socket.on('pong',function(data) {
done();
});
});
});
});
and the simple server is (full version)
var httpPort = 10999;
var socketPort = 5001;
var restify = require('restify');
var socketio = require('socket.io')(socketPort);
var fs = require('fs');
var server = restify.createServer({
name: 'ilcServer Mock'
});
var io = socketio.listen(server);
server.get(/.*/, restify.serveStatic({
'directory': __dirname,
'default': './app/index.html',
'maxAge': 0
}));
io.sockets.on('connection', function(socket) {
var socketId = socket.id;
console.log('user connected');
socket.on('ping', function(data) {
console.log('ping');
socket.emit('pong', data);
});
socket.on('disconnect',function() {
console.log('disconnect');
socket.disconnect();
});
});
server.listen(httpPort, function() {
console.log('restify server listening at %s', server.url, 'socket port:', socketPort);
});
Edit
After carefully exploring the connections using the logging described by the Socket.io docs it has become clear to me that disconnecting the client is not enough. The client logs the "pong" events without firing the socket.on('pong',event), even when using an afterEach to cause socket.disconnect() and socket.io.connect(function(){done()}) to trigger, the new calls to socket.emit are not triggered.
Related
I have a Node/Vue application. I am consuming a WebSocket from Binance, a crypto exchange. I can see the quotes on the server console as I log them, I can send them to the browser for a short period of time before the client stops logging them.
Browser just using WebSocket API
Node using ws library
Node code, this I am running as it's own service as its just this.
'use strict';
const WebSocket = require('ws');
const binanceWS = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt#trade')
const server = new WebSocket.Server({ port: 5002 });
//websocket connection event will return a socket you can later use
binanceWS.on("open", function() {
console.log("connected to Binance");
});
binanceWS.on('message', function(data){
console.log(data);
server.on('connection', function connection(ws){
console.log("Connected a new client");
ws.send(data);
});
server.on('closed', function (id){
console.log("connection closed");
console.log(id);
});
server.on('error', function (err){
console.log(err)
})
})
On the Client side I am using Vue and in the app.js file I have this on the created hook.
let socket = new WebSocket("ws://localhost:5002")
socket.addEventListener('message', function(event){
let quotes = JSON.parse(event.data);
console.log(quotes.p)
});
socket.addEventListener('error', function(event){
console.log("closing because " + event);
})
Right now I am only listening to the consoles in the above app.vue file.
What I see in the browser console is a lot of quotes, then they stop after a second or 2. There can be over a thousand quotes in some times. Then on occasion I see a console.log('created') that I have in a child component of app.vue. In many cases this is the last thing in the console after hundreds of quotes.
In the console.log for the server I see a lot of sessions being created with one page refresh. So much that it fills my console.
So I'm not sure I am creating the connections correcly, I am not sure if Vue is somehow stopping the console.log's?
I don't see any errors anywhere and the entire time in my server console the Binance API continues streaming.
you have to write server event listener outside binance on message handler;
then you can pass messages from binance to the server by emitting new event to the server
on receiving message from binance you can send data to all connection on the server
Or Try this code I think it will work :
'use strict';
const WebSocket = require('ws');
const binanceWS = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt#trade')
const server = new WebSocket.Server({ port: 5002 });
server.on('connection', function connection(ws){
console.log("Connected a new client");
});
server.on('closed', function (id){
console.log("connection closed");
console.log(id);
});
server.on('error', function (err){
console.log(err)
})
//websocket connection event will return a socket you can later use
binanceWS.on("open", function() {
console.log("connected to Binance");
});
binanceWS.on('message', function(data){
console.log(data);
server.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
})
I have been looking into this Socket.io MVC node.js but I'm currently struggling.
It says in the documentation:
Socket.io API's
Since Socket.MVC is just a wrapping mechanism for Socket.io, all of
the same API's can be used using the Socket.MVC module. Please see a
list of all of the API's available by visiting the Socket.io Github
page, or http://socket.io (depending on your version)
My problem is that I cant find a way to emit socket MVC to a room.
socketMVC.to(userid).emit('message', {message:2});
Should work, but it doesn't. Any idea how I can accomplish this?
EDIT:
userid is same as assigned here:
import * as io from 'socket.io-client';
download
oninit:
this.socket = io(this.socketurl);
var privateRoom = socket.request.session.passport.user;
socket.join(privateRoom);
this.socket.on('message', (data) => {
// this.messagesCounter = this.messagesCounter + 1;
alert("OMG?");
});
edit , in server.js
io.on('connection',function(socket) {
console.log('user connected');
OnlineUsers.push(socket);
// socket.join('');
console.log(socket.request.session.passport);
console.log("user is connceted");
socketMVC.init(io, socket, {
debug: true,
filePath: ['./src/routes/sockets.js']
});
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('add-message',function (message) {
io.emit('message', {type:'new-message', text: message});
});
socket.on('myevent', function(someData) {
console.log("MYEVENT WORKS???????");
});
});
sockets.js
var path = require('path');
module.exports = function (socket) {
var privateRoom = socket.request.session.passport.user;
socket.join(privateRoom);
socket.on('testing', function() {
console.log('GOT SOME SORT OF RESPONSE!!!');
});
};
Replace socketMVC.to by socketMVC.io.to.
I have a use case where I need to take input from browser pass it to my node server over a socket, this input is then send to a third party website for processing again over socket. The result received from the third party website needs to be sent back to browser.
node server
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var socketIO = require('socket.io'),
server, io;
var thirdPartSocketClient = require('socket.io-client');
//Custom imports
var thirdParty = require('./ms_socket.js');
var socket = socketIO(server);
socket.on('connection', function(client) {
var token = null;
//Token from third party site that we should have before sending the actual info
thirdParty.getToken(function callback(returnToken) {
token = returnToken;
});
thirdPartSocketClient = thirdParty.getTranslation(token);
client.on('audio', function(data) {
thirdPartSocketClient.emit(data);
});
});
server.listen(8080, function() {
console.log('Open http://localhost:8080 in your browser');
});
ms_socket.js
//Exported function making a socket call to third party service
var exports = module.exports = {};
var request = require('request');
var wsClient = require('socket.io-client');
var fs = require('fs');
exports.getToken = function(callback) {
//send back the token
}
exports.getTranslation = function(accessToken) {
var ws = new wsClient(thirdPartySocketURL);
// event for connection failure
ws.on('connectFailed', function(error) {
console.log('Initial connection failed: ' + error.toString());
});
// event for connection succeed
ws.on('connect', function(connection) {
console.log('Websocket client connected');
// process message that is returned
//processMessage would process the incoming msg from third party service
connection.on('message', processMessage);
connection.on('close', function(reasonCode, description) {
console.log('Connection closed: ' + reasonCode);
});
// print out the error
connection.on('error', function(error) {
console.log('Connection error: ' + error.toString());
});
});
// connect to the service
ws.connect(thirdPartySocketURL, null, null, {
'Authorization': 'Bearer ' + accessToken
});
return ws;
}; //End of export function
I am able to receive the data from browser, make a connection to third party service (can see the socket connection) and emit the data. however I am unable to receive the reply back from the third part service.
Is it because node is not listening to my socket events of thirdparty ?
Not sure exactly why its not working.
I save the data locally on the server, read the file and then send it, then I get a response back from the service.
If this is not a "right" design can you please suggest a good way, should I be using message queues (if yes, feel free to recommend one)
Thanks
Testing node httpServer and webSocketServer(ws)
Trying to implement a http-ws server that will close after a client is connected as illustrated below:
var HTTPserver =
httpServer(require('path')
.join(__dirname, 'www'));
HTTPserver
.on('listening', function()
{
console.log('HTTP listening:');
//---------------
var WebSocket = require('ws');
var webSocketServer =
new WebSocket.Server(
{
server: HTTPserver
});
webSocketServer
.on('connection',
function(ws)
{
console.log('client connected');
setTimeout(function()
{
console.log('trying to close webSocketserver');
webSocketServer.close();
setTimeout(function()
{
console.log('trying to close HTTPserver');
HTTPserver.close();
}, 1000);
}, 1000);
});
})
.on('close', function()
{
console.log('server closed'); // never happens
})
.on('error', function()
{
console.log('server error');
})
.listen(8000);
// this works when no Client Connection
/*
setTimeout(function()
{
HTTPserver.close();
}, 3000);
*/
I uploaded the full test project.
https://github.com/kenokabe/http-ws-test
HTTPserver.close(); works just as expected without ws client connections.
HTTPserver.close(); does not work (fails to close) with ws client connections.
Any idea what is going on and how to fix this issue? Thanks.
**PS. Please note that what I need to close is
NOT only ws connections but also httpServer.
I need to open and close whole frequently.
The reason to close httpServer is that the project is for plugin, and need to shut down httpServer in a specific case.**
UPDATE
I modified the code to close webSocketServer before httpServer, but still httpServer is alive.
I updated my gitHub
https://github.com/kenokabe/http-ws-test
Finding
How do I shutdown a Node.js http(s) server immediately?
Force close all connections in a node.js http server
connection->socket needs to be destroyed for each.
For my sample code, I use ES6 observe method.
http://wiki.ecmascript.org/doku.php?id=harmony:observe#object.observe
http://wiki.ecmascript.org/doku.php?id=harmony:observe_api_usage
https://github.com/jdarling/Object.observe
var IO = {
terminate:
{
val: false
}
};
var trigger = function(obj)
{
obj.val = !obj.val;
};
var HTTPserver =
httpServer(require('path')
.join(__dirname, 'www'));
var webSocketServer;
HTTPserver
.on('listening', function()
{
console.log('HTTP listening:');
//---------------
var WebSocket = require('ws');
webSocketServer =
new WebSocket.Server(
{
server: HTTPserver
})
.on('connection',
function(ws)
{
console.log('client connected');
});
})
.on('close', function()
{
console.log('server closed'); // never happens
})
.on('error', function()
{
console.log('server error');
})
.on('connection', function(socket)
{
console.log('connection');
Object.observe(IO.terminate, function(changes)
{
console.log('now!2');
socket.destroy();
});
})
.listen(8000);
setTimeout(function()
{
console.log('now');
HTTPserver.close();
webSocketServer.close();
trigger(IO.terminate);
}, 15000);
I'm using the code below to test websockets on my browser:
this.webSocket = new WebSocket("ws://echo.websocket.org");
this.webSocket.onopen = function(evt) {
cc.log("Send Text WS was opened.");
};
this.webSocket.onmessage = function(evt) {
this.socketSendTextTimes++;
var textStr = "response text msg: " + evt.data + this.socketSendTextTimes;
cc.log(textStr);
};
The code works well, but if I connect to my own server running the code below:
var http = require('http');
var io = require('socket.io');
var server = http.createServer(function(req, res) {
// Send HTML headers and message
res.writeHead(200,{ 'Content-Type': 'text/html' });
res.end('<h1>Hello!</h1>');
});
var socket = io.listen(server);
socket.set('destroy upgrade', false);
socket.on('connection', function(client) {
client.on('message', function(event) {
console.log('Received message from client!', event);
});
client.on('disconnect', function() {
console.log('Server has disconnected');
});
});
server.listen(8080);
console.log('start to listen');
My browser displays:
hello!
But the listening socket does not do anything. How can I connect to the Socket.IO server using websockets?
Socket.IO uses alternate transport methods than the native websocket, even when emulating websockets themselves. You will need the client library to connect to Socket.IO sockets.