blob: 3735931329ad030ef927f5e59f61f80b406e2be0 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var http = require("http");
var ws = require("ws");
function Dispatcher()
{
this._constructors = new Map();
this._connections = new Set();
}
Dispatcher.prototype = {
start: function(port)
{
var http_server = http.createServer();
http_server.listen(port);
var WebSocketServer = ws.Server;
var options = { server: http_server, path: "/endpoint" };
var wss = new WebSocketServer(options);
wss.on("connection", (socket) => {
var connection = new Connection(this, socket);
this._connections.add(connection);
});
},
registerObject: function(name, constructor)
{
this._constructors.set(name, constructor);
},
_connectionClosed: function(connection)
{
this._connections.delete(connection);
}
}
exports.Dispatcher = Dispatcher;
function Connection(dispatcher, socket)
{
this._dispatcher = dispatcher;
this._objects = new Map();
this._lastObjectId = 1;
this._socket = socket;
this._socket.on("message", this._dispatchMessageWrapped.bind(this));
this._socket.on("close", this._connectionClosed.bind(this));
}
Connection.prototype = {
_dispatchMessageWrapped: function(data)
{
try {
var message = JSON.parse(data);
this._dispatchMessage(message);
} catch(e) {
this._sendErrorResponse(message.id, e.toString());
}
},
_dispatchMessage: function(message)
{
var [objectName, method] = message.method.split(".");
var result = JSON.stringify({id: message.id});
var constructor = this._dispatcher._constructors.get(objectName);
if (!constructor) {
this._sendErrorResponse(message.id, "Could not resolve service '" + objectName + "'");
return;
}
if (method === "create") {
var id = String(this._lastObjectId++);
var object = new constructor(this._notify.bind(this, id, objectName));
this._objects.set(id, object);
this._sendResponse(message.id, { id: id });
} else if (method === "dispose") {
var object = this._objects.get(message.params.id);
if (!object) {
console.error("Could not look up object with id for " + JSON.stringify(message));
return;
}
this._objects.delete(message.params.id);
object.dispose().then(() => this._sendResponse(message.id));
} else {
if (!message.params) {
console.error("No params in the message: " + JSON.stringify(message));
return;
}
var object = this._objects.get(message.params.id);
if (!object) {
console.error("Could not look up object with id for " + JSON.stringify(message));
return;
}
var handler = object[method];
if (!(handler instanceof Function)) {
console.error("Handler for '" + method + "' is missing.");
return;
}
object[method](message.params).then(result => this._sendResponse(message.id, result));
}
},
_connectionClosed: function()
{
for (var object of this._objects.values())
object.dispose();
this._objects.clear();
this._dispatcher._connectionClosed(this);
},
_notify: function(objectId, objectName, method, params)
{
params["id"] = objectId;
var message = { method: objectName + "." + method, params: params };
this._socket.send(JSON.stringify(message));
},
_sendResponse: function(messageId, result)
{
var message = { id: messageId, result: result };
this._socket.send(JSON.stringify(message));
},
_sendErrorResponse: function(messageId, error)
{
var message = { id: messageId, error: error };
this._socket.send(JSON.stringify(message));
},
}