Skip to content

Commit 04e865f

Browse files
authored
Merge pull request #15 from iceddev/configurable-methods
optional method execution configation
2 parents c1e977d + 80245a4 commit 04e865f

File tree

6 files changed

+160
-59
lines changed

6 files changed

+160
-59
lines changed

README.md

+22
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,25 @@ transport.send({jsonrpc:'2.0', id: 1, method: 'subtract', params: [5, 4]});
114114
```
115115

116116
While, websockets, mqtt, and webworkers are common, transports could be built from any form of communication you wish!
117+
118+
119+
## Custom Configuration for Method invocations
120+
121+
if you need to pass configuration specific method invocations, you can uses the `methodsExt` property of a rawr instance.
122+
123+
For example, if you want to specify a specific timeout for a method call you can use a configuration object as the last parameter:
124+
```javascript
125+
try {
126+
const result = await peer.methodsExt.doSomething(a, b, { timeout: 100 });
127+
} catch(e) {
128+
// method took longer than a 100 millseconds
129+
}
130+
```
131+
132+
This also works for customizaton of the transport.
133+
For example, you may want to pass configuration for transferable objects to a webWorker:
134+
```javascript
135+
const result = await peer.methodsExt.processImage({ imageBitmap, stuff }, {
136+
postMessageOptions: { transfer: [imageBitmap] }
137+
});
138+
```

dist/bundle.js

+50-29
Original file line numberDiff line numberDiff line change
@@ -66,40 +66,60 @@ function rawr({ transport, timeout = 0, handlers = {}, methods, idGenerator }) {
6666
addHandler(m, methods[m]);
6767
});
6868

69-
const methodsProxy = new Proxy({}, {
70-
get: (target, name) => {
71-
return (...args) => {
72-
const id = idGenerator ? idGenerator() : ++callId;
73-
const msg = {
74-
jsonrpc: '2.0',
75-
method: name,
76-
params: args,
77-
id
78-
};
69+
function sendMessage(method, params, config) {
70+
const id = idGenerator ? idGenerator() : ++callId;
71+
const msg = {
72+
jsonrpc: '2.0',
73+
method,
74+
params,
75+
id
76+
};
7977

80-
let timeoutId;
81-
if (timeout) {
82-
timeoutId = setTimeout(() => {
83-
if (pendingCalls[id]) {
84-
const err = new Error('RPC timeout');
85-
err.code = 504;
86-
pendingCalls[id].reject(err);
87-
delete pendingCalls[id];
88-
}
89-
}, timeout);
78+
let timeoutId;
79+
if (config.timeout || timeout) {
80+
timeoutId = setTimeout(() => {
81+
if (pendingCalls[id]) {
82+
const err = new Error('RPC timeout');
83+
err.code = 504;
84+
pendingCalls[id].reject(err);
85+
delete pendingCalls[id];
9086
}
87+
}, config.timeout || timeout);
88+
}
9189

92-
const response = new Promise((resolve, reject) => {
93-
pendingCalls[id] = { resolve, reject, timeoutId };
94-
});
90+
const response = new Promise((resolve, reject) => {
91+
pendingCalls[id] = { resolve, reject, timeoutId };
92+
});
9593

96-
transport.send(msg);
94+
transport.send(msg, config);
9795

98-
return response;
96+
return response;
97+
}
98+
99+
const methodsProxy = new Proxy({}, {
100+
get: (target, name) => {
101+
return (...args) => {
102+
return sendMessage(name, args, {});
99103
};
100104
}
101105
});
102106

107+
const configurableMethodsProxy = new Proxy({}, {
108+
get: (target, name) => {
109+
return (...args) => {
110+
let config;
111+
if (args.length) {
112+
const testArg = args.pop();
113+
if (testArg && typeof testArg === 'object' && !Array.isArray(testArg)) {
114+
config = testArg;
115+
}
116+
}
117+
return sendMessage(name, args, config || {});
118+
};
119+
}
120+
});
121+
122+
103123
const notifiers = new Proxy({}, {
104124
get: (target, name) => {
105125
return (...args) => {
@@ -125,6 +145,7 @@ function rawr({ transport, timeout = 0, handlers = {}, methods, idGenerator }) {
125145

126146
return {
127147
methods: methodsProxy,
148+
methodsExt: configurableMethodsProxy,
128149
addHandler,
129150
notifications,
130151
notifiers,
@@ -759,8 +780,8 @@ function dom(webWorker) {
759780
emitter.emit('rpc', data);
760781
}
761782
});
762-
emitter.send = (msg) => {
763-
webWorker.postMessage(msg);
783+
emitter.send = (msg, config) => {
784+
webWorker.postMessage(msg, config ? config.postMessageOptions : undefined);
764785
};
765786
return emitter;
766787
}
@@ -773,8 +794,8 @@ function worker() {
773794
emitter.emit('rpc', data);
774795
}
775796
};
776-
emitter.send = (msg) => {
777-
self.postMessage(msg);
797+
emitter.send = (msg, config) => {
798+
self.postMessage(msg, config ? config.postMessageOptions : undefined);
778799
};
779800
return emitter;
780801
}

index.js

+46-25
Original file line numberDiff line numberDiff line change
@@ -65,40 +65,60 @@ function rawr({ transport, timeout = 0, handlers = {}, methods, idGenerator }) {
6565
addHandler(m, methods[m]);
6666
});
6767

68-
const methodsProxy = new Proxy({}, {
69-
get: (target, name) => {
70-
return (...args) => {
71-
const id = idGenerator ? idGenerator() : ++callId;
72-
const msg = {
73-
jsonrpc: '2.0',
74-
method: name,
75-
params: args,
76-
id
77-
};
68+
function sendMessage(method, params, config) {
69+
const id = idGenerator ? idGenerator() : ++callId;
70+
const msg = {
71+
jsonrpc: '2.0',
72+
method,
73+
params,
74+
id
75+
};
7876

79-
let timeoutId;
80-
if (timeout) {
81-
timeoutId = setTimeout(() => {
82-
if (pendingCalls[id]) {
83-
const err = new Error('RPC timeout');
84-
err.code = 504;
85-
pendingCalls[id].reject(err);
86-
delete pendingCalls[id];
87-
}
88-
}, timeout);
77+
let timeoutId;
78+
if (config.timeout || timeout) {
79+
timeoutId = setTimeout(() => {
80+
if (pendingCalls[id]) {
81+
const err = new Error('RPC timeout');
82+
err.code = 504;
83+
pendingCalls[id].reject(err);
84+
delete pendingCalls[id];
8985
}
86+
}, config.timeout || timeout);
87+
}
9088

91-
const response = new Promise((resolve, reject) => {
92-
pendingCalls[id] = { resolve, reject, timeoutId };
93-
});
89+
const response = new Promise((resolve, reject) => {
90+
pendingCalls[id] = { resolve, reject, timeoutId };
91+
});
9492

95-
transport.send(msg);
93+
transport.send(msg, config);
94+
95+
return response;
96+
}
9697

97-
return response;
98+
const methodsProxy = new Proxy({}, {
99+
get: (target, name) => {
100+
return (...args) => {
101+
return sendMessage(name, args, {});
102+
};
103+
}
104+
});
105+
106+
const configurableMethodsProxy = new Proxy({}, {
107+
get: (target, name) => {
108+
return (...args) => {
109+
let config;
110+
if (args.length) {
111+
const testArg = args.pop();
112+
if (testArg && typeof testArg === 'object' && !Array.isArray(testArg)) {
113+
config = testArg;
114+
}
115+
}
116+
return sendMessage(name, args, config || {});
98117
};
99118
}
100119
});
101120

121+
102122
const notifiers = new Proxy({}, {
103123
get: (target, name) => {
104124
return (...args) => {
@@ -124,6 +144,7 @@ function rawr({ transport, timeout = 0, handlers = {}, methods, idGenerator }) {
124144

125145
return {
126146
methods: methodsProxy,
147+
methodsExt: configurableMethodsProxy,
127148
addHandler,
128149
notifications,
129150
notifiers,

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rawr",
3-
"version": "0.15.1",
3+
"version": "0.16.0",
44
"description": "JSON-RPC over simple event emitters",
55
"dependencies": {},
66
"devDependencies": {

test/index.js

+37
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ function subtract(a, b) {
4848
return a - b;
4949
}
5050

51+
function slowFunction() {
52+
return new Promise((resolve) => {
53+
setTimeout(() => {
54+
resolve('slow');
55+
}, 300);
56+
});
57+
}
58+
59+
function hi() {
60+
return 'hi';
61+
}
62+
5163
describe('rawr', () => {
5264
it('should make a client', (done) => {
5365
const client = rawr({ transport: mockTransports().a });
@@ -126,4 +138,29 @@ describe('rawr', () => {
126138

127139
clientB.notifiers.doSomething('testing_notification');
128140
});
141+
142+
it('client should fail on a configured timeout', async () => {
143+
const { a, b } = mockTransports();
144+
const clientA = rawr({ transport: a, handlers: { slowFunction, hi } });
145+
const clientB = rawr({ transport: b, handlers: { slowFunction, add } });
146+
147+
const resultA = await clientA.methodsExt.slowFunction({ timeout: 1000 });
148+
resultA.should.equal('slow');
149+
const resultA2 = await clientA.methodsExt.add(1, 2, null);
150+
resultA2.should.equal(3);
151+
try {
152+
await clientB.methodsExt.slowFunction({ timeout: 100 });
153+
154+
} catch (error) {
155+
error.code.should.equal(504);
156+
}
157+
try {
158+
await clientB.methodsExt.slowFunction('useless param', { timeout: 100 });
159+
} catch (error) {
160+
error.code.should.equal(504);
161+
}
162+
const resultB2 = await clientB.methodsExt.hi();
163+
resultB2.should.equal('hi');
164+
165+
});
129166
});

transports/worker/index.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ function dom(webWorker) {
88
emitter.emit('rpc', data);
99
}
1010
});
11-
emitter.send = (msg) => {
12-
webWorker.postMessage(msg);
11+
emitter.send = (msg, config) => {
12+
webWorker.postMessage(msg, config ? config.postMessageOptions : undefined);
1313
};
1414
return emitter;
1515
}
@@ -22,8 +22,8 @@ function worker() {
2222
emitter.emit('rpc', data);
2323
}
2424
};
25-
emitter.send = (msg) => {
26-
self.postMessage(msg);
25+
emitter.send = (msg, config) => {
26+
self.postMessage(msg, config ? config.postMessageOptions : undefined);
2727
};
2828
return emitter;
2929
}

0 commit comments

Comments
 (0)