@capturebridge/sdk 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Plugin.js CHANGED
@@ -1,298 +1,298 @@
1
- import Device from './Device.js'
2
-
3
- import { BASE_URL, DELETE, asyncToCallback } from './Common.js'
4
-
5
- /**
6
- * @classdesc CaptureBridge utilizes a plugin system for interacting with
7
- * hardware devices and vendor SDKs. Clients will interact with plugins via the
8
- * REST API using their unique plugin ID. This class provides basic methods
9
- * for working with these plugins such as obtaining a list of compatible devices
10
- * and managing the plugin's configuration.
11
- *
12
- * @see {@link CaptureBridge#plugins} Get all installed plugin.
13
- * @see {@link CaptureBridge#plugin} Get a single plugin by ID.
14
- */
15
- class Plugin {
16
- /**
17
- * @property {string} id - ID of the plugin, used when building REST endpoint paths.
18
- * @property {string} name - Human friendly name for the plugin.
19
- * @property {string} description - Human friendly description of plugin.
20
- * @property {string} version - {@link https://semver.org/|Semantic version} version of the plugin.
21
- * @property {string[]} methods - A plugin's list of supported RPC methods.
22
- * @property {boolean} ready - True if plugin has been loaded into memory and is ready to receive requests.
23
- * @property {object} defaultDevice - Default device to use for the plugin.
24
- * @property {string[]} configMethods - Methods required to implement configuration.
25
- */
26
- baseUrl
27
- id
28
- name
29
- description
30
- version
31
- methods = []
32
- ready = false
33
- defaultDevice = null
34
- configMethods = ['config_schema', 'get_config', 'set_config']
35
-
36
- /**
37
- * Instantiate a plugin.
38
- * @constructor
39
- * @param {object|string} plugin - plugin object as received from the API or a plugin ID string.
40
- * @param {string} plugin.id - ID of the plugin, used when building endpoint paths to call methods on the plugin.
41
- * @param {string} plugin.name - Human friendly name of plugin.
42
- * @param {string} plugin.description - Human friendly description of plugin.
43
- * @param {string} plugin.version - {@link https://semver.org/|Semantic version} version of the plugin.
44
- * @param {string[]} plugin.methods - plugin's capabilities.
45
- * @param {boolean} plugin.ready - True if plugin has been loaded into memory and is ready.
46
- * @param {string} [baseURL=BASE_URL] - Override the default protocol, domain, and port for the service.
47
- * @throws Will throw an Error the plugin argument is not a plugin ID (String) or an object.
48
- */
49
- constructor (plugin, baseUrl = BASE_URL) {
50
- this.baseUrl = baseUrl
51
- if (typeof plugin === 'string') {
52
- this.id = plugin
53
- } else if (typeof plugin === 'object') {
54
- Object.assign(this, {}, plugin)
55
- } else {
56
- throw new Error('Invalid properties supplied to Plugin constructor')
57
- }
58
- }
59
-
60
- /**
61
- * Get all devices for this plugin
62
- *
63
- * @method
64
- * @async
65
- * @see {@link https://capture.local.valididcloud.com:9001/doc/#api-Plugin-GetPluginDevices|API Endpoint (/plugin/:pluginId/device)}
66
- * @returns {object[]} Array of {@link Device} objects.
67
- * @example
68
- * const plugin = await captureBridge.plugin('capture_camera_canon')
69
- * const devices = await plugin.devices()
70
- */
71
- async devices () {
72
- const response = await fetch(`${this.baseUrl}/plugin/${this.id}/device`)
73
- const devices = await response.json()
74
- return devices.map(d => new Device(d, this, this.baseUrl))
75
- }
76
-
77
- /**
78
- * Get all Devices for this plugin
79
- *
80
- * @method
81
- * @see {@link https://capture.local.valididcloud.com:9001/doc/#api-Plugin-GetPluginDevices|API Endpoint (/plugin/:pluginId/device)}
82
- * @param {function} callback - Invoked with two arguments. The first argument
83
- * is an Error object (if an error occurred) or null. The second argument is
84
- * an Array of {@link Device} objects. If no devices are available the second
85
- * argument will be an empty Array.
86
- * @example
87
- * captureBridge.pluginHandler('capture_camera_canon', (error, plugin) => {
88
- * plugin.devicesHandler((error, devices) => console.log(devices))
89
- * })
90
- */
91
- devicesHandler (callback) {
92
- asyncToCallback(this, this.devices, callback)
93
- }
94
-
95
- /**
96
- * Get a device by ID for this plugin
97
- *
98
- * @method
99
- * @async
100
- * @see {@link https://capture.local.valididcloud.com:9001/doc/#api-Plugin-GetPluginDevices|API Endpoint (/plugin/:pluginId/device)}
101
- * @param {string} id - Device ID
102
- * @returns {object?} Requested {@link Device} or null
103
- * @example
104
- * const plugin = await captureBridge.plugin('capture_camera_canon')
105
- * const device = await plugin.device('AWOOO56709')
106
- */
107
- async device (id) {
108
- const response = await fetch(`${this.baseUrl}/plugin/${this.id}/device`)
109
- const devices = await response.json()
110
- const device = devices.find(d => d.id === id)
111
- return device ? new Device(device, this, this.baseUrl) : null
112
- }
113
-
114
- /**
115
- * Get a Device by ID for this plugin
116
- * @method
117
- * @see {@link https://capture.local.valididcloud.com:9001/doc/#api-Plugin-GetPluginDevices|API Endpoint (/plugin/:pluginId/device)}
118
- * @param {string} id - Device ID
119
- * @param {function} callback - Invoked with two arguments. The first argument
120
- * is an Error object (if an error occurred) or null. The second argument is
121
- * a {@link Device} object. If the requested device is not available the
122
- * second argument will be null.
123
- * @example
124
- * captureBridge.pluginHandler('capture_camera_canon', (error, plugin) => {
125
- * plugin.deviceHandler('AWOOO56709', (error, device) => console.log(device))
126
- * })
127
- */
128
- deviceHandler (id, callback) {
129
- asyncToCallback(this, this.device, callback, id)
130
- }
131
-
132
- async configSchema () {
133
- if (!await this.supportsConfig()) {
134
- throw new Error('Plugin does not support config')
135
- }
136
- const response = await fetch(`${this.baseUrl}/plugin/${this.id}/config/schema`)
137
- return await response.json()
138
- }
139
-
140
- configSchemaHandler (callback) {
141
- asyncToCallback(this, this.configSchema, callback)
142
- }
143
-
144
- async config () {
145
- if (!await this.supportsConfig()) {
146
- throw new Error('Plugin does not support config')
147
- }
148
- const response = await fetch(`${this.baseUrl}/plugin/${this.id}/config`)
149
- return await response.json()
150
- }
151
-
152
- configHandler (callback) {
153
- asyncToCallback(this, this.config, callback)
154
- }
155
-
156
- async saveConfig (config) {
157
- if (!await this.supportsConfig()) {
158
- throw new Error('Plugin does not support config')
159
- }
160
- const options = {
161
- method: 'POST',
162
- mode: 'cors',
163
- headers: {
164
- 'Content-Type': 'application/json'
165
- },
166
- body: JSON.stringify(config)
167
- }
168
- const url = `${this.baseUrl}/plugin/${this.id}/config`
169
- const response = await fetch(url, options)
170
- return await response.json()
171
- }
172
-
173
- async saveConfigHandler (config, callback) {
174
- asyncToCallback(this, this.saveConfig, callback, config)
175
- }
176
-
177
- async supportsConfig () {
178
- await this.update()
179
- return this.configMethods.every(m => this.methods.includes(m))
180
- }
181
-
182
- supportsConfigHandler (callback) {
183
- asyncToCallback(this, this.configHandler, callback)
184
- }
185
-
186
- async shutdown () {
187
- const url = `${this.baseUrl}/plugin/${this.id}`
188
- const response = await fetch(url, DELETE)
189
- return await response.json()
190
- }
191
-
192
- shutdownHandler (callback) {
193
- asyncToCallback(this, this.shutdown, callback)
194
- }
195
-
196
- async startup () {
197
- // See: ValidRD/wa_capture_bridge/issues/48
198
- // We need an explicit endpoint for this instead
199
- const devices = await this.devices()
200
- if (devices) {
201
- await this.update(true)
202
- return { status: 'starting' }
203
- }
204
- return { status: 'failed' }
205
- }
206
-
207
- startupHandler (callback) {
208
- asyncToCallback(this, this.startup, callback)
209
- }
210
-
211
- /**
212
- * This class can be instantiated from either a plugin ID or a full plugin
213
- * object from an API request.
214
- * Because constructors cannot be async we use this method to hydrate the
215
- * plugin properties if needed.
216
- *
217
- * @private
218
- * @method
219
- */
220
- async update (force = false) {
221
- if (force || this.methods.length === 0) {
222
- const response = await fetch(`${this.baseUrl}/plugin`)
223
- const plugins = await response.json()
224
- const plugin = plugins.find(p => p.id === this.id)
225
- Object.assign(this, plugin)
226
- }
227
- }
228
-
229
- updateHandler (force = false, callback) {
230
- asyncToCallback(this, this.update, callback, force)
231
- }
232
-
233
- async rpc (request) {
234
- const options = {
235
- method: 'POST',
236
- mode: 'cors',
237
- headers: {
238
- 'Content-Type': 'application/json'
239
- },
240
- body: JSON.stringify(request)
241
- }
242
- const url = `${this.baseUrl}/plugin/${this.id}/rpc`
243
- const response = await fetch(url, options)
244
- return await response.json()
245
- }
246
-
247
- rpcHandler (request, callback) {
248
- asyncToCallback(this, this.rpc, callback, request)
249
- }
250
-
251
- async ping () {
252
- const response = await fetch(`${this.baseUrl}/plugin/${this.id}/ping`)
253
- return await response.json()
254
- }
255
-
256
- pingHandler (callback) {
257
- asyncToCallback(this, this.ping, callback)
258
- }
259
-
260
- /**
261
- * Classes that extend this one will add their own methods to perform
262
- * operations on a device. They will call this method first to get a device
263
- * object to use for making calls to the appropriate endpoint.
264
- *
265
- * This method really should be "protected" in classical OOP terms but
266
- * Javascript does not currently have support for such scopes, and it's not
267
- * marked using the ES6 private modifier so that it can be inherited by it's
268
- * children.
269
- * @private
270
- * @method
271
- */
272
- async setupDevice (deviceOpt) {
273
- await this.update()
274
-
275
- if (deviceOpt instanceof Device) {
276
- this.defaultDevice = deviceOpt
277
- return this.defaultDevice
278
- }
279
-
280
- if (typeof deviceOpt === 'string') {
281
- this.defaultDevice = this.device(deviceOpt)
282
- return this.defaultDevice
283
- }
284
-
285
- if (!this.defaultDevice) {
286
- const devices = await this.devices()
287
- if (!devices.length) {
288
- throw new Error('No devices found for the plugin')
289
- }
290
- this.defaultDevice = devices[0]
291
- return this.defaultDevice
292
- }
293
-
294
- return this.defaultDevice
295
- }
296
- }
297
-
298
- export default Plugin
1
+ import Device from './Device.js'
2
+
3
+ import { BASE_URL, DELETE, asyncToCallback } from './Common.js'
4
+
5
+ /**
6
+ * @classdesc CaptureBridge utilizes a plugin system for interacting with
7
+ * hardware devices and vendor SDKs. Clients will interact with plugins via the
8
+ * REST API using their unique plugin ID. This class provides basic methods
9
+ * for working with these plugins such as obtaining a list of compatible devices
10
+ * and managing the plugin's configuration.
11
+ *
12
+ * @see {@link CaptureBridge#plugins} Get all installed plugin.
13
+ * @see {@link CaptureBridge#plugin} Get a single plugin by ID.
14
+ */
15
+ class Plugin {
16
+ /**
17
+ * @property {string} id - ID of the plugin, used when building REST endpoint paths.
18
+ * @property {string} name - Human friendly name for the plugin.
19
+ * @property {string} description - Human friendly description of plugin.
20
+ * @property {string} version - {@link https://semver.org/|Semantic version} version of the plugin.
21
+ * @property {string[]} methods - A plugin's list of supported RPC methods.
22
+ * @property {boolean} ready - True if plugin has been loaded into memory and is ready to receive requests.
23
+ * @property {object} defaultDevice - Default device to use for the plugin.
24
+ * @property {string[]} configMethods - Methods required to implement configuration.
25
+ */
26
+ baseUrl
27
+ id
28
+ name
29
+ description
30
+ version
31
+ methods = []
32
+ ready = false
33
+ defaultDevice = null
34
+ configMethods = ['config_schema', 'get_config', 'set_config']
35
+
36
+ /**
37
+ * Instantiate a plugin.
38
+ * @constructor
39
+ * @param {object|string} plugin - plugin object as received from the API or a plugin ID string.
40
+ * @param {string} plugin.id - ID of the plugin, used when building endpoint paths to call methods on the plugin.
41
+ * @param {string} plugin.name - Human friendly name of plugin.
42
+ * @param {string} plugin.description - Human friendly description of plugin.
43
+ * @param {string} plugin.version - {@link https://semver.org/|Semantic version} version of the plugin.
44
+ * @param {string[]} plugin.methods - plugin's capabilities.
45
+ * @param {boolean} plugin.ready - True if plugin has been loaded into memory and is ready.
46
+ * @param {string} [baseURL=BASE_URL] - Override the default protocol, domain, and port for the service.
47
+ * @throws Will throw an Error the plugin argument is not a plugin ID (String) or an object.
48
+ */
49
+ constructor (plugin, baseUrl = BASE_URL) {
50
+ this.baseUrl = baseUrl
51
+ if (typeof plugin === 'string') {
52
+ this.id = plugin
53
+ } else if (typeof plugin === 'object') {
54
+ Object.assign(this, {}, plugin)
55
+ } else {
56
+ throw new Error('Invalid properties supplied to Plugin constructor')
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Get all devices for this plugin
62
+ *
63
+ * @method
64
+ * @async
65
+ * @see {@link https://capture.local.valididcloud.com:9001/doc/#api-Plugin-GetPluginDevices|API Endpoint (/plugin/:pluginId/device)}
66
+ * @returns {object[]} Array of {@link Device} objects.
67
+ * @example
68
+ * const plugin = await captureBridge.plugin('capture_camera_canon')
69
+ * const devices = await plugin.devices()
70
+ */
71
+ async devices () {
72
+ const response = await fetch(`${this.baseUrl}/plugin/${this.id}/device`)
73
+ const devices = await response.json()
74
+ return devices.map(d => new Device(d, this, this.baseUrl))
75
+ }
76
+
77
+ /**
78
+ * Get all Devices for this plugin
79
+ *
80
+ * @method
81
+ * @see {@link https://capture.local.valididcloud.com:9001/doc/#api-Plugin-GetPluginDevices|API Endpoint (/plugin/:pluginId/device)}
82
+ * @param {function} callback - Invoked with two arguments. The first argument
83
+ * is an Error object (if an error occurred) or null. The second argument is
84
+ * an Array of {@link Device} objects. If no devices are available the second
85
+ * argument will be an empty Array.
86
+ * @example
87
+ * captureBridge.pluginHandler('capture_camera_canon', (error, plugin) => {
88
+ * plugin.devicesHandler((error, devices) => console.log(devices))
89
+ * })
90
+ */
91
+ devicesHandler (callback) {
92
+ asyncToCallback(this, this.devices, callback)
93
+ }
94
+
95
+ /**
96
+ * Get a device by ID for this plugin
97
+ *
98
+ * @method
99
+ * @async
100
+ * @see {@link https://capture.local.valididcloud.com:9001/doc/#api-Plugin-GetPluginDevices|API Endpoint (/plugin/:pluginId/device)}
101
+ * @param {string} id - Device ID
102
+ * @returns {object?} Requested {@link Device} or null
103
+ * @example
104
+ * const plugin = await captureBridge.plugin('capture_camera_canon')
105
+ * const device = await plugin.device('AWOOO56709')
106
+ */
107
+ async device (id) {
108
+ const response = await fetch(`${this.baseUrl}/plugin/${this.id}/device`)
109
+ const devices = await response.json()
110
+ const device = devices.find(d => d.id === id)
111
+ return device ? new Device(device, this, this.baseUrl) : null
112
+ }
113
+
114
+ /**
115
+ * Get a Device by ID for this plugin
116
+ * @method
117
+ * @see {@link https://capture.local.valididcloud.com:9001/doc/#api-Plugin-GetPluginDevices|API Endpoint (/plugin/:pluginId/device)}
118
+ * @param {string} id - Device ID
119
+ * @param {function} callback - Invoked with two arguments. The first argument
120
+ * is an Error object (if an error occurred) or null. The second argument is
121
+ * a {@link Device} object. If the requested device is not available the
122
+ * second argument will be null.
123
+ * @example
124
+ * captureBridge.pluginHandler('capture_camera_canon', (error, plugin) => {
125
+ * plugin.deviceHandler('AWOOO56709', (error, device) => console.log(device))
126
+ * })
127
+ */
128
+ deviceHandler (id, callback) {
129
+ asyncToCallback(this, this.device, callback, id)
130
+ }
131
+
132
+ async configSchema () {
133
+ if (!await this.supportsConfig()) {
134
+ throw new Error('Plugin does not support config')
135
+ }
136
+ const response = await fetch(`${this.baseUrl}/plugin/${this.id}/config/schema`)
137
+ return await response.json()
138
+ }
139
+
140
+ configSchemaHandler (callback) {
141
+ asyncToCallback(this, this.configSchema, callback)
142
+ }
143
+
144
+ async config () {
145
+ if (!await this.supportsConfig()) {
146
+ throw new Error('Plugin does not support config')
147
+ }
148
+ const response = await fetch(`${this.baseUrl}/plugin/${this.id}/config`)
149
+ return await response.json()
150
+ }
151
+
152
+ configHandler (callback) {
153
+ asyncToCallback(this, this.config, callback)
154
+ }
155
+
156
+ async saveConfig (config) {
157
+ if (!await this.supportsConfig()) {
158
+ throw new Error('Plugin does not support config')
159
+ }
160
+ const options = {
161
+ method: 'POST',
162
+ mode: 'cors',
163
+ headers: {
164
+ 'Content-Type': 'application/json'
165
+ },
166
+ body: JSON.stringify(config)
167
+ }
168
+ const url = `${this.baseUrl}/plugin/${this.id}/config`
169
+ const response = await fetch(url, options)
170
+ return await response.json()
171
+ }
172
+
173
+ async saveConfigHandler (config, callback) {
174
+ asyncToCallback(this, this.saveConfig, callback, config)
175
+ }
176
+
177
+ async supportsConfig () {
178
+ await this.update()
179
+ return this.configMethods.every(m => this.methods.includes(m))
180
+ }
181
+
182
+ supportsConfigHandler (callback) {
183
+ asyncToCallback(this, this.configHandler, callback)
184
+ }
185
+
186
+ async shutdown () {
187
+ const url = `${this.baseUrl}/plugin/${this.id}`
188
+ const response = await fetch(url, DELETE)
189
+ return await response.json()
190
+ }
191
+
192
+ shutdownHandler (callback) {
193
+ asyncToCallback(this, this.shutdown, callback)
194
+ }
195
+
196
+ async startup () {
197
+ // See: ValidRD/wa_capture_bridge/issues/48
198
+ // We need an explicit endpoint for this instead
199
+ const devices = await this.devices()
200
+ if (devices) {
201
+ await this.update(true)
202
+ return { status: 'starting' }
203
+ }
204
+ return { status: 'failed' }
205
+ }
206
+
207
+ startupHandler (callback) {
208
+ asyncToCallback(this, this.startup, callback)
209
+ }
210
+
211
+ /**
212
+ * This class can be instantiated from either a plugin ID or a full plugin
213
+ * object from an API request.
214
+ * Because constructors cannot be async we use this method to hydrate the
215
+ * plugin properties if needed.
216
+ *
217
+ * @private
218
+ * @method
219
+ */
220
+ async update (force = false) {
221
+ if (force || this.methods.length === 0) {
222
+ const response = await fetch(`${this.baseUrl}/plugin`)
223
+ const plugins = await response.json()
224
+ const plugin = plugins.find(p => p.id === this.id)
225
+ Object.assign(this, plugin)
226
+ }
227
+ }
228
+
229
+ updateHandler (force = false, callback) {
230
+ asyncToCallback(this, this.update, callback, force)
231
+ }
232
+
233
+ async rpc (request) {
234
+ const options = {
235
+ method: 'POST',
236
+ mode: 'cors',
237
+ headers: {
238
+ 'Content-Type': 'application/json'
239
+ },
240
+ body: JSON.stringify(request)
241
+ }
242
+ const url = `${this.baseUrl}/plugin/${this.id}/rpc`
243
+ const response = await fetch(url, options)
244
+ return await response.json()
245
+ }
246
+
247
+ rpcHandler (request, callback) {
248
+ asyncToCallback(this, this.rpc, callback, request)
249
+ }
250
+
251
+ async ping () {
252
+ const response = await fetch(`${this.baseUrl}/plugin/${this.id}/ping`)
253
+ return await response.json()
254
+ }
255
+
256
+ pingHandler (callback) {
257
+ asyncToCallback(this, this.ping, callback)
258
+ }
259
+
260
+ /**
261
+ * Classes that extend this one will add their own methods to perform
262
+ * operations on a device. They will call this method first to get a device
263
+ * object to use for making calls to the appropriate endpoint.
264
+ *
265
+ * This method really should be "protected" in classical OOP terms but
266
+ * Javascript does not currently have support for such scopes, and it's not
267
+ * marked using the ES6 private modifier so that it can be inherited by it's
268
+ * children.
269
+ * @private
270
+ * @method
271
+ */
272
+ async setupDevice (deviceOpt) {
273
+ await this.update()
274
+
275
+ if (deviceOpt instanceof Device) {
276
+ this.defaultDevice = deviceOpt
277
+ return this.defaultDevice
278
+ }
279
+
280
+ if (typeof deviceOpt === 'string') {
281
+ this.defaultDevice = this.device(deviceOpt)
282
+ return this.defaultDevice
283
+ }
284
+
285
+ if (!this.defaultDevice) {
286
+ const devices = await this.devices()
287
+ if (!devices.length) {
288
+ throw new Error('No devices found for the plugin')
289
+ }
290
+ this.defaultDevice = devices[0]
291
+ return this.defaultDevice
292
+ }
293
+
294
+ return this.defaultDevice
295
+ }
296
+ }
297
+
298
+ export default Plugin