-
Notifications
You must be signed in to change notification settings - Fork 13
/
remote-api.js
71 lines (63 loc) · 1.82 KB
/
remote-api.js
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
'use strict'
const clarify = require('clarify-error')
const u = require('./util')
/**
* Recursively traverse the `obj` according to the `manifest` shape,
* replacing all leafs with `remoteCall`. Returns the mutated `obj`.
*/
function recurse (obj, manifest, path, remoteCall) {
for (const name in manifest) {
const val = manifest[name]
const nestedPath = path ? path.concat(name) : [name]
if (val && typeof val === 'object') {
const nestedManifest = val
obj[name] = recurse({}, nestedManifest, nestedPath, remoteCall)
} else {
const type = val
obj[name] = (...args) => remoteCall(type, nestedPath, args)
}
}
return obj
}
function noop (err) {
if (err) throw clarify(err, 'callback not provided')
}
function createRemoteApi (obj, manifest, actualRemoteCall, bootstrapCB) {
obj = obj || {}
function remoteCall (type, name, args) {
const cb = typeof args[args.length - 1] === 'function'
? args.pop()
: type === 'sync' || type === 'async' // promise types
? null
: noop
if (typeof cb === 'function') {
let value
// Callback style
try {
value = actualRemoteCall(type, name, args, cb)
} catch (err) {
return u.errorAsStreamOrCb(type, err, cb)
}
return value
} else {
// Promise style
return new Promise((resolve, reject) => {
actualRemoteCall(type, name, args, (err, val) => {
if (err) reject(err)
else resolve(val)
})
})
}
}
if (bootstrapCB) {
remoteCall('async', 'manifest', [function (err, manifest) {
if (err) return bootstrapCB(err)
recurse(obj, manifest, null, remoteCall)
bootstrapCB(null, manifest, obj)
}])
} else {
recurse(obj, manifest, null, remoteCall)
}
return obj
}
module.exports = createRemoteApi