-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathisc.js
More file actions
96 lines (92 loc) · 3.3 KB
/
Copy pathisc.js
File metadata and controls
96 lines (92 loc) · 3.3 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
// Inter-service Communication
const {WebSocketServer} = require('ws');
const {WebSocketHandle} = require('./wshandle.js');
const {wait} = require('./util/concurrent.js');
const {generateId} = require('./util/util.js');
const log = require('./util/logger.js')('isc');
const E = module.exports;
const MessageType = {
CONNECT: 'connect',
ERROR: 'error',
FN_CALL: 'fn_call',
FN_RESULT: 'fn_result',
FN_ERROR: 'fn_error',
};
E.createServer = ({service, exports, port})=>{
const wss = new WebSocketServer({port});
log.notice(`Initialized service "${service}" on port ${port}`);
wss.on('connection', socket=>{
socket.on('message', async data=>{
const msg = JSON.parse(String(data));
if (msg.type==MessageType.FN_CALL) {
try {
const fn = exports[msg.fn];
if (!fn)
throw new Error(`Unknown function: ${msg.fn}`);
const args = msg.args || [];
const res = await fn.apply(null, args);
socket.send(JSON.stringify({
type: MessageType.FN_RESULT,
service,
fn: msg.fn,
args,
res,
id: msg.id,
}));
} catch (e) {
socket.send(JSON.stringify({
type: MessageType.FN_ERROR,
service,
error: e.message,
id: msg.id,
fn: msg.fn,
}));
}
}
});
socket.send(JSON.stringify({
type: 'connect',
service,
exports: Object.keys(exports),
}));
});
};
E.createClient = ({service, port})=>new Promise(resolve=>{
const activeCalls = {};
const ws = new WebSocketHandle({
url: `ws://localhost:${port}`,
persistent: true,
onMessage: msg=>{
if (msg.type==MessageType.CONNECT && !!msg.exports) {
const exports = msg.exports.reduce((acc, fn)=>({
...acc,
[fn]: async function() {
const args = [...arguments];
const w = wait();
const id = generateId({prefix: service+'_fn_call'});
activeCalls[id] = w;
ws.send({type: MessageType.FN_CALL, fn, id, args});
return w.promise;
},
}), {});
return resolve({...exports, _close: ()=>ws.close()});
}
if (msg.type==MessageType.FN_RESULT) {
const w = activeCalls[msg.id];
delete activeCalls[msg.id];
return w.resolve(msg.res);
}
if (msg.type==MessageType.FN_ERROR) {
const w = activeCalls[msg.id];
delete activeCalls[msg.id];
return w.reject(msg.error);
}
},
onError: err=>{
Object.keys(activeCalls).forEach(id=>{
activeCalls[id].reject(new Error('ISC Connection Error', err));
delete activeCalls[id];
});
},
});
});