buttplug 3.2.2 → 4.0.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/.eslintrc.js +25 -25
- package/.jscsrc +2 -2
- package/.jshintrc +5 -5
- package/.prettierrc.json +3 -3
- package/.yarnrc.yml +5 -5
- package/CHANGELOG.md +591 -577
- package/LICENSE +27 -27
- package/README.md +105 -97
- package/dist/main/src/client/ButtplugBrowserWebsocketClientConnector.js +6 -9
- package/dist/main/src/client/ButtplugBrowserWebsocketClientConnector.js.map +1 -1
- package/dist/main/src/client/{Client.d.ts → ButtplugClient.d.ts} +3 -4
- package/dist/main/src/client/ButtplugClient.js +232 -0
- package/dist/main/src/client/ButtplugClient.js.map +1 -0
- package/dist/main/src/client/ButtplugClientConnectorException.js +17 -7
- package/dist/main/src/client/ButtplugClientConnectorException.js.map +1 -1
- package/dist/main/src/client/ButtplugClientDevice.d.ts +13 -28
- package/dist/main/src/client/ButtplugClientDevice.js +105 -247
- package/dist/main/src/client/ButtplugClientDevice.js.map +1 -1
- package/dist/main/src/client/ButtplugClientDeviceCommand.d.ts +42 -0
- package/dist/main/src/client/ButtplugClientDeviceCommand.js +105 -0
- package/dist/main/src/client/ButtplugClientDeviceCommand.js.map +1 -0
- package/dist/main/src/client/ButtplugClientDeviceFeature.d.ts +18 -0
- package/dist/main/src/client/ButtplugClientDeviceFeature.js +166 -0
- package/dist/main/src/client/ButtplugClientDeviceFeature.js.map +1 -0
- package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.d.ts +1 -8
- package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.js +1 -4
- package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.js.map +1 -1
- package/dist/main/src/core/Exceptions.js +27 -9
- package/dist/main/src/core/Exceptions.js.map +1 -1
- package/dist/main/src/core/Logging.js +12 -6
- package/dist/main/src/core/Logging.js.map +1 -1
- package/dist/main/src/core/Messages.d.ts +119 -230
- package/dist/main/src/core/Messages.js +50 -404
- package/dist/main/src/core/Messages.js.map +1 -1
- package/dist/main/src/index.d.ts +2 -2
- package/dist/main/src/index.js +4 -2
- package/dist/main/src/index.js.map +1 -1
- package/dist/main/src/utils/ButtplugBrowserWebsocketConnector.js +40 -52
- package/dist/main/src/utils/ButtplugBrowserWebsocketConnector.js.map +1 -1
- package/dist/main/src/utils/ButtplugMessageSorter.js +27 -15
- package/dist/main/src/utils/ButtplugMessageSorter.js.map +1 -1
- package/dist/main/src/utils/Utils.js +1 -2
- package/dist/main/src/utils/Utils.js.map +1 -1
- package/dist/web/buttplug.js +1 -38
- package/dist/web/buttplug.mjs +595 -1984
- package/dist/web/client/ButtplugBrowserWebsocketClientConnector.d.ts +0 -7
- package/dist/web/client/{Client.d.ts → ButtplugClient.d.ts} +3 -11
- package/dist/web/client/ButtplugClientConnectorException.d.ts +0 -7
- package/dist/web/client/ButtplugClientDevice.d.ts +14 -29
- package/dist/web/client/ButtplugClientDeviceCommand.d.ts +42 -0
- package/dist/web/client/ButtplugClientDeviceFeature.d.ts +18 -0
- package/dist/web/client/ButtplugNodeWebsocketClientConnector.d.ts +1 -15
- package/dist/web/client/IButtplugClientConnector.d.ts +0 -7
- package/dist/web/core/Exceptions.d.ts +1 -1
- package/dist/web/core/Logging.d.ts +0 -7
- package/dist/web/core/Messages.d.ts +119 -229
- package/dist/web/index.d.ts +2 -2
- package/dist/web/utils/ButtplugBrowserWebsocketConnector.d.ts +0 -7
- package/examples/node/SYNC_MANIFEST.md +105 -0
- package/examples/node/application-example.ts +213 -0
- package/examples/node/async-example.ts +124 -0
- package/examples/node/connection-example.ts +76 -0
- package/examples/node/device-control-example.ts +131 -0
- package/examples/node/device-enumeration-example.ts +86 -0
- package/examples/node/device-info-example.ts +131 -0
- package/examples/node/errors-example.ts +166 -0
- package/examples/node/package-lock.json +281 -0
- package/examples/node/package.json +25 -0
- package/examples/node/remote-connector-example.ts +84 -0
- package/examples/node/tsconfig.json +14 -0
- package/examples/web/application-example.js +197 -0
- package/examples/web/async-example.js +90 -0
- package/examples/web/device-control-example.js +87 -0
- package/examples/web/device-enumeration-example.js +49 -0
- package/examples/web/device-info-example.js +100 -0
- package/examples/web/errors-example.js +110 -0
- package/examples/web/index.html +55 -0
- package/examples/web/logging.js +42 -0
- package/examples/web/ping-timeout-example.js +59 -0
- package/examples/web/remote-connector-example.js +68 -0
- package/node-test.js +24 -0
- package/node-test.ts +23 -5
- package/package.json +85 -87
- package/src/client/ButtplugBrowserWebsocketClientConnector.ts +25 -25
- package/src/client/ButtplugClient.ts +242 -0
- package/src/client/ButtplugClientConnectorException.ts +16 -16
- package/src/client/ButtplugClientDevice.ts +178 -401
- package/src/client/ButtplugClientDeviceCommand.ts +112 -0
- package/src/client/ButtplugClientDeviceFeature.ts +138 -0
- package/src/client/ButtplugNodeWebsocketClientConnector.ts +17 -17
- package/src/client/IButtplugClientConnector.ts +18 -18
- package/src/core/Exceptions.ts +107 -101
- package/src/core/Logging.ts +197 -197
- package/src/core/Messages.ts +205 -480
- package/src/core/index.d.ts +4 -4
- package/src/index.ts +21 -19
- package/src/utils/ButtplugBrowserWebsocketConnector.ts +89 -89
- package/src/utils/ButtplugMessageSorter.ts +66 -65
- package/src/utils/Utils.ts +3 -3
- package/tsconfig.json +22 -22
- package/tsfmt.json +14 -14
- package/tslint.json +27 -27
- package/typedocconfig.js +6 -6
- package/vite.config.ts +26 -26
- package/dist/main/src/client/Client.js +0 -242
- package/dist/main/src/client/Client.js.map +0 -1
- package/dist/main/src/core/MessageUtils.d.ts +0 -10
- package/dist/main/src/core/MessageUtils.js +0 -65
- package/dist/main/src/core/MessageUtils.js.map +0 -1
- package/dist/web/core/MessageUtils.d.ts +0 -10
- package/doc/.nojekyll +0 -1
- package/doc/assets/highlight.css +0 -22
- package/doc/assets/main.js +0 -58
- package/doc/assets/search.js +0 -1
- package/doc/assets/style.css +0 -1280
- package/doc/classes/ButtplugBrowserWebsocketClientConnector.html +0 -234
- package/doc/classes/ButtplugClient.html +0 -331
- package/doc/classes/ButtplugClientConnectorException.html +0 -216
- package/doc/classes/ButtplugClientDevice.html +0 -489
- package/doc/classes/ButtplugDeviceError.html +0 -218
- package/doc/classes/ButtplugDeviceMessage.html +0 -165
- package/doc/classes/ButtplugError.html +0 -220
- package/doc/classes/ButtplugInitError.html +0 -218
- package/doc/classes/ButtplugLogger.html +0 -288
- package/doc/classes/ButtplugMessage.html +0 -147
- package/doc/classes/ButtplugMessageError.html +0 -218
- package/doc/classes/ButtplugMessageSorter.html +0 -128
- package/doc/classes/ButtplugNodeWebsocketClientConnector.html +0 -239
- package/doc/classes/ButtplugPingError.html +0 -218
- package/doc/classes/ButtplugSystemMessage.html +0 -150
- package/doc/classes/ButtplugUnknownError.html +0 -218
- package/doc/classes/DeviceAdded.html +0 -186
- package/doc/classes/DeviceInfo.html +0 -114
- package/doc/classes/DeviceList.html +0 -160
- package/doc/classes/DeviceRemoved.html +0 -158
- package/doc/classes/Error.html +0 -179
- package/doc/classes/GenericDeviceMessageAttributes.html +0 -107
- package/doc/classes/GenericMessageSubcommand.html +0 -90
- package/doc/classes/LinearCmd.html +0 -187
- package/doc/classes/LogMessage.html +0 -134
- package/doc/classes/MessageAttributes.html +0 -160
- package/doc/classes/Ok.html +0 -151
- package/doc/classes/Ping.html +0 -151
- package/doc/classes/RawDeviceMessageAttributes.html +0 -86
- package/doc/classes/RawReadCmd.html +0 -188
- package/doc/classes/RawReading.html +0 -179
- package/doc/classes/RawSubscribeCmd.html +0 -170
- package/doc/classes/RawUnsubscribeCmd.html +0 -170
- package/doc/classes/RawWriteCmd.html +0 -188
- package/doc/classes/RequestDeviceList.html +0 -151
- package/doc/classes/RequestServerInfo.html +0 -169
- package/doc/classes/RotateCmd.html +0 -187
- package/doc/classes/RotateSubcommand.html +0 -108
- package/doc/classes/ScalarCmd.html +0 -170
- package/doc/classes/ScalarSubcommand.html +0 -108
- package/doc/classes/ScanningFinished.html +0 -146
- package/doc/classes/SensorDeviceMessageAttributes.html +0 -107
- package/doc/classes/SensorReadCmd.html +0 -179
- package/doc/classes/SensorReading.html +0 -188
- package/doc/classes/ServerInfo.html +0 -178
- package/doc/classes/StartScanning.html +0 -151
- package/doc/classes/StopAllDevices.html +0 -151
- package/doc/classes/StopDeviceCmd.html +0 -161
- package/doc/classes/StopScanning.html +0 -151
- package/doc/classes/VectorSubcommand.html +0 -108
- package/doc/enums/ActuatorType.html +0 -104
- package/doc/enums/ButtplugLogLevel.html +0 -97
- package/doc/enums/ErrorClass.html +0 -90
- package/doc/enums/SensorType.html +0 -90
- package/doc/functions/FromJSON.html +0 -113
- package/doc/index.html +0 -184
- package/doc/interfaces/IButtplugClientConnector.html +0 -137
- package/doc/modules.html +0 -176
- package/doc/variables/DEFAULT_MESSAGE_ID.html +0 -104
- package/doc/variables/MAX_ID.html +0 -104
- package/doc/variables/MESSAGE_SPEC_VERSION.html +0 -104
- package/doc/variables/SYSTEM_MESSAGE_ID.html +0 -104
- package/src/client/Client.ts +0 -276
- package/src/core/MessageUtils.ts +0 -48
|
@@ -1,401 +1,178 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Buttplug JS Source Code File - Visit https://buttplug.io for more info about
|
|
3
|
-
* the project. Licensed under the BSD 3-Clause license. See LICENSE file in the
|
|
4
|
-
* project root for full license information.
|
|
5
|
-
*
|
|
6
|
-
* @copyright Copyright (c) Nonpolynomial Labs LLC. All rights reserved.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
'use strict';
|
|
10
|
-
import * as Messages from '../core/Messages';
|
|
11
|
-
import {
|
|
12
|
-
ButtplugDeviceError,
|
|
13
|
-
ButtplugError,
|
|
14
|
-
ButtplugMessageError,
|
|
15
|
-
} from '../core/Exceptions';
|
|
16
|
-
import { EventEmitter } from 'eventemitter3';
|
|
17
|
-
import {
|
|
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
|
-
_deviceInfo.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
await this.scalarCommandBuilder(speed, Messages.ActuatorType.Oscillate);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
public get rotateAttributes(): Messages.GenericDeviceMessageAttributes[] {
|
|
183
|
-
return this.messageAttributes.RotateCmd ?? [];
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
public async rotate(
|
|
187
|
-
values: number | [number, boolean][],
|
|
188
|
-
clockwise?: boolean
|
|
189
|
-
): Promise<void> {
|
|
190
|
-
const rotateAttrs = this.messageAttributes.RotateCmd;
|
|
191
|
-
if (!rotateAttrs || rotateAttrs.length === 0) {
|
|
192
|
-
throw new ButtplugDeviceError(
|
|
193
|
-
`Device ${this.name} has no Rotate capabilities`
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
let msg: Messages.RotateCmd;
|
|
197
|
-
if (typeof values === 'number') {
|
|
198
|
-
msg = Messages.RotateCmd.Create(
|
|
199
|
-
this.index,
|
|
200
|
-
new Array(rotateAttrs.length).fill([values, clockwise])
|
|
201
|
-
);
|
|
202
|
-
} else if (Array.isArray(values)) {
|
|
203
|
-
msg = Messages.RotateCmd.Create(this.index, values);
|
|
204
|
-
} else {
|
|
205
|
-
throw new ButtplugDeviceError(
|
|
206
|
-
'SendRotateCmd can only take a number and boolean, or an array of number/boolean tuples'
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
await this.sendExpectOk(msg);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
public get linearAttributes(): Messages.GenericDeviceMessageAttributes[] {
|
|
213
|
-
return this.messageAttributes.LinearCmd ?? [];
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
public async linear(
|
|
217
|
-
values: number | [number, number][],
|
|
218
|
-
duration?: number
|
|
219
|
-
): Promise<void> {
|
|
220
|
-
const linearAttrs = this.messageAttributes.LinearCmd;
|
|
221
|
-
if (!linearAttrs || linearAttrs.length === 0) {
|
|
222
|
-
throw new ButtplugDeviceError(
|
|
223
|
-
`Device ${this.name} has no Linear capabilities`
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
let msg: Messages.LinearCmd;
|
|
227
|
-
if (typeof values === 'number') {
|
|
228
|
-
msg = Messages.LinearCmd.Create(
|
|
229
|
-
this.index,
|
|
230
|
-
new Array(linearAttrs.length).fill([values, duration])
|
|
231
|
-
);
|
|
232
|
-
} else if (Array.isArray(values)) {
|
|
233
|
-
msg = Messages.LinearCmd.Create(this.index, values);
|
|
234
|
-
} else {
|
|
235
|
-
throw new ButtplugDeviceError(
|
|
236
|
-
'SendLinearCmd can only take a number and number, or an array of number/number tuples'
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
await this.sendExpectOk(msg);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
public async sensorRead(
|
|
243
|
-
sensorIndex: number,
|
|
244
|
-
sensorType: Messages.SensorType
|
|
245
|
-
): Promise<number[]> {
|
|
246
|
-
const response = await this.send(
|
|
247
|
-
new Messages.SensorReadCmd(this.index, sensorIndex, sensorType)
|
|
248
|
-
);
|
|
249
|
-
switch (getMessageClassFromMessage(response)) {
|
|
250
|
-
case Messages.SensorReading:
|
|
251
|
-
return (response as Messages.SensorReading).Data;
|
|
252
|
-
case Messages.Error:
|
|
253
|
-
throw ButtplugError.FromError(response as Messages.Error);
|
|
254
|
-
default:
|
|
255
|
-
throw new ButtplugMessageError(
|
|
256
|
-
`Message type ${response.constructor} not handled by sensorRead`
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
public get hasBattery(): boolean {
|
|
262
|
-
const batteryAttrs = this.messageAttributes.SensorReadCmd?.filter(
|
|
263
|
-
(x) => x.SensorType === Messages.SensorType.Battery
|
|
264
|
-
);
|
|
265
|
-
return batteryAttrs !== undefined && batteryAttrs.length > 0;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
public async battery(): Promise<number> {
|
|
269
|
-
if (!this.hasBattery) {
|
|
270
|
-
throw new ButtplugDeviceError(
|
|
271
|
-
`Device ${this.name} has no Battery capabilities`
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
const batteryAttrs = this.messageAttributes.SensorReadCmd?.filter(
|
|
275
|
-
(x) => x.SensorType === Messages.SensorType.Battery
|
|
276
|
-
);
|
|
277
|
-
// Find the battery sensor, we'll need its index.
|
|
278
|
-
const result = await this.sensorRead(
|
|
279
|
-
batteryAttrs![0].Index,
|
|
280
|
-
Messages.SensorType.Battery
|
|
281
|
-
);
|
|
282
|
-
return result[0] / 100.0;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
public get hasRssi(): boolean {
|
|
286
|
-
const rssiAttrs = this.messageAttributes.SensorReadCmd?.filter(
|
|
287
|
-
(x) => x.SensorType === Messages.SensorType.RSSI
|
|
288
|
-
);
|
|
289
|
-
return rssiAttrs !== undefined && rssiAttrs.length === 0;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
public async rssi(): Promise<number> {
|
|
293
|
-
if (!this.hasRssi) {
|
|
294
|
-
throw new ButtplugDeviceError(
|
|
295
|
-
`Device ${this.name} has no RSSI capabilities`
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
const rssiAttrs = this.messageAttributes.SensorReadCmd?.filter(
|
|
299
|
-
(x) => x.SensorType === Messages.SensorType.RSSI
|
|
300
|
-
);
|
|
301
|
-
// Find the battery sensor, we'll need its index.
|
|
302
|
-
const result = await this.sensorRead(
|
|
303
|
-
rssiAttrs![0].Index,
|
|
304
|
-
Messages.SensorType.RSSI
|
|
305
|
-
);
|
|
306
|
-
return result[0];
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
public async rawRead(
|
|
310
|
-
endpoint: string,
|
|
311
|
-
expectedLength: number,
|
|
312
|
-
timeout: number
|
|
313
|
-
): Promise<Uint8Array> {
|
|
314
|
-
if (!this.messageAttributes.RawReadCmd) {
|
|
315
|
-
throw new ButtplugDeviceError(
|
|
316
|
-
`Device ${this.name} has no raw read capabilities`
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
if (this.messageAttributes.RawReadCmd.Endpoints.indexOf(endpoint) === -1) {
|
|
320
|
-
throw new ButtplugDeviceError(
|
|
321
|
-
`Device ${this.name} has no raw readable endpoint ${endpoint}`
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
const response = await this.send(
|
|
325
|
-
new Messages.RawReadCmd(this.index, endpoint, expectedLength, timeout)
|
|
326
|
-
);
|
|
327
|
-
switch (getMessageClassFromMessage(response)) {
|
|
328
|
-
case Messages.RawReading:
|
|
329
|
-
return new Uint8Array((response as Messages.RawReading).Data);
|
|
330
|
-
case Messages.Error:
|
|
331
|
-
throw ButtplugError.FromError(response as Messages.Error);
|
|
332
|
-
default:
|
|
333
|
-
throw new ButtplugMessageError(
|
|
334
|
-
`Message type ${response.constructor} not handled by rawRead`
|
|
335
|
-
);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
public async rawWrite(
|
|
340
|
-
endpoint: string,
|
|
341
|
-
data: Uint8Array,
|
|
342
|
-
writeWithResponse: boolean
|
|
343
|
-
): Promise<void> {
|
|
344
|
-
if (!this.messageAttributes.RawWriteCmd) {
|
|
345
|
-
throw new ButtplugDeviceError(
|
|
346
|
-
`Device ${this.name} has no raw write capabilities`
|
|
347
|
-
);
|
|
348
|
-
}
|
|
349
|
-
if (this.messageAttributes.RawWriteCmd.Endpoints.indexOf(endpoint) === -1) {
|
|
350
|
-
throw new ButtplugDeviceError(
|
|
351
|
-
`Device ${this.name} has no raw writable endpoint ${endpoint}`
|
|
352
|
-
);
|
|
353
|
-
}
|
|
354
|
-
await this.sendExpectOk(
|
|
355
|
-
new Messages.RawWriteCmd(this.index, endpoint, data, writeWithResponse)
|
|
356
|
-
);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
public async rawSubscribe(endpoint: string): Promise<void> {
|
|
360
|
-
if (!this.messageAttributes.RawSubscribeCmd) {
|
|
361
|
-
throw new ButtplugDeviceError(
|
|
362
|
-
`Device ${this.name} has no raw subscribe capabilities`
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
if (
|
|
366
|
-
this.messageAttributes.RawSubscribeCmd.Endpoints.indexOf(endpoint) === -1
|
|
367
|
-
) {
|
|
368
|
-
throw new ButtplugDeviceError(
|
|
369
|
-
`Device ${this.name} has no raw subscribable endpoint ${endpoint}`
|
|
370
|
-
);
|
|
371
|
-
}
|
|
372
|
-
await this.sendExpectOk(new Messages.RawSubscribeCmd(this.index, endpoint));
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
public async rawUnsubscribe(endpoint: string): Promise<void> {
|
|
376
|
-
// This reuses raw subscribe's info.
|
|
377
|
-
if (!this.messageAttributes.RawSubscribeCmd) {
|
|
378
|
-
throw new ButtplugDeviceError(
|
|
379
|
-
`Device ${this.name} has no raw unsubscribe capabilities`
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
if (
|
|
383
|
-
this.messageAttributes.RawSubscribeCmd.Endpoints.indexOf(endpoint) === -1
|
|
384
|
-
) {
|
|
385
|
-
throw new ButtplugDeviceError(
|
|
386
|
-
`Device ${this.name} has no raw unsubscribable endpoint ${endpoint}`
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
await this.sendExpectOk(
|
|
390
|
-
new Messages.RawUnsubscribeCmd(this.index, endpoint)
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
public async stop(): Promise<void> {
|
|
395
|
-
await this.sendExpectOk(new Messages.StopDeviceCmd(this.index));
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
public emitDisconnected() {
|
|
399
|
-
this.emit('deviceremoved');
|
|
400
|
-
}
|
|
401
|
-
}
|
|
1
|
+
/*!
|
|
2
|
+
* Buttplug JS Source Code File - Visit https://buttplug.io for more info about
|
|
3
|
+
* the project. Licensed under the BSD 3-Clause license. See LICENSE file in the
|
|
4
|
+
* project root for full license information.
|
|
5
|
+
*
|
|
6
|
+
* @copyright Copyright (c) Nonpolynomial Labs LLC. All rights reserved.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
import * as Messages from '../core/Messages';
|
|
11
|
+
import {
|
|
12
|
+
ButtplugDeviceError,
|
|
13
|
+
ButtplugError,
|
|
14
|
+
ButtplugMessageError,
|
|
15
|
+
} from '../core/Exceptions';
|
|
16
|
+
import { EventEmitter } from 'eventemitter3';
|
|
17
|
+
import { ButtplugClientDeviceFeature } from './ButtplugClientDeviceFeature';
|
|
18
|
+
import { DeviceOutputCommand } from './ButtplugClientDeviceCommand';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Represents an abstract device, capable of taking certain kinds of messages.
|
|
22
|
+
*/
|
|
23
|
+
export class ButtplugClientDevice extends EventEmitter {
|
|
24
|
+
|
|
25
|
+
private _features: Map<number, ButtplugClientDeviceFeature>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Return the name of the device.
|
|
29
|
+
*/
|
|
30
|
+
public get name(): string {
|
|
31
|
+
return this._deviceInfo.DeviceName;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Return the user set name of the device.
|
|
36
|
+
*/
|
|
37
|
+
public get displayName(): string | undefined {
|
|
38
|
+
return this._deviceInfo.DeviceDisplayName;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Return the index of the device.
|
|
43
|
+
*/
|
|
44
|
+
public get index(): number {
|
|
45
|
+
return this._deviceInfo.DeviceIndex;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Return the index of the device.
|
|
50
|
+
*/
|
|
51
|
+
public get messageTimingGap(): number | undefined {
|
|
52
|
+
return this._deviceInfo.DeviceMessageTimingGap;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public get features(): Map<number, ButtplugClientDeviceFeature> {
|
|
56
|
+
return this._features;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// /**
|
|
60
|
+
// * Return a list of message types the device accepts.
|
|
61
|
+
// */
|
|
62
|
+
// public get messageAttributes(): Messages.MessageAttributes {
|
|
63
|
+
// return this._deviceInfo.DeviceMessages;
|
|
64
|
+
// }
|
|
65
|
+
//
|
|
66
|
+
public static fromMsg(
|
|
67
|
+
msg: Messages.DeviceInfo,
|
|
68
|
+
sendClosure: (
|
|
69
|
+
msg: Messages.ButtplugMessage
|
|
70
|
+
) => Promise<Messages.ButtplugMessage>
|
|
71
|
+
): ButtplugClientDevice {
|
|
72
|
+
return new ButtplugClientDevice(msg, sendClosure);
|
|
73
|
+
}
|
|
74
|
+
//
|
|
75
|
+
// // Map of messages and their attributes (feature count, etc...)
|
|
76
|
+
// private allowedMsgs: Map<string, Messages.MessageAttributes> = new Map<
|
|
77
|
+
// string,
|
|
78
|
+
// Messages.MessageAttributes
|
|
79
|
+
// >();
|
|
80
|
+
//
|
|
81
|
+
/**
|
|
82
|
+
* @param _index Index of the device, as created by the device manager.
|
|
83
|
+
* @param _name Name of the device.
|
|
84
|
+
* @param allowedMsgs Buttplug messages the device can receive.
|
|
85
|
+
*/
|
|
86
|
+
private constructor(
|
|
87
|
+
private _deviceInfo: Messages.DeviceInfo,
|
|
88
|
+
private _sendClosure: (
|
|
89
|
+
msg: Messages.ButtplugMessage
|
|
90
|
+
) => Promise<Messages.ButtplugMessage>
|
|
91
|
+
) {
|
|
92
|
+
super();
|
|
93
|
+
this._features = new Map(Object.entries(_deviceInfo.DeviceFeatures).map(([index, v]) => [parseInt(index), new ButtplugClientDeviceFeature(_deviceInfo.DeviceIndex, _deviceInfo.DeviceName, v, _sendClosure)]));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public async send(
|
|
97
|
+
msg: Messages.ButtplugMessage
|
|
98
|
+
): Promise<Messages.ButtplugMessage> {
|
|
99
|
+
// Assume we're getting the closure from ButtplugClient, which does all of
|
|
100
|
+
// the index/existence/connection/message checks for us.
|
|
101
|
+
return await this._sendClosure(msg);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
protected sendMsgExpectOk = async (
|
|
105
|
+
msg: Messages.ButtplugMessage
|
|
106
|
+
): Promise<void> => {
|
|
107
|
+
const response = await this.send(msg);
|
|
108
|
+
if (response.Ok !== undefined) {
|
|
109
|
+
return;
|
|
110
|
+
} else if (response.Error !== undefined) {
|
|
111
|
+
throw ButtplugError.FromError(response as Messages.Error);
|
|
112
|
+
} else {
|
|
113
|
+
/*
|
|
114
|
+
throw ButtplugError.LogAndError(
|
|
115
|
+
ButtplugMessageError,
|
|
116
|
+
this._logger,
|
|
117
|
+
`Message ${response} not handled by SendMsgExpectOk`
|
|
118
|
+
);
|
|
119
|
+
*/
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
protected isOutputValid(featureIndex: number, type: Messages.OutputType) {
|
|
124
|
+
if (!this._deviceInfo.DeviceFeatures.hasOwnProperty(featureIndex.toString())) {
|
|
125
|
+
throw new ButtplugDeviceError(`Feature index ${featureIndex} does not exist for device ${this.name}`);
|
|
126
|
+
}
|
|
127
|
+
if (this._deviceInfo.DeviceFeatures[featureIndex.toString()].Outputs !== undefined && !this._deviceInfo.DeviceFeatures[featureIndex.toString()].Outputs.hasOwnProperty(type)) {
|
|
128
|
+
throw new ButtplugDeviceError(`Feature index ${featureIndex} does not support type ${type} for device ${this.name}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public hasOutput(type: Messages.OutputType): boolean {
|
|
133
|
+
return this._features.values().filter((f) => f.hasOutput(type)).toArray().length > 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public hasInput(type: Messages.InputType): boolean {
|
|
137
|
+
return this._features.values().filter((f) => f.hasInput(type)).toArray().length > 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public async runOutput(cmd: DeviceOutputCommand): Promise<void> {
|
|
141
|
+
let p: Promise<void>[] = [];
|
|
142
|
+
for (let f of this._features.values()) {
|
|
143
|
+
if (f.hasOutput(cmd.outputType)) {
|
|
144
|
+
p.push(f.runOutput(cmd));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (p.length == 0) {
|
|
148
|
+
return Promise.reject(`No features with output type ${cmd.outputType}`);
|
|
149
|
+
}
|
|
150
|
+
await Promise.all(p);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public async stop(): Promise<void> {
|
|
154
|
+
await this.sendMsgExpectOk({StopCmd: { Id: 1, DeviceIndex: this.index, FeatureIndex: undefined, Inputs: true, Outputs: true}});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public async battery(): Promise<number> {
|
|
158
|
+
let p: Promise<void>[] = [];
|
|
159
|
+
for (let f of this._features.values()) {
|
|
160
|
+
if (f.hasInput(Messages.InputType.Battery)) {
|
|
161
|
+
// Right now, we only have one battery per device, so assume the first one we find is it.
|
|
162
|
+
let response = await f.runInput(Messages.InputType.Battery, Messages.InputCommandType.Read);
|
|
163
|
+
if (response === undefined) {
|
|
164
|
+
throw new ButtplugMessageError("Got incorrect message back.");
|
|
165
|
+
}
|
|
166
|
+
if (response.Reading[Messages.InputType.Battery] === undefined) {
|
|
167
|
+
throw new ButtplugMessageError("Got reading with no Battery info.");
|
|
168
|
+
}
|
|
169
|
+
return response.Reading[Messages.InputType.Battery].Value;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
throw new ButtplugDeviceError(`No battery present on this device.`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public emitDisconnected() {
|
|
176
|
+
this.emit('deviceremoved');
|
|
177
|
+
}
|
|
178
|
+
}
|