Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

koa-ws

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

koa-ws - npm Package Compare versions

Comparing version 0.1.3 to 0.2.0

src/request.js

2

package.json
{
"name": "koa-ws",
"version": "0.1.3",
"version": "0.2.0",
"keywords": [

@@ -5,0 +5,0 @@ "koa",

@@ -43,3 +43,3 @@ [![Build Status](https://secure.travis-ci.org/mekwall/koa-ws.png)](http://travis-ci.org/mekwall/koa-ws) [![Coverage Status](https://img.shields.io/coveralls/mekwall/koa-ws.svg)](https://coveralls.io/r/mekwall/koa-ws) [![Dependency Status](https://david-dm.org/mekwall/koa-ws.png)](https://david-dm.org/mekwall/koa-ws)

Make sure the client library is loaded in the browser. The path is `/koaws.js` per default but can easily be changed.
Load the client library in the browser with require (`var koaws = require('koa-ws/client')`) or use the hosted version at `/koaws.js`.

@@ -46,0 +46,0 @@ Call the method from the client:

@@ -5,7 +5,15 @@ (function(){

var debug, hostname, port;
// Utils
var util = require('util');
// EventEmitter
var EventEmitter = require('events').EventEmitter;
// Request object
var Request = require('./request');
// Debug output
var debug;
try {
debug = require('debug')('koa:ws');
debug = require('debug')('koa-ws');
} catch (e) {

@@ -15,16 +23,2 @@ debug = console.log.bind(console);

if (typeof WS_HOSTNAME !== 'undefined') {
hostname = WS_HOSTNAME;
} else if (typeof location !== 'undefined') {
hostname = location.hostname;
} else {
hostname = 'localhost';
}
if (typeof WS_HOSTNAME !== 'undefined') {
port = WS_PORT;
} else {
port = 3000;
}
if (typeof WebSocket === 'undefined') {

@@ -34,67 +28,128 @@ var WebSocket = require('ws');

// Initialize WebSocket client
debug('Connecting to server: ws://%s:%s', hostname, port);
var client = new WebSocket('ws://' + hostname + ':' + port);
var scriptElements = document.getElementsByTagName('script');
var guessedAddress = typeof __resourceQuery === "string" && __resourceQuery ?
__resourceQuery.substr(1) :
scriptElements[scriptElements.length-1].getAttribute("src").replace(/\/[^\/]+$/, "");
// Queue list for messages
var messageQueue = [];
function Client() {
// Init EventEmitter
EventEmitter.call(this);
// Callback container for results
var awaitingResults = {};
// Queue list for messages
this._messageQueue = [];
// Simple support for events
var callbacks = client._events = {
open: [],
close: [],
connection: [],
message: []
// Callback container for results
this._awaitingResults = {};
// Client-side methods
this._methods = {};
// Event handler containers
this._events = {
open: [],
close: [],
connection: [],
message: []
};
// On WebSocket open
this.on('open', this.onOpen);
// On WebSocket close
this.on('close', this.onClose);
// On WebSocket message
this.on('message', this.onMessage);
};
if (!client.on)
client.addListener = client.on = function (type, cb) {
if (callbacks[type]) {
callbacks[type].push(cb);
} else {
callbacks[type] = [cb];
// Inherit prototype from EventEmitter
util.inherits(Client, EventEmitter);
Client.prototype.onOpen = function (e) {
debug('WebSocket opened');
if (this._messageQueue.length) {
var payload;
while (this._messageQueue.length) {
payload = this._messageQueue.shift();
debug('→ %o', payload);
this.socket.send(JSON.stringify(payload));
}
};
}
};
if (!client.once)
client.once = function (type, cb) {
client.on(type, function onceFn () {
client.off(type, onceFn);
cb.apply(cb, arguments);
});
};
Client.prototype.onClose = function (e) {
debug('WebSocket closed');
};
if (!client.off)
client.removeListener = client.off = function (type, cb) {
if (Array.isArray(callbacks[type])) {
var idx = callbacks[type].indexOf(cb);
if (idx !== -1) {
if (callbacks[type].length === 1) {
delete callbacks[type];
} else {
callbacks[type].splice(idx, 1);
}
}
Client.prototype.onMessage = function (e) {
var payload = JSON.parse(e.data || e);
if (payload.method) {
debug('← %s: %o', payload.method, payload.params);
var request = new Request(this, payload);
if (payload.error) {
debug('Got error for method %s, code %s: %s',
payload.method, payload.error.code, payload.error.message);
this._methods[payload.method].apply(
request,
payload.params
);
}
};
} else {
// Add helper handlers for the folowing events
if (typeof client._socket === 'undefined') {
if (payload.error && payload.id && this._awaitingResults[payload.id]) {
debug('← (%s) Error %s: %o', payload.id, payload.error.code, payload.error.message);
this._awaitingResults[payload.id].apply(
this,
[payload.error]
);
} else if (payload.error) {
debug('← Error %s: %o', payload.error.code, payload.error.message);
//client.emit('error', payload.error);
//console.error('Error %s: %s', payload.error.code, payload.error.message);
} else if (payload.id && this._awaitingResults[payload.id]) {
debug('← (%s) %o', payload.id, payload.result);
this._awaitingResults[payload.id].apply(
this,
[null, payload.result]
);
}
}
};
Client.prototype.connect = function (address) {
address = address || guessedAddress;
address = address.replace('ws://', '');
// Initialize WebSocket client
debug('Connecting to server: ws://%s', address);
this.socket = new WebSocket('ws://' + address);
// Add helper handlers for the folowing events
['open', 'close', 'message']
.forEach(function (type, i) {
if (!client['on' + type]) {
client['on' + type] = function () {
for (var i = 0, l = callbacks[type].length; i < l; i++) {
callbacks[type][i].apply(client, arguments);
}
};
var handler = function (e) {
this.emit.apply(this, [type].concat(Array.prototype.slice.call(arguments)));
}.bind(this);
if (this.socket.on) {
this.socket.on(type, handler)
} else if (!this.socket['on' + type]) {
this.socket['on' + type] = handler;
}
});
}
}.bind(this));
};
// Call a method
client.method = function () {
// Register a client-side method
Client.prototype.register = function (method, handler) {
if (typeof method === 'object') {
for (var name in methods) {
this.register(name, method[name]);
}
} else {
debug('Registering method: %s', method);
this._methods[method] = handler;
}
};
// Call a server-side method
Client.prototype.method = function () {
var cb = null;

@@ -117,19 +172,18 @@ var payload = {

if (cb) {
debug('Registering callback for id %s', payload.id);
awaitingResults[payload.id] = function () {
this._awaitingResults[payload.id] = function () {
cb.apply(this, arguments);
delete awaitingResults[payload.id];
delete this._awaitingResults[payload.id];
};
}
if (this.readyState !== 1) {
// Webclient is not ready, push payload to messsage queue
messageQueue.push(payload);
if (this.socket.readyState !== 1) {
// WebSocket is not ready yet, push payload to messsage queue
this._messageQueue.push(payload);
} else {
try {
debug('Sending message: %o', payload);
client.send(JSON.stringify(payload));
debug('→ %o', payload);
this.socket.send(JSON.stringify(payload));
} catch (e) {
if (cb) {
cb.call(client, e);
cb.call(this, e);
}

@@ -140,43 +194,11 @@ }

client.on('open', function (e) {
debug('WebSocket open');
var clientInstance = new Client();
if (messageQueue.length) {
var payload;
while (messageQueue.length) {
payload = messageQueue.shift();
debug('Sending message: %o', payload);
client.send(JSON.stringify(payload));
}
}
});
client.on('message', function (e) {
var payload = JSON.parse(e.data || e);
debug('Incoming message: %o', payload);
if (payload.error && payload.id && awaitingResults[payload.id]) {
debug('Got error for id %s, code %s: %s', payload.id, payload.error.code, payload.error.message);
awaitingResults[payload.id].apply(client, [payload.error]);
} else if (payload.error) {
debug('Error %s: %s', payload.error.code, payload.error.message);
//client.emit('error', payload.error);
//console.error('Error %s: %s', payload.error.code, payload.error.message);
} else if (payload.id && awaitingResults[payload.id]) {
debug('Got result for id %s: %s', payload.id, payload.results);
awaitingResults[payload.id].apply(client, [null, payload.result]);
} else if (payload.method && Array.isArray(callbacks[payload.method])) {
for (var i = 0, l = callbacks[payload.method].length; i < l; i++) {
callbacks[payload.method][i].apply(
client, [null, payload.params]);
}
}
});
// Expose the client
if (typeof module !== 'undefined' && module.exports) {
module.exports = client;
module.exports = clientInstance;
} else {
window.koaws = client;
window.koaws = clientInstance;
}
}.call(this));

@@ -1,2 +0,1 @@

var co = require('co');
var fs = require('fs');

@@ -6,211 +5,6 @@ var path = require('path');

var replaceStream = require('replacestream');
var WebSocketServer = require('ws').Server;
var cookieHelper = require('koa-ws-cookie-helper');
var debug = require('debug')('koa:ws');
var debug = require('debug')('koa-ws:middleware');
/**
* KoaWebSocketServer object
* @param app
* @param options
*/
function KoaWebSocketServer (app, options) {
// Save ref to app
this.app = app;
var KoaWebSocketServer = require('./server');
// Container for methods
this.methods = {};
// Container for sockets
this.sockets = {};
// Session to socket mapping
this.sessions = {};
}
KoaWebSocketServer.prototype.listen = function (server) {
// Create WebSocketServer
this.server = new WebSocketServer({
server: server
});
// Listen to connection
this.server.on('connection', this.onConnection.bind(this));
}
/**
* On new connection
* @param socket
*/
KoaWebSocketServer.prototype.onConnection = function (socket) {
var server = this.server;
var methods = this.methods;
var sockets = this.sockets;
var sessions = this.sessions;
socket.respond = function (method, params) {
try {
var payload = {
jsonrpc: '2.0',
method: method
};
if (params) {
payload.params = params;
}
debug('→ %s: %o', payload.method, payload.params);
socket.send(JSON.stringify(payload));
} catch (e) {
console.error('Something went wrong: ', e.stack);
}
};
socket.result = function (result) {
try {
var payload = {
jsonrpc: '2.0',
result: result,
id: this.currentId
};
debug('→ result for id %s: %o', payload.id, payload.result);
socket.send(JSON.stringify(payload));
} catch (e) {
console.error('Something went wrong: ', e.stack);
}
}
socket.error = function (code, message) {
try {
var data = {
jsonrpc: '2.0',
error: {
code: code,
message: message
},
id: this.currentId
};
debug('→', data);
socket.send(JSON.stringify(data));
} catch (e) {
console.error('Something went wrong: ', e.stack);
}
};
socket.on('close', function () {
debug('Client disconnected');
if (socket.session && Array.isArray(sockets[socket.session.id])) {
sockets[socket.session.id].splice(
sockets[socket.session.id].indexOf(socket),
1
);
}
});
socket.on('error', function (err) {
debug('Error occurred:', err);
});
socket.on('message', function (message) {
try {
var payload = JSON.parse(message);
} catch (e) {
debug('Parse error: %s', e.stack);
socket.error(-32700, 'Parse error');
return;
}
var request = {
currentId: payload.id,
method: payload.method,
params: payload.params,
session: socket.session
};
request.error = socket.error.bind(request);
request.result = socket.result.bind(request);
request.respond = socket.result.bind(request);
if (!payload.jsonrpc && payload.jsonrpc !== '2.0') {
debug('Wrong protocol: %s', payload.jsonrpc);
socket.error.apply(request, [-32600, 'Invalid Request']);
return;
}
if (!payload.method) {
debug('Missing method: %o', payload);
socket.error.apply(request, [-32600, 'Invalid Request']);
return;
}
if (typeof payload.params !== 'undefined' && typeof payload.params !== 'object' && !Array.isArray(payload.params)) {
debug('Invalid params: %o', payload.params);
socket.error.apply(request, [-32602, 'Invalid params']);
return;
}
debug('← %s: %o', payload.method, payload.params);
if (typeof methods[payload.method] === 'function') {
try {
methods[payload.method].apply(request);
} catch (e) {
debug('Internal error: %s', e.stack);
socket.error.apply(request, [-32603, 'Internal error']);
}
} else {
debug('Method not found: %s', payload.method, payload.params);
socket.error.apply(request, [-32601, 'Method not found']);
}
});
// Let's try and connect the socket to session
var sessionId = cookieHelper.get(socket, 'koa.sid', this.app.keys);
if (sessionId) {
if (typeof this.sockets[sessionId] === 'undefined') {
this.sockets[sessionId] = [];
}
this.sockets[sessionId].push(socket);
if (this.app.sessionStore) {
var _this = this;
(co(function* () {
socket.session = yield _this.app.sessionStore.get('koa:sess:' + sessionId);
socket.respond('session', socket.session);
})());
}
}
}
/**
* Register a handler generator for method
* @param method
* @param generator
* @param expose
*/
KoaWebSocketServer.prototype.register = function (method, generator, expose) {
if (typeof method === 'object') {
for (var m in method) {
this.register(m, method[m]);
}
} else if (typeof generator === 'object') {
for (var m in generator) {
this.register(method + ':' + m, generator[m]);
}
} else if (typeof method === 'string') {
debug('Registering method: %s', method);
generator.expose = expose || false;
this.methods[method] = co(generator);
}
};
/**
* Broadcast to all connected sockets
* @param method string
* @param params object
*/
KoaWebSocketServer.prototype.broadcast = function (method, params) {
for (var i in this.server.clients) {
this.server.clients[i].respond(method, params, function (err) {
debug('Could not send message', data, err);
});
}
}
module.exports = function (app, passedOptions) {

@@ -254,5 +48,4 @@ // Default options

}
yield next;
};
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc