-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJSON-RPC.js
More file actions
158 lines (153 loc) · 4.86 KB
/
JSON-RPC.js
File metadata and controls
158 lines (153 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*!
* JSON-RPC
* Copyright(c) 2010-2013 Georgi Kostov <p_e_a@gbg.bg>, http://performancehorizon.com
* https://github.com/PerformanceHorizonGroup/simple-json-rpc
* MIT Licensed
*/
(function (global){
( ((typeof module !== 'undefined' && module.exports) ? module.exports : global).RPC = function (cfg){
this.remoteMethods={};
this.callbacks={};
this.cbIds=0;
if(cfg){
/**
* @cfg {Object} targetObj (optional) The object which the RPC interface (exported and remote methods) will be modeled on.
*/
if(cfg.targetObj){
this.targetObj=cfg.targetObj;
delete cfg.targetObj;
}else
this.targetObj={};
this.targetObj.RPC=this;
/**
* @cfg {Function} (optional) sendRPCMessage A function to call when a message needs to be sent.
* If not ptovided the object will not be able to send messages but that does not prevent it from accepting messages and
* executing the calls they request (but will not be able to respond of course).
*/
if(cfg.sendRPCMessage){
this.sendRPCMessage=cfg.sendRPCMessage;
delete cfg.sendRPCMessage;
}else
this.sendRPCMessage=function (){};
/**
* @cfg {Object} ownMethods (optional) A hash with functions keyed by names which the object needs to export.
*/
if(cfg.ownMethods){
for(var p in cfg.ownMethods)
this.targetObj[p]=cfg.ownMethods[p];
delete cfg.ownMethods;
}
/**
* @cfg {String/Array} remoteMethods (optional) A name or an array of names of methods that the remote party provides.
*/
if(cfg.remoteMethods){
this.addRemoteMethods(cfg.remoteMethods);
delete cfg.remoteMethods;
}
// copy other properties from the configuration
for(var p in cfg)
this[p]=cfg[p];
}
// return this.targetObj;
} ).prototype={
/**
* @method onRPCMessage
* @param {Object} msg The RPC message that the object needs to process
*/
onRPCMessage:function (msg){
if('name' in msg){
var fn=null,
scope=null;
if(msg.name=='getExportedRPCMethods'){
fn=this.getExportedRPCMethods;
scope=this;
}else if(msg.name in this.targetObj)
fn=this.targetObj[msg.name];
else if(msg.name in this.callbacks){
fn=this.callbacks[msg.name];
delete this.callbacks[msg.name];
}
if(fn){
var args=msg.args,
obj=this;
if(msg.cbId) // if there's a cb setup for the call
args.push(function (){
obj.callRemoteMethod(msg.cbId, arguments);
});
fn.apply(scope||this.targetObj, args);
}
}
},
/**
* @method getExportedRPCMethods
* Returns all methods that this object implements and exports to be called remotely.
* @param {Function} cb (optional) A callback to use to send the result
* @return {Array} The list of own methods that the object exports.
*/
getExportedRPCMethods:function (cb){
var list=[];
for(var p in this.targetObj)
if(this.targetObj[p] && typeof this.targetObj[p]=='function' && !(p in this.remoteMethods))
list.push(p);
if(cb)
cb(null, list);
return list; // return in case this is not RPC call
},
/**
* @method callRemoteMethod
* Prepares and sends the RPC message to call the remote method.
* @param {String} name Remote method's name
* @param {Array} args (optional) A list of arguments for the call.
*/
callRemoteMethod:function (name, args){
var cb=null,
cbId=null;
args = args ? [].slice.call(args, 0) : []; // .slice() it in case it's and arguments object
// look for last parameter of type "function" and use it as a callback
if(args.length && typeof args[args.length-1]=='function')
cb=args.pop();
if(cb){
// set cbId so the other side knows to provide a callback to the invoked method
cbId='cb'+this.cbIds++;
this.callbacks[cbId]=cb;
}
this.sendRPCMessage({
name:name,
args:args,
cbId:cbId
});
},
/**
* @method retrieveRemoteMethods
* When called the object will call the other side asking for its list of exported methods and will
* update the local remote methods hash.
* @param {Function} cb (optional) A callback to also be given the list of remote methods.
*/
retrieveRemoteMethods:function (cb){
var obj=this;
this.callRemoteMethod('getExportedRPCMethods', [function (err, list){
if(!err){
obj.remoteMethods={};
obj.addRemoteMethods(list);
}
if(cb)
cb(err, list);
}]);
},
/**
* @method addRemoteMethods
* Adds a name or an array of names of methods to the local remote methods hash.
* @param {String/Array} methods A name or an array of names of remote methods.
*/
addRemoteMethods:function (methods){
if(typeof methods=='string'){
(this.targetObj)[methods]=
this.remoteMethods[methods]=function (){
this.RPC.callRemoteMethod(methods, arguments);
};
}else
for(var i=0; i<methods.length; i++)
this.addRemoteMethods(methods[i]);
}
};
}(function() {return this;}()));