-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
95 lines (80 loc) · 2.83 KB
/
index.js
File metadata and controls
95 lines (80 loc) · 2.83 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
//////////////////////////////////////////////////////////////////////
//
// Remote
//
// A little class for messaging with sockets.
//
// Copyright © 2020 Aral Balkan, Small Technology Foundation.
// License: ISC.
//
//////////////////////////////////////////////////////////////////////
const keyd = require('keyd')
const { v4: uuid } = require('uuid')
class Remote {
constructor (socket) {
this.socket = socket
this.keyPath = ''
socket.addEventListener ('message', event => {
// Call the correct handler based on the event type key path.
const message = JSON.parse(event.data)
const handler = keyd(this).get(`${message.type}.handler`)
if (typeof handler === 'function') {
handler(message)
}
})
const handler = {
get: (self, keyPath) => {
if (self[keyPath] === undefined) {
// The key doesn’t exist. If this is a request,
// fire it off. If not, create the key.
if (keyPath === 'send') {
return (message = {}) => {
this.socket.send(JSON.stringify(Object.assign({
type: self.keyPath
}, message)))
}
}
// These two methods are used for RPC-style request/response
// messages that you can await.
if (keyPath === 'respond') {
return (originalMessage, response = {}) => {
this.socket.send(JSON.stringify(Object.assign({
type: self.keyPath,
__id: originalMessage.__id
}, response)))
}
}
if (keyPath === 'await') {
return async (message = {}, timeout = 10000 /* 10 seconds */) => {
const __id = uuid()
this.socket.send(JSON.stringify(Object.assign({
type: self.keyPath,
__id
}, message)))
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
this.socket.removeEventListener('message', listener)
reject(new Error('Request timed out'))
}, timeout)
const listener = (event => {
const message = JSON.parse(event.data)
if (message.__id === __id) {
clearInterval(timeoutId)
this.socket.removeEventListener('message', listener)
resolve(message)
}
}).bind(this)
this.socket.addEventListener('message', listener)
})
}
}
self[keyPath] = {}
self[keyPath].keyPath = self.keyPath === '' ? keyPath : `${self.keyPath}.${keyPath}`
}
return new Proxy(self[keyPath], handler)
}
}
return new Proxy(this, handler)
}
}
module.exports = Remote