brilliantsole 0.0.27 → 0.0.29
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/assets/3d/anchor.glb +0 -0
- package/assets/3d/coin.glb +0 -0
- package/assets/3d/glasses.glb +0 -0
- package/assets/audio/bounceMedium.wav +0 -0
- package/assets/audio/bounceStrong.wav +0 -0
- package/assets/audio/bounceWeak.wav +0 -0
- package/assets/audio/coin.wav +0 -0
- package/assets/audio/getUp.wav +0 -0
- package/assets/audio/grab.wav +0 -0
- package/assets/audio/kick.wav +0 -0
- package/assets/audio/platterFadeIn old.wav +0 -0
- package/assets/audio/platterFadeIn.wav +0 -0
- package/assets/audio/platterFadeOut.wav +0 -0
- package/assets/audio/punch.wav +0 -0
- package/assets/audio/punchSqueak.wav +0 -0
- package/assets/audio/purr.wav +0 -0
- package/assets/audio/purrFadeOut.wav +0 -0
- package/assets/audio/release.wav +0 -0
- package/assets/audio/splat.wav +0 -0
- package/assets/audio/stomp.wav +0 -0
- package/build/brilliantsole.cjs +3091 -741
- package/build/brilliantsole.cjs.map +1 -1
- package/build/brilliantsole.js +2759 -709
- package/build/brilliantsole.js.map +1 -1
- package/build/brilliantsole.ls.js +2602 -543
- package/build/brilliantsole.ls.js.map +1 -1
- package/build/brilliantsole.min.js +1 -1
- package/build/brilliantsole.min.js.map +1 -1
- package/build/brilliantsole.module.d.ts +295 -65
- package/build/brilliantsole.module.js +2749 -710
- package/build/brilliantsole.module.js.map +1 -1
- package/build/brilliantsole.module.min.d.ts +295 -65
- package/build/brilliantsole.module.min.js +1 -1
- package/build/brilliantsole.module.min.js.map +1 -1
- package/build/brilliantsole.node.module.d.ts +289 -62
- package/build/brilliantsole.node.module.js +3080 -742
- package/build/brilliantsole.node.module.js.map +1 -1
- package/build/dts/BS-output.d.ts +10 -0
- package/build/dts/BS.d.ts +21 -8
- package/build/dts/CameraManager.d.ts +72 -0
- package/build/dts/Device.d.ts +64 -13
- package/build/dts/DeviceInformationManager.d.ts +4 -4
- package/build/dts/DeviceManager.d.ts +2 -0
- package/build/dts/FileTransferManager.d.ts +18 -8
- package/build/dts/InformationManager.d.ts +2 -0
- package/build/dts/MicrophoneManager.d.ts +88 -0
- package/build/dts/TfliteManager.d.ts +22 -2
- package/build/dts/WifiManager.d.ts +61 -0
- package/build/dts/connection/BaseConnectionManager.d.ts +35 -3
- package/build/dts/connection/ClientConnectionManager.d.ts +7 -2
- package/build/dts/connection/bluetooth/NobleConnectionManager.d.ts +2 -1
- package/build/dts/connection/bluetooth/WebBluetoothConnectionManager.d.ts +1 -0
- package/build/dts/connection/bluetooth/bluetoothUUIDs.d.ts +2 -2
- package/build/dts/connection/udp/UDPConnectionManager.d.ts +28 -0
- package/build/dts/connection/webSocket/WebSocketConnectionManager.d.ts +25 -0
- package/build/dts/devicePair/DevicePair.d.ts +5 -5
- package/build/dts/scanner/BaseScanner.d.ts +4 -1
- package/build/dts/scanner/NobleScanner.d.ts +2 -1
- package/build/dts/sensor/MotionSensorDataManager.d.ts +5 -2
- package/build/dts/sensor/SensorDataManager.d.ts +5 -4
- package/build/dts/server/BaseClient.d.ts +5 -3
- package/build/dts/server/ServerUtils.d.ts +1 -1
- package/build/dts/server/websocket/WebSocketUtils.d.ts +1 -1
- package/build/dts/utils/AudioUtils.d.ts +2 -0
- package/build/dts/utils/Console.d.ts +2 -0
- package/build/dts/utils/ThrottleUtils.d.ts +2 -0
- package/build/dts/vibration/VibrationManager.d.ts +19 -2
- package/build/index.d.ts +292 -62
- package/build/index.node.d.ts +286 -59
- package/examples/3d/scene.html +19 -5
- package/examples/3d-generic/index.html +144 -0
- package/examples/3d-generic/script.js +266 -0
- package/examples/basic/index.html +267 -17
- package/examples/basic/script.js +958 -105
- package/examples/camera/barcode-detector.js +109 -0
- package/examples/camera/depth-estimation.js +71 -0
- package/examples/camera/face-detector.js +119 -0
- package/examples/camera/face-landmark.js +111 -0
- package/examples/camera/gesture-recognition.js +97 -0
- package/examples/camera/hand-landmark.js +74 -0
- package/examples/camera/image-segmentation.js +98 -0
- package/examples/camera/image-to-text.js +43 -0
- package/examples/camera/image-upscale.js +75 -0
- package/examples/camera/index.html +129 -0
- package/examples/camera/object-detection.js +98 -0
- package/examples/camera/pose-landmark.js +60 -0
- package/examples/camera/script.js +316 -0
- package/examples/camera/utils.js +165 -0
- package/examples/camera/yolo-tiny.js +54 -0
- package/examples/camera/yolo.js +119 -0
- package/examples/edge-impulse/script.js +157 -48
- package/examples/edge-impulse-test/README.md +11 -0
- package/examples/edge-impulse-test/edge-impulse-standalone.js +7228 -0
- package/examples/edge-impulse-test/edge-impulse-standalone.wasm +0 -0
- package/examples/edge-impulse-test/index.html +75 -0
- package/examples/edge-impulse-test/run-impulse.js +135 -0
- package/examples/edge-impulse-test/script.js +200 -0
- package/examples/glasses-gestures/README.md +11 -0
- package/examples/glasses-gestures/edge-impulse-standalone.js +7228 -0
- package/examples/glasses-gestures/edge-impulse-standalone.wasm +0 -0
- package/examples/glasses-gestures/index.html +69 -0
- package/examples/glasses-gestures/run-impulse.js +135 -0
- package/examples/glasses-gestures/script.js +226 -0
- package/examples/gloves/edge-impulse-standalone.js +7228 -0
- package/examples/gloves/edge-impulse-standalone.wasm +0 -0
- package/examples/gloves/index.html +4 -1
- package/examples/gloves/run-impulse.js +135 -0
- package/examples/gloves/script.js +367 -51
- package/examples/graph/script.js +94 -37
- package/examples/microphone/gender.js +54 -0
- package/examples/microphone/index.html +102 -0
- package/examples/microphone/script.js +394 -0
- package/examples/microphone/utils.js +45 -0
- package/examples/microphone/whisper-realtime.js +166 -0
- package/examples/microphone/whisper.js +132 -0
- package/examples/punch/index.html +135 -0
- package/examples/punch/punch.tflite +0 -0
- package/examples/punch/script.js +169 -0
- package/examples/server/index.html +98 -22
- package/examples/server/script.js +317 -109
- package/examples/ukaton-firmware-update/merged-firmware.bin +0 -0
- package/examples/utils/aframe/aframe-master.min.js +2 -0
- package/examples/utils/aframe/bs-vibration.js +150 -0
- package/examples/utils/aframe/force-pushable.js +80 -0
- package/examples/utils/aframe/grabbable-anchor.js +46 -0
- package/examples/utils/aframe/grabbable-listener.js +31 -0
- package/examples/utils/aframe/grabbable-physics-body.js +190 -0
- package/examples/utils/aframe/grow-shrink.js +25 -0
- package/examples/utils/aframe/hand-punch.js +119 -0
- package/examples/utils/aframe/my-obb-collider.js +293 -0
- package/examples/utils/aframe/occlude-hand-tracking-controls.js +47 -0
- package/examples/utils/aframe/occlude-mesh.js +42 -0
- package/examples/utils/aframe/palm-up-detector.js +47 -0
- package/examples/utils/aframe/shadow-material.js +20 -0
- package/examples/utils/aframe/soft-shadow-light.js +9 -0
- package/examples/webxr-2/assets/3d/soccerBall.glb +0 -0
- package/examples/webxr-2/assets/audio/shellBounce.wav +0 -0
- package/examples/webxr-2/assets/audio/shellHit.wav +0 -0
- package/examples/webxr-2/assets/audio/shellKick.wav +0 -0
- package/examples/webxr-2/assets/audio/soccerBounce.wav +0 -0
- package/examples/webxr-2/assets/audio/soccerKick.mp3 +0 -0
- package/examples/webxr-2/assets/images/shellTexture.png +0 -0
- package/examples/webxr-2/components/bs-ankle.js +337 -0
- package/examples/webxr-2/components/coin.js +84 -0
- package/examples/webxr-2/components/custom-wrap.js +17 -0
- package/examples/webxr-2/components/goomba.js +3250 -0
- package/examples/webxr-2/components/init-shell-material.js +215 -0
- package/examples/webxr-2/components/platter.js +172 -0
- package/examples/webxr-2/components/shell.js +374 -0
- package/examples/webxr-2/components/soccer-ball.js +250 -0
- package/examples/webxr-2/components/squashed-goomba.js +249 -0
- package/examples/webxr-2/edge-impulse-standalone.js +7228 -0
- package/examples/webxr-2/edge-impulse-standalone.wasm +0 -0
- package/examples/webxr-2/index.html +996 -0
- package/examples/webxr-2/kick.tflite +0 -0
- package/examples/webxr-2/kick2.tflite +0 -0
- package/examples/webxr-2/run-impulse.js +135 -0
- package/examples/webxr-2/script.js +384 -0
- package/examples/webxr-3/components/bs-camera.js +65 -0
- package/examples/webxr-3/index.html +134 -0
- package/examples/webxr-3/script.js +432 -0
- package/package.json +2 -1
- package/src/.prettierrc +4 -0
- package/src/BS.ts +79 -8
- package/src/CameraManager.ts +497 -0
- package/src/Device.ts +691 -86
- package/src/DeviceInformationManager.ts +19 -10
- package/src/DeviceManager.ts +85 -25
- package/src/FileTransferManager.ts +145 -20
- package/src/InformationManager.ts +40 -15
- package/src/MicrophoneManager.ts +599 -0
- package/src/TfliteManager.ts +171 -25
- package/src/WifiManager.ts +323 -0
- package/src/connection/BaseConnectionManager.ts +130 -30
- package/src/connection/ClientConnectionManager.ts +34 -10
- package/src/connection/bluetooth/BluetoothConnectionManager.ts +8 -2
- package/src/connection/bluetooth/NobleConnectionManager.ts +147 -41
- package/src/connection/bluetooth/WebBluetoothConnectionManager.ts +99 -34
- package/src/connection/bluetooth/bluetoothUUIDs.ts +40 -13
- package/src/connection/udp/UDPConnectionManager.ts +356 -0
- package/src/connection/websocket/WebSocketConnectionManager.ts +282 -0
- package/src/devicePair/DevicePair.ts +95 -25
- package/src/devicePair/DevicePairPressureSensorDataManager.ts +27 -7
- package/src/scanner/BaseScanner.ts +49 -11
- package/src/scanner/NobleScanner.ts +76 -14
- package/src/sensor/MotionSensorDataManager.ts +21 -6
- package/src/sensor/PressureSensorDataManager.ts +37 -8
- package/src/sensor/SensorConfigurationManager.ts +73 -22
- package/src/sensor/SensorDataManager.ts +109 -23
- package/src/server/BaseClient.ts +150 -36
- package/src/server/BaseServer.ts +50 -2
- package/src/server/ServerUtils.ts +39 -9
- package/src/server/udp/UDPServer.ts +73 -22
- package/src/server/udp/UDPUtils.ts +9 -2
- package/src/server/websocket/WebSocketClient.ts +27 -7
- package/src/server/websocket/WebSocketUtils.ts +4 -2
- package/src/utils/AudioUtils.ts +65 -0
- package/src/utils/Console.ts +62 -9
- package/src/utils/ParseUtils.ts +24 -5
- package/src/utils/ThrottleUtils.ts +62 -0
- package/src/utils/Timer.ts +1 -1
- package/src/vibration/VibrationManager.ts +166 -40
|
@@ -22,19 +22,23 @@ export interface DeviceInformation {
|
|
|
22
22
|
serialNumber: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export const
|
|
25
|
+
export const DeviceInformationTypes = [
|
|
26
26
|
"manufacturerName",
|
|
27
27
|
"modelNumber",
|
|
28
|
-
"softwareRevision",
|
|
29
28
|
"hardwareRevision",
|
|
30
29
|
"firmwareRevision",
|
|
30
|
+
"softwareRevision",
|
|
31
31
|
"pnpId",
|
|
32
32
|
"serialNumber",
|
|
33
33
|
] as const;
|
|
34
|
-
export type
|
|
34
|
+
export type DeviceInformationType = (typeof DeviceInformationTypes)[number];
|
|
35
35
|
|
|
36
|
-
export const DeviceInformationEventTypes = [
|
|
37
|
-
|
|
36
|
+
export const DeviceInformationEventTypes = [
|
|
37
|
+
...DeviceInformationTypes,
|
|
38
|
+
"deviceInformation",
|
|
39
|
+
] as const;
|
|
40
|
+
export type DeviceInformationEventType =
|
|
41
|
+
(typeof DeviceInformationEventTypes)[number];
|
|
38
42
|
|
|
39
43
|
export interface DeviceInformationEventMessages {
|
|
40
44
|
manufacturerName: { manufacturerName: string };
|
|
@@ -67,18 +71,21 @@ class DeviceInformationManager {
|
|
|
67
71
|
this.#information = {};
|
|
68
72
|
}
|
|
69
73
|
get #isComplete() {
|
|
70
|
-
return
|
|
74
|
+
return DeviceInformationTypes.filter((key) => key != "serialNumber").every(
|
|
71
75
|
(key) => key in this.#information
|
|
72
76
|
);
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
#update(partialDeviceInformation: Partial<DeviceInformation>) {
|
|
76
80
|
_console.log({ partialDeviceInformation });
|
|
77
|
-
const deviceInformationNames = Object.keys(
|
|
81
|
+
const deviceInformationNames = Object.keys(
|
|
82
|
+
partialDeviceInformation
|
|
83
|
+
) as (keyof DeviceInformation)[];
|
|
78
84
|
deviceInformationNames.forEach((deviceInformationName) => {
|
|
79
85
|
// @ts-expect-error
|
|
80
86
|
this.#dispatchEvent(deviceInformationName, {
|
|
81
|
-
[deviceInformationName]:
|
|
87
|
+
[deviceInformationName]:
|
|
88
|
+
partialDeviceInformation[deviceInformationName],
|
|
82
89
|
});
|
|
83
90
|
});
|
|
84
91
|
|
|
@@ -86,11 +93,13 @@ class DeviceInformationManager {
|
|
|
86
93
|
_console.log({ deviceInformation: this.#information });
|
|
87
94
|
if (this.#isComplete) {
|
|
88
95
|
_console.log("completed deviceInformation");
|
|
89
|
-
this.#dispatchEvent("deviceInformation", {
|
|
96
|
+
this.#dispatchEvent("deviceInformation", {
|
|
97
|
+
deviceInformation: this.information,
|
|
98
|
+
});
|
|
90
99
|
}
|
|
91
100
|
}
|
|
92
101
|
|
|
93
|
-
parseMessage(messageType:
|
|
102
|
+
parseMessage(messageType: DeviceInformationType, dataView: DataView) {
|
|
94
103
|
_console.log({ messageType });
|
|
95
104
|
|
|
96
105
|
switch (messageType) {
|
package/src/DeviceManager.ts
CHANGED
|
@@ -4,7 +4,12 @@ import Device, { BoundDeviceEventListeners, DeviceEventMap } from "./Device.ts";
|
|
|
4
4
|
import { DeviceType } from "./InformationManager.ts";
|
|
5
5
|
import { createConsole } from "./utils/Console.ts";
|
|
6
6
|
import { isInBluefy, isInBrowser } from "./utils/environment.ts";
|
|
7
|
-
import EventDispatcher, {
|
|
7
|
+
import EventDispatcher, {
|
|
8
|
+
BoundEventListeners,
|
|
9
|
+
Event,
|
|
10
|
+
EventListenerMap,
|
|
11
|
+
EventMap,
|
|
12
|
+
} from "./utils/EventDispatcher.ts";
|
|
8
13
|
import { addEventListeners } from "./utils/EventUtils.ts";
|
|
9
14
|
|
|
10
15
|
const _console = createConsole("DeviceManager", { log: false });
|
|
@@ -12,6 +17,8 @@ const _console = createConsole("DeviceManager", { log: false });
|
|
|
12
17
|
export interface LocalStorageDeviceInformation {
|
|
13
18
|
type: DeviceType;
|
|
14
19
|
bluetoothId: string;
|
|
20
|
+
ipAddress?: string;
|
|
21
|
+
isWifiSecure?: boolean;
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
export interface LocalStorageConfiguration {
|
|
@@ -43,13 +50,21 @@ export type DeviceManagerEventDispatcher = EventDispatcher<
|
|
|
43
50
|
DeviceManagerEventType,
|
|
44
51
|
DeviceManagerEventMessages
|
|
45
52
|
>;
|
|
46
|
-
export type DeviceManagerEventMap = EventMap<
|
|
53
|
+
export type DeviceManagerEventMap = EventMap<
|
|
54
|
+
typeof Device,
|
|
55
|
+
DeviceManagerEventType,
|
|
56
|
+
DeviceManagerEventMessages
|
|
57
|
+
>;
|
|
47
58
|
export type DeviceManagerEventListenerMap = EventListenerMap<
|
|
48
59
|
typeof Device,
|
|
49
60
|
DeviceManagerEventType,
|
|
50
61
|
DeviceManagerEventMessages
|
|
51
62
|
>;
|
|
52
|
-
export type DeviceManagerEvent = Event<
|
|
63
|
+
export type DeviceManagerEvent = Event<
|
|
64
|
+
typeof Device,
|
|
65
|
+
DeviceManagerEventType,
|
|
66
|
+
DeviceManagerEventMessages
|
|
67
|
+
>;
|
|
53
68
|
export type BoundDeviceManagerEventListeners = BoundEventListeners<
|
|
54
69
|
typeof Device,
|
|
55
70
|
DeviceManagerEventType,
|
|
@@ -87,8 +102,15 @@ class DeviceManager {
|
|
|
87
102
|
|
|
88
103
|
// CONNECTION STATUS
|
|
89
104
|
/** @private */
|
|
90
|
-
OnDeviceConnectionStatusUpdated(
|
|
91
|
-
|
|
105
|
+
OnDeviceConnectionStatusUpdated(
|
|
106
|
+
device: Device,
|
|
107
|
+
connectionStatus: ConnectionStatus
|
|
108
|
+
) {
|
|
109
|
+
if (
|
|
110
|
+
connectionStatus == "notConnected" &&
|
|
111
|
+
!device.canReconnect &&
|
|
112
|
+
this.#AvailableDevices.includes(device)
|
|
113
|
+
) {
|
|
92
114
|
const deviceIndex = this.#AvailableDevices.indexOf(device);
|
|
93
115
|
this.AvailableDevices.splice(deviceIndex, 1);
|
|
94
116
|
this.#DispatchAvailableDevices();
|
|
@@ -125,20 +147,29 @@ class DeviceManager {
|
|
|
125
147
|
}
|
|
126
148
|
|
|
127
149
|
#AssertLocalStorage() {
|
|
128
|
-
_console.assertWithError(
|
|
150
|
+
_console.assertWithError(
|
|
151
|
+
isInBrowser,
|
|
152
|
+
"localStorage is only available in the browser"
|
|
153
|
+
);
|
|
129
154
|
_console.assertWithError(window.localStorage, "localStorage not found");
|
|
130
155
|
}
|
|
131
156
|
#LocalStorageKey = "BS.Device";
|
|
132
157
|
#SaveToLocalStorage() {
|
|
133
158
|
this.#AssertLocalStorage();
|
|
134
|
-
localStorage.setItem(
|
|
159
|
+
localStorage.setItem(
|
|
160
|
+
this.#LocalStorageKey,
|
|
161
|
+
JSON.stringify(this.#LocalStorageConfiguration)
|
|
162
|
+
);
|
|
135
163
|
}
|
|
136
164
|
async #LoadFromLocalStorage() {
|
|
137
165
|
this.#AssertLocalStorage();
|
|
138
166
|
let localStorageString = localStorage.getItem(this.#LocalStorageKey);
|
|
139
167
|
if (typeof localStorageString != "string") {
|
|
140
168
|
_console.log("no info found in localStorage");
|
|
141
|
-
this.#LocalStorageConfiguration = Object.assign(
|
|
169
|
+
this.#LocalStorageConfiguration = Object.assign(
|
|
170
|
+
{},
|
|
171
|
+
this.#DefaultLocalStorageConfiguration
|
|
172
|
+
);
|
|
142
173
|
this.#SaveToLocalStorage();
|
|
143
174
|
return;
|
|
144
175
|
}
|
|
@@ -160,13 +191,17 @@ class DeviceManager {
|
|
|
160
191
|
return;
|
|
161
192
|
}
|
|
162
193
|
this.#AssertLocalStorage();
|
|
163
|
-
const deviceInformationIndex =
|
|
164
|
-
|
|
165
|
-
|
|
194
|
+
const deviceInformationIndex =
|
|
195
|
+
this.#LocalStorageConfiguration!.devices.findIndex(
|
|
196
|
+
(deviceInformation) => {
|
|
197
|
+
return deviceInformation.bluetoothId == device.bluetoothId;
|
|
198
|
+
}
|
|
199
|
+
);
|
|
166
200
|
if (deviceInformationIndex == -1) {
|
|
167
201
|
return;
|
|
168
202
|
}
|
|
169
|
-
this.#LocalStorageConfiguration!.devices[deviceInformationIndex].type =
|
|
203
|
+
this.#LocalStorageConfiguration!.devices[deviceInformationIndex].type =
|
|
204
|
+
device.type;
|
|
170
205
|
this.#SaveToLocalStorage();
|
|
171
206
|
}
|
|
172
207
|
|
|
@@ -229,7 +264,8 @@ class DeviceManager {
|
|
|
229
264
|
return;
|
|
230
265
|
}
|
|
231
266
|
let deviceInformation = configuration.devices.find(
|
|
232
|
-
(deviceInformation) =>
|
|
267
|
+
(deviceInformation) =>
|
|
268
|
+
bluetoothDevice.id == deviceInformation.bluetoothId
|
|
233
269
|
);
|
|
234
270
|
if (!deviceInformation) {
|
|
235
271
|
return;
|
|
@@ -245,10 +281,13 @@ class DeviceManager {
|
|
|
245
281
|
if (existingAvailableDevice) {
|
|
246
282
|
if (
|
|
247
283
|
existingConnectedDevice &&
|
|
248
|
-
existingConnectedDevice?.bluetoothId ==
|
|
284
|
+
existingConnectedDevice?.bluetoothId ==
|
|
285
|
+
existingAvailableDevice.bluetoothId &&
|
|
249
286
|
existingConnectedDevice != existingAvailableDevice
|
|
250
287
|
) {
|
|
251
|
-
this.AvailableDevices[
|
|
288
|
+
this.AvailableDevices[
|
|
289
|
+
this.#AvailableDevices.indexOf(existingAvailableDevice)
|
|
290
|
+
] = existingConnectedDevice;
|
|
252
291
|
}
|
|
253
292
|
return;
|
|
254
293
|
}
|
|
@@ -274,7 +313,10 @@ class DeviceManager {
|
|
|
274
313
|
|
|
275
314
|
// STATIC EVENTLISTENERS
|
|
276
315
|
|
|
277
|
-
#EventDispatcher: DeviceManagerEventDispatcher = new EventDispatcher(
|
|
316
|
+
#EventDispatcher: DeviceManagerEventDispatcher = new EventDispatcher(
|
|
317
|
+
this as DeviceManager,
|
|
318
|
+
DeviceManagerEventTypes
|
|
319
|
+
);
|
|
278
320
|
|
|
279
321
|
get AddEventListener() {
|
|
280
322
|
return this.#EventDispatcher.addEventListener;
|
|
@@ -302,14 +344,19 @@ class DeviceManager {
|
|
|
302
344
|
const deviceInformation: LocalStorageDeviceInformation = {
|
|
303
345
|
type: device.type,
|
|
304
346
|
bluetoothId: device.bluetoothId!,
|
|
347
|
+
ipAddress: device.ipAddress,
|
|
348
|
+
isWifiSecure: device.isWifiSecure,
|
|
305
349
|
};
|
|
306
|
-
const deviceInformationIndex =
|
|
307
|
-
(
|
|
308
|
-
|
|
350
|
+
const deviceInformationIndex =
|
|
351
|
+
this.#LocalStorageConfiguration!.devices.findIndex(
|
|
352
|
+
(_deviceInformation) =>
|
|
353
|
+
_deviceInformation.bluetoothId == deviceInformation.bluetoothId
|
|
354
|
+
);
|
|
309
355
|
if (deviceInformationIndex == -1) {
|
|
310
356
|
this.#LocalStorageConfiguration!.devices.push(deviceInformation);
|
|
311
357
|
} else {
|
|
312
|
-
this.#LocalStorageConfiguration!.devices[deviceInformationIndex] =
|
|
358
|
+
this.#LocalStorageConfiguration!.devices[deviceInformationIndex] =
|
|
359
|
+
deviceInformation;
|
|
313
360
|
}
|
|
314
361
|
this.#SaveToLocalStorage();
|
|
315
362
|
}
|
|
@@ -322,7 +369,10 @@ class DeviceManager {
|
|
|
322
369
|
} else {
|
|
323
370
|
if (this.#ConnectedDevices.includes(device)) {
|
|
324
371
|
_console.log("removing device", device);
|
|
325
|
-
this.#ConnectedDevices.splice(
|
|
372
|
+
this.#ConnectedDevices.splice(
|
|
373
|
+
this.#ConnectedDevices.indexOf(device),
|
|
374
|
+
1
|
|
375
|
+
);
|
|
326
376
|
this.#DispatchEvent("deviceDisconnected", { device });
|
|
327
377
|
this.#DispatchEvent("deviceIsConnected", { device });
|
|
328
378
|
this.#DispatchConnectedDevices();
|
|
@@ -339,7 +389,9 @@ class DeviceManager {
|
|
|
339
389
|
);
|
|
340
390
|
_console.log({ existingAvailableDevice });
|
|
341
391
|
if (existingAvailableDevice) {
|
|
342
|
-
this.AvailableDevices[
|
|
392
|
+
this.AvailableDevices[
|
|
393
|
+
this.AvailableDevices.indexOf(existingAvailableDevice)
|
|
394
|
+
] = device;
|
|
343
395
|
} else {
|
|
344
396
|
this.AvailableDevices.push(device);
|
|
345
397
|
}
|
|
@@ -349,7 +401,11 @@ class DeviceManager {
|
|
|
349
401
|
}
|
|
350
402
|
|
|
351
403
|
_CheckDeviceAvailability(device: Device) {
|
|
352
|
-
if (
|
|
404
|
+
if (
|
|
405
|
+
!device.isConnected &&
|
|
406
|
+
!device.isAvailable &&
|
|
407
|
+
this.#AvailableDevices.includes(device)
|
|
408
|
+
) {
|
|
353
409
|
_console.log("removing device from availableDevices...");
|
|
354
410
|
this.#AvailableDevices.splice(this.#AvailableDevices.indexOf(device), 1);
|
|
355
411
|
this.#DispatchAvailableDevices();
|
|
@@ -358,11 +414,15 @@ class DeviceManager {
|
|
|
358
414
|
|
|
359
415
|
#DispatchAvailableDevices() {
|
|
360
416
|
_console.log({ AvailableDevices: this.AvailableDevices });
|
|
361
|
-
this.#DispatchEvent("availableDevices", {
|
|
417
|
+
this.#DispatchEvent("availableDevices", {
|
|
418
|
+
availableDevices: this.AvailableDevices,
|
|
419
|
+
});
|
|
362
420
|
}
|
|
363
421
|
#DispatchConnectedDevices() {
|
|
364
422
|
_console.log({ ConnectedDevices: this.ConnectedDevices });
|
|
365
|
-
this.#DispatchEvent("connectedDevices", {
|
|
423
|
+
this.#DispatchEvent("connectedDevices", {
|
|
424
|
+
connectedDevices: this.ConnectedDevices,
|
|
425
|
+
});
|
|
366
426
|
}
|
|
367
427
|
}
|
|
368
428
|
|
|
@@ -9,6 +9,7 @@ import autoBind from "auto-bind";
|
|
|
9
9
|
const _console = createConsole("FileTransferManager", { log: false });
|
|
10
10
|
|
|
11
11
|
export const FileTransferMessageTypes = [
|
|
12
|
+
"getFileTypes",
|
|
12
13
|
"maxFileLength",
|
|
13
14
|
"getFileType",
|
|
14
15
|
"setFileType",
|
|
@@ -24,13 +25,17 @@ export const FileTransferMessageTypes = [
|
|
|
24
25
|
] as const;
|
|
25
26
|
export type FileTransferMessageType = (typeof FileTransferMessageTypes)[number];
|
|
26
27
|
|
|
27
|
-
export const FileTypes = ["tflite"] as const;
|
|
28
|
+
export const FileTypes = ["tflite", "wifiServerCert", "wifiServerKey"] as const;
|
|
28
29
|
export type FileType = (typeof FileTypes)[number];
|
|
29
30
|
|
|
30
31
|
export const FileTransferStatuses = ["idle", "sending", "receiving"] as const;
|
|
31
32
|
export type FileTransferStatus = (typeof FileTransferStatuses)[number];
|
|
32
33
|
|
|
33
|
-
export const FileTransferCommands = [
|
|
34
|
+
export const FileTransferCommands = [
|
|
35
|
+
"startSend",
|
|
36
|
+
"startReceive",
|
|
37
|
+
"cancel",
|
|
38
|
+
] as const;
|
|
34
39
|
export type FileTransferCommand = (typeof FileTransferCommands)[number];
|
|
35
40
|
|
|
36
41
|
export const FileTransferDirections = ["sending", "receiving"] as const;
|
|
@@ -44,7 +49,21 @@ export const FileTransferEventTypes = [
|
|
|
44
49
|
] as const;
|
|
45
50
|
export type FileTransferEventType = (typeof FileTransferEventTypes)[number];
|
|
46
51
|
|
|
52
|
+
export const RequiredFileTransferMessageTypes: FileTransferMessageType[] = [
|
|
53
|
+
"maxFileLength",
|
|
54
|
+
"getFileLength",
|
|
55
|
+
"getFileChecksum",
|
|
56
|
+
"getFileType",
|
|
57
|
+
"fileTransferStatus",
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
export interface FileConfiguration {
|
|
61
|
+
file: FileLike;
|
|
62
|
+
type: FileType;
|
|
63
|
+
}
|
|
64
|
+
|
|
47
65
|
export interface FileTransferEventMessages {
|
|
66
|
+
getFileTypes: { fileTypes: FileType[] };
|
|
48
67
|
maxFileLength: { maxFileLength: number };
|
|
49
68
|
getFileType: { fileType: FileType };
|
|
50
69
|
getFileLength: { fileLength: number };
|
|
@@ -56,8 +75,13 @@ export interface FileTransferEventMessages {
|
|
|
56
75
|
fileReceived: { file: File | Blob };
|
|
57
76
|
}
|
|
58
77
|
|
|
59
|
-
export type FileTransferEventDispatcher = EventDispatcher<
|
|
60
|
-
|
|
78
|
+
export type FileTransferEventDispatcher = EventDispatcher<
|
|
79
|
+
Device,
|
|
80
|
+
FileTransferEventType,
|
|
81
|
+
FileTransferEventMessages
|
|
82
|
+
>;
|
|
83
|
+
export type SendFileTransferMessageCallback =
|
|
84
|
+
SendMessageCallback<FileTransferMessageType>;
|
|
61
85
|
|
|
62
86
|
class FileTransferManager {
|
|
63
87
|
constructor() {
|
|
@@ -82,17 +106,41 @@ class FileTransferManager {
|
|
|
82
106
|
#assertValidType(type: FileType) {
|
|
83
107
|
_console.assertEnumWithError(type, FileTypes);
|
|
84
108
|
}
|
|
109
|
+
#isValidType(type: FileType) {
|
|
110
|
+
return FileTypes.includes(type);
|
|
111
|
+
}
|
|
85
112
|
#assertValidTypeEnum(typeEnum: number) {
|
|
86
|
-
_console.assertWithError(
|
|
113
|
+
_console.assertWithError(
|
|
114
|
+
typeEnum in FileTypes,
|
|
115
|
+
`invalid typeEnum ${typeEnum}`
|
|
116
|
+
);
|
|
87
117
|
}
|
|
88
118
|
|
|
89
119
|
#assertValidStatusEnum(statusEnum: number) {
|
|
90
|
-
_console.assertWithError(
|
|
120
|
+
_console.assertWithError(
|
|
121
|
+
statusEnum in FileTransferStatuses,
|
|
122
|
+
`invalid statusEnum ${statusEnum}`
|
|
123
|
+
);
|
|
91
124
|
}
|
|
92
125
|
#assertValidCommand(command: FileTransferCommand) {
|
|
93
126
|
_console.assertEnumWithError(command, FileTransferCommands);
|
|
94
127
|
}
|
|
95
128
|
|
|
129
|
+
#fileTypes: FileType[] = [];
|
|
130
|
+
get fileTypes() {
|
|
131
|
+
return this.#fileTypes;
|
|
132
|
+
}
|
|
133
|
+
#parseFileTypes(dataView: DataView) {
|
|
134
|
+
const fileTypes = Array.from(new Uint8Array(dataView.buffer))
|
|
135
|
+
.map((index) => FileTypes[index])
|
|
136
|
+
.filter(Boolean);
|
|
137
|
+
this.#fileTypes = fileTypes;
|
|
138
|
+
_console.log("fileTypes", fileTypes);
|
|
139
|
+
this.#dispatchEvent("getFileTypes", {
|
|
140
|
+
fileTypes: this.#fileTypes,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
96
144
|
static #MaxLength = 0; // kB
|
|
97
145
|
static get MaxLength() {
|
|
98
146
|
return this.#MaxLength;
|
|
@@ -146,7 +194,10 @@ class FileTransferManager {
|
|
|
146
194
|
const promise = this.waitForEvent("getFileType");
|
|
147
195
|
|
|
148
196
|
const typeEnum = FileTypes.indexOf(newType);
|
|
149
|
-
this.sendMessage(
|
|
197
|
+
this.sendMessage(
|
|
198
|
+
[{ type: "setFileType", data: Uint8Array.from([typeEnum]).buffer }],
|
|
199
|
+
sendImmediately
|
|
200
|
+
);
|
|
150
201
|
|
|
151
202
|
await promise;
|
|
152
203
|
}
|
|
@@ -178,7 +229,10 @@ class FileTransferManager {
|
|
|
178
229
|
|
|
179
230
|
const dataView = new DataView(new ArrayBuffer(4));
|
|
180
231
|
dataView.setUint32(0, newLength, true);
|
|
181
|
-
this.sendMessage(
|
|
232
|
+
this.sendMessage(
|
|
233
|
+
[{ type: "setFileLength", data: dataView.buffer }],
|
|
234
|
+
sendImmediately
|
|
235
|
+
);
|
|
182
236
|
|
|
183
237
|
await promise;
|
|
184
238
|
}
|
|
@@ -208,7 +262,10 @@ class FileTransferManager {
|
|
|
208
262
|
|
|
209
263
|
const dataView = new DataView(new ArrayBuffer(4));
|
|
210
264
|
dataView.setUint32(0, newChecksum, true);
|
|
211
|
-
this.sendMessage(
|
|
265
|
+
this.sendMessage(
|
|
266
|
+
[{ type: "setFileChecksum", data: dataView.buffer }],
|
|
267
|
+
sendImmediately
|
|
268
|
+
);
|
|
212
269
|
|
|
213
270
|
await promise;
|
|
214
271
|
}
|
|
@@ -220,7 +277,12 @@ class FileTransferManager {
|
|
|
220
277
|
_console.log(`setting command ${command}`);
|
|
221
278
|
const commandEnum = FileTransferCommands.indexOf(command);
|
|
222
279
|
this.sendMessage(
|
|
223
|
-
[
|
|
280
|
+
[
|
|
281
|
+
{
|
|
282
|
+
type: "setFileTransferCommand",
|
|
283
|
+
data: Uint8Array.from([commandEnum]).buffer,
|
|
284
|
+
},
|
|
285
|
+
],
|
|
224
286
|
sendImmediately
|
|
225
287
|
);
|
|
226
288
|
|
|
@@ -243,6 +305,7 @@ class FileTransferManager {
|
|
|
243
305
|
this.#status = status;
|
|
244
306
|
this.#dispatchEvent("fileTransferStatus", { fileTransferStatus: status });
|
|
245
307
|
this.#receivedBlocks.length = 0;
|
|
308
|
+
this.#isCancelling = false;
|
|
246
309
|
}
|
|
247
310
|
#assertIsIdle() {
|
|
248
311
|
_console.assertWithError(this.#status == "idle", "status is not idle");
|
|
@@ -259,10 +322,15 @@ class FileTransferManager {
|
|
|
259
322
|
_console.log("parseFileBlock", dataView);
|
|
260
323
|
this.#receivedBlocks.push(dataView.buffer);
|
|
261
324
|
|
|
262
|
-
const bytesReceived = this.#receivedBlocks.reduce(
|
|
325
|
+
const bytesReceived = this.#receivedBlocks.reduce(
|
|
326
|
+
(sum, arrayBuffer) => (sum += arrayBuffer.byteLength),
|
|
327
|
+
0
|
|
328
|
+
);
|
|
263
329
|
const progress = bytesReceived / this.#length;
|
|
264
330
|
|
|
265
|
-
_console.log(
|
|
331
|
+
_console.log(
|
|
332
|
+
`received ${bytesReceived} of ${this.#length} bytes (${progress * 100}%)`
|
|
333
|
+
);
|
|
266
334
|
|
|
267
335
|
this.#dispatchEvent("fileTransferProgress", { progress });
|
|
268
336
|
|
|
@@ -273,7 +341,9 @@ class FileTransferManager {
|
|
|
273
341
|
if (this.isServerSide) {
|
|
274
342
|
return;
|
|
275
343
|
}
|
|
276
|
-
await this.sendMessage([
|
|
344
|
+
await this.sendMessage([
|
|
345
|
+
{ type: "fileBytesTransferred", data: dataView.buffer },
|
|
346
|
+
]);
|
|
277
347
|
return;
|
|
278
348
|
}
|
|
279
349
|
|
|
@@ -284,6 +354,12 @@ class FileTransferManager {
|
|
|
284
354
|
case "tflite":
|
|
285
355
|
fileName += ".tflite";
|
|
286
356
|
break;
|
|
357
|
+
case "wifiServerCert":
|
|
358
|
+
fileName += "_server.crt";
|
|
359
|
+
break;
|
|
360
|
+
case "wifiServerKey":
|
|
361
|
+
fileName += "_server.key";
|
|
362
|
+
break;
|
|
287
363
|
}
|
|
288
364
|
|
|
289
365
|
let file: File | Blob;
|
|
@@ -298,7 +374,9 @@ class FileTransferManager {
|
|
|
298
374
|
_console.log({ checksum });
|
|
299
375
|
|
|
300
376
|
if (checksum != this.#checksum) {
|
|
301
|
-
_console.error(
|
|
377
|
+
_console.error(
|
|
378
|
+
`wrong checksum - expected ${this.#checksum}, got ${checksum}`
|
|
379
|
+
);
|
|
302
380
|
return;
|
|
303
381
|
}
|
|
304
382
|
|
|
@@ -313,6 +391,9 @@ class FileTransferManager {
|
|
|
313
391
|
_console.log({ messageType });
|
|
314
392
|
|
|
315
393
|
switch (messageType) {
|
|
394
|
+
case "getFileTypes":
|
|
395
|
+
this.#parseFileTypes(dataView);
|
|
396
|
+
break;
|
|
316
397
|
case "maxFileLength":
|
|
317
398
|
this.#parseMaxLength(dataView);
|
|
318
399
|
break;
|
|
@@ -343,17 +424,39 @@ class FileTransferManager {
|
|
|
343
424
|
}
|
|
344
425
|
|
|
345
426
|
async send(type: FileType, file: FileLike) {
|
|
346
|
-
|
|
427
|
+
if (true) {
|
|
428
|
+
this.#assertIsIdle();
|
|
429
|
+
this.#assertValidType(type);
|
|
430
|
+
} else {
|
|
431
|
+
if (this.status != "idle") {
|
|
432
|
+
_console.warn(`cannot send file - status is ${this.status}`);
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
if (!this.#isValidType(type)) {
|
|
436
|
+
_console.warn(`invalid fileType ${type}`);
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
347
440
|
|
|
348
|
-
this.#assertValidType(type);
|
|
349
441
|
const fileBuffer = await getFileBuffer(file);
|
|
442
|
+
const fileLength = fileBuffer.byteLength;
|
|
443
|
+
const checksum = crc32(fileBuffer);
|
|
444
|
+
|
|
445
|
+
if (type != this.type) {
|
|
446
|
+
_console.log("different fileTypes - sending");
|
|
447
|
+
} else if (fileLength != this.length) {
|
|
448
|
+
_console.log("different fileLengths - sending");
|
|
449
|
+
} else if (checksum != this.checksum) {
|
|
450
|
+
_console.log("different fileChecksums - sending");
|
|
451
|
+
} else {
|
|
452
|
+
_console.log("already sent file");
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
350
455
|
|
|
351
456
|
const promises: Promise<any>[] = [];
|
|
352
457
|
|
|
353
458
|
promises.push(this.#setType(type, false));
|
|
354
|
-
const fileLength = fileBuffer.byteLength;
|
|
355
459
|
promises.push(this.#setLength(fileLength, false));
|
|
356
|
-
const checksum = crc32(fileBuffer);
|
|
357
460
|
promises.push(this.#setChecksum(checksum, false));
|
|
358
461
|
promises.push(this.#setCommand("startSend", false));
|
|
359
462
|
|
|
@@ -362,6 +465,8 @@ class FileTransferManager {
|
|
|
362
465
|
await Promise.all(promises);
|
|
363
466
|
|
|
364
467
|
await this.#send(fileBuffer);
|
|
468
|
+
|
|
469
|
+
return true;
|
|
365
470
|
}
|
|
366
471
|
|
|
367
472
|
#buffer?: ArrayBuffer;
|
|
@@ -377,6 +482,10 @@ class FileTransferManager {
|
|
|
377
482
|
if (this.status != "sending") {
|
|
378
483
|
return;
|
|
379
484
|
}
|
|
485
|
+
if (this.#isCancelling) {
|
|
486
|
+
_console.error("not sending block - busy cancelling");
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
380
489
|
if (!this.#buffer) {
|
|
381
490
|
if (!this.isServerSide) {
|
|
382
491
|
_console.error("no buffer defined");
|
|
@@ -393,7 +502,9 @@ class FileTransferManager {
|
|
|
393
502
|
|
|
394
503
|
const progress = 1 - bytesLeft / buffer.byteLength;
|
|
395
504
|
_console.log(
|
|
396
|
-
`sending bytes ${offset}-${offset + slicedBuffer.byteLength} of ${
|
|
505
|
+
`sending bytes ${offset}-${offset + slicedBuffer.byteLength} of ${
|
|
506
|
+
buffer.byteLength
|
|
507
|
+
} bytes (${progress * 100}%)`
|
|
397
508
|
);
|
|
398
509
|
this.#dispatchEvent("fileTransferProgress", { progress });
|
|
399
510
|
if (slicedBuffer.byteLength == 0) {
|
|
@@ -415,7 +526,11 @@ class FileTransferManager {
|
|
|
415
526
|
return;
|
|
416
527
|
}
|
|
417
528
|
if (!this.isServerSide && this.#bytesTransferred != bytesTransferred) {
|
|
418
|
-
_console.error(
|
|
529
|
+
_console.error(
|
|
530
|
+
`bytesTransferred are not equal - got ${bytesTransferred}, expected ${
|
|
531
|
+
this.#bytesTransferred
|
|
532
|
+
}`
|
|
533
|
+
);
|
|
419
534
|
this.cancel();
|
|
420
535
|
return;
|
|
421
536
|
}
|
|
@@ -431,9 +546,11 @@ class FileTransferManager {
|
|
|
431
546
|
await this.#setCommand("startReceive");
|
|
432
547
|
}
|
|
433
548
|
|
|
549
|
+
#isCancelling = false;
|
|
434
550
|
async cancel() {
|
|
435
551
|
this.#assertIsNotIdle();
|
|
436
552
|
_console.log("cancelling file transfer...");
|
|
553
|
+
this.#isCancelling = true;
|
|
437
554
|
await this.#setCommand("cancel");
|
|
438
555
|
}
|
|
439
556
|
|
|
@@ -450,6 +567,14 @@ class FileTransferManager {
|
|
|
450
567
|
_console.log({ newIsServerSide });
|
|
451
568
|
this.#isServerSide = newIsServerSide;
|
|
452
569
|
}
|
|
570
|
+
|
|
571
|
+
requestRequiredInformation() {
|
|
572
|
+
_console.log("requesting required fileTransfer information");
|
|
573
|
+
const messages = RequiredFileTransferMessageTypes.map((messageType) => ({
|
|
574
|
+
type: messageType,
|
|
575
|
+
}));
|
|
576
|
+
this.sendMessage(messages, false);
|
|
577
|
+
}
|
|
453
578
|
}
|
|
454
579
|
|
|
455
580
|
export default FileTransferManager;
|