3 Create a document explaining the protocol
4 Some way to expire unused callbacks? TTL? expireCallback() function?
7 function WebsocketRpc(eio_socket
) {
11 this._rpc_callbacks
= {};
12 this._socket
= eio_socket
;
15 this._bindSocketListeners();
19 WebsocketRpc
.prototype._bindSocketListeners = function() {
22 // Proxy the onMessage listener
23 this._onMessageProxy
= function rpcOnMessageBoundFunction(){
24 self
._onMessage
.apply(self
, arguments
);
26 this._socket
.on('message', this._onMessageProxy
);
31 WebsocketRpc
.prototype.dispose = function() {
32 if (this._onMessageProxy
) {
33 this._socket
.removeListener('message', this._onMessageProxy
);
34 delete this._onMessageProxy
;
37 this.removeAllListeners();
44 * The engine.io socket already has an emitter mixin so steal it from there
46 WebsocketRpc
.prototype._mixinEmitter = function() {
47 var funcs
= ['on', 'once', 'off', 'removeListener', 'removeAllListeners', 'emit', 'listeners', 'hasListeners'];
49 for (var i
=0; i
<funcs
.length
; i
++) {
50 if (typeof this._socket
[funcs
[i
]] === 'function')
51 this[funcs
[i
]] = this._socket
[funcs
[i
]];
57 * Check if a packet is a valid RPC call
59 WebsocketRpc
.prototype._isCall = function(packet
) {
60 return (typeof packet
.method
!== 'undefined' &&
61 typeof packet
.params
!== 'undefined');
66 * Check if a packet is a valid RPC response
68 WebsocketRpc
.prototype._isResponse = function(packet
) {
69 return (typeof packet
.id
!== 'undefined' &&
70 typeof packet
.response
!== 'undefined');
77 * First argument must be the method name to call
78 * If the last argument is a function, it is used as a callback
79 * All other arguments are passed to the RPC method
80 * Eg. Rpc.call('namespace.method_name', 1, 2, 3, callbackFn)
82 WebsocketRpc
.prototype.call = function(method
) {
83 var params
, callback
, packet
;
85 // Get a normal array of passed in arguments
86 params
= Array
.prototype.slice
.call(arguments
, 1, arguments
.length
);
88 // If the last argument is a function, take it as a callback and strip it out
89 if (typeof params
[params
.length
-1] === 'function') {
90 callback
= params
[params
.length
-1];
91 params
= params
.slice(0, params
.length
-1);
99 if (typeof callback
=== 'function') {
100 packet
.id
= this._next_id
;
103 this._rpc_callbacks
[packet
.id
] = callback
;
111 * Encode the packet into JSON and send it over the websocket
113 WebsocketRpc
.prototype.send = function(packet
) {
115 this._socket
.send(JSON
.stringify(packet
));
120 * Handler for the websocket `message` event
122 WebsocketRpc
.prototype._onMessage = function(message_raw
) {
129 packet
= JSON
.parse(message_raw
);
130 if (!packet
) throw 'Corrupt packet';
135 if (this._isResponse(packet
)) {
136 // If we have no callback waiting for this response, don't do anything
137 if (typeof this._rpc_callbacks
[packet
.id
] !== 'function')
140 // Delete the callback before calling it. If any exceptions accur within the callback
141 // we don't have to worry about the delete not happening
142 callback
= this._rpc_callbacks
[packet
.id
];
143 delete this._rpc_callbacks
[packet
.id
];
145 callback
.apply(this, packet
.response
);
147 } else if (this._isCall(packet
)) {
148 // Calls with an ID may be responded to
149 if (typeof packet
.id
!== 'undefined') {
150 returnFn
= this._createReturnCallFn(packet
.id
);
152 returnFn
= this._noop
;
155 this.emit
.apply(this, [packet
.method
, returnFn
].concat(packet
.params
));
161 * Returns a function used as a callback when responding to a call
163 WebsocketRpc
.prototype._createReturnCallFn = function(packet_id
) {
166 return function returnCallFn() {
167 var value
= Array
.prototype.slice
.call(arguments
, 0);
174 self
.send(ret_packet
);
180 WebsocketRpc
.prototype._noop = function() {};
185 // If running a node module, set the exports
186 if (typeof module
=== 'object' && typeof module
.exports
!== 'undefined') {
187 module
.exports
= WebsocketRpc
;