thintalk
Version:
Very thin RPC layer using TPC and IPC
153 lines (123 loc) • 3.41 kB
JavaScript
/**
* Copyright (c) 2012 Andreas Madsen
* MIT License
*/
(function () {
"use strict";
// get the core
var events = require('events'),
util = require('util'),
helpers = require('./helpers.js'),
message = require('./message.js'),
handlers = {};
/**
* Requester
*/
function Requester(args) {
this.lisenter = args[0];
this.remote = null;
this.online = false;
}
util.inherits(Requester, events.EventEmitter);
exports.Requester = Requester;
// connect to remote
Requester.prototype.connect = function (layerName, object) {
var self = this;
// get layer collection
var layerCollection = exports.layers[layerName];
// check that layer is supported
if (layerCollection === undefined) {
this.emit('error', new Error('The layer ' + layerName + ' do not exist.'));
return;
}
// Create and store layer object
this.layer = new layerCollection.Requester(object);
// keep online state
this.layer.on('connect', function () {
self.online = true;
});
this.layer.on('close', function () {
self.online = false;
});
// Relay error and close events
this.layer.on('close', this.emit.bind(this, 'close'));
this.layer.on('error', this.emit.bind(this, 'error'));
this.layer.on('connect', function () {
// execute connect callback given by arguments[0] if exist
if (self.lisenter) {
self.lisenter(self.remote);
}
self.emit('connect', self.remote);
});
// execute ready event handlers if they are set after online is true
this.on('newListener', function (name, fn) {
if (name === 'connect' && self.online === true) {
fn(self.remote);
}
});
// setup message handler
var handler = new message.MessageHandler(this, handlers);
this.layer.setupHandle(handler);
};
// close the communication
Requester.prototype.close = function () {
if (this.online === false) {
this.emit('error', new Error("Requester is already closed"));
return;
}
this.layer.close();
};
// assing requester with an id and send all stored requests
handlers.setup = function (id, methods) {
var layer = this.communication;
// set the ID and online
layer.assignID = id;
// setup all request functions
var remote = this.root.remote = new RemoteWrapper(this.ipc, methods);
// this will set online in remote
this.callback();
// emit connect
this.communication.emit('connect', remote);
};
/**
* RemoteWrapper
*/
function RemoteWrapper(ipc, methods) {
function requestWrapper(name) {
return function () {
request(ipc, name, helpers.toArray(arguments));
};
}
var i = methods.length;
while (i--) {
this[methods[i]] = requestWrapper(methods[i]);
}
}
// request a method from the listener
function request(ipc, name, args) {
// check online
if (!ipc.root.online) {
ipc.root.emit('error', new Error("Could not make a request, channel is offline"));
return;
}
// store callback for later
var callback = args.pop();
// check that a callback is set
if (typeof callback !== 'function') {
ipc.root.emit('error', new TypeError("No callback specified"));
return;
}
// send request to remote
ipc.send('call', [name, args], function (sucess, content) {
if (sucess) {
callback.apply({
error: null
}, content);
} else {
callback.apply({
error: helpers.object2error(content)
}, []);
}
});
}
})();