brilliantsole 0.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.
Files changed (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/build/brilliantsole.cjs +5957 -0
  4. package/build/brilliantsole.cjs.map +1 -0
  5. package/build/brilliantsole.js +5448 -0
  6. package/build/brilliantsole.js.map +1 -0
  7. package/build/brilliantsole.ls.js +4872 -0
  8. package/build/brilliantsole.ls.js.map +1 -0
  9. package/build/brilliantsole.min.js +6 -0
  10. package/build/brilliantsole.min.js.map +1 -0
  11. package/build/brilliantsole.module.d.ts +908 -0
  12. package/build/brilliantsole.module.js +5412 -0
  13. package/build/brilliantsole.module.js.map +1 -0
  14. package/build/brilliantsole.module.min.d.ts +908 -0
  15. package/build/brilliantsole.module.min.js +6 -0
  16. package/build/brilliantsole.module.min.js.map +1 -0
  17. package/build/brilliantsole.node.module.d.ts +908 -0
  18. package/build/brilliantsole.node.module.js +5906 -0
  19. package/build/brilliantsole.node.module.js.map +1 -0
  20. package/build/dts/BS.d.ts +25 -0
  21. package/build/dts/Device.d.ts +136 -0
  22. package/build/dts/DeviceInformationManager.d.ts +56 -0
  23. package/build/dts/DeviceManager.d.ts +67 -0
  24. package/build/dts/FileTransferManager.d.ts +84 -0
  25. package/build/dts/FirmwareManager.d.ts +71 -0
  26. package/build/dts/InformationManager.d.ts +66 -0
  27. package/build/dts/TfliteManager.d.ts +92 -0
  28. package/build/dts/connection/BaseConnectionManager.d.ts +59 -0
  29. package/build/dts/connection/ClientConnectionManager.d.ts +23 -0
  30. package/build/dts/connection/WebSocketClientConnectionManager.d.ts +23 -0
  31. package/build/dts/connection/bluetooth/BluetoothConnectionManager.d.ts +10 -0
  32. package/build/dts/connection/bluetooth/NobleConnectionManager.d.ts +42 -0
  33. package/build/dts/connection/bluetooth/WebBluetoothConnectionManager.d.ts +20 -0
  34. package/build/dts/connection/bluetooth/bluetoothUUIDs.d.ts +14 -0
  35. package/build/dts/connection/webSocket/ClientConnectionManager.d.ts +23 -0
  36. package/build/dts/connection/webSocket/WebSocketClientConnectionManager.d.ts +23 -0
  37. package/build/dts/devicePair/DevicePair.d.ts +60 -0
  38. package/build/dts/devicePair/DevicePairPressureSensorDataManager.d.ts +25 -0
  39. package/build/dts/devicePair/DevicePairSensorDataManager.d.ts +33 -0
  40. package/build/dts/scanner/BaseScanner.d.ts +66 -0
  41. package/build/dts/scanner/NobleScanner.d.ts +17 -0
  42. package/build/dts/scanner/Scanner.d.ts +3 -0
  43. package/build/dts/sensor/BarometerSensorDataManager.d.ts +16 -0
  44. package/build/dts/sensor/MotionSensorDataManager.d.ts +69 -0
  45. package/build/dts/sensor/PressureSensorDataManager.d.ts +36 -0
  46. package/build/dts/sensor/SensorConfigurationManager.d.ts +44 -0
  47. package/build/dts/sensor/SensorDataManager.d.ts +40 -0
  48. package/build/dts/server/BaseClient.d.ts +85 -0
  49. package/build/dts/server/BaseServer.d.ts +48 -0
  50. package/build/dts/server/ServerUtils.d.ts +23 -0
  51. package/build/dts/server/udp/UDPServer.d.ts +11 -0
  52. package/build/dts/server/udp/UDPUtils.d.ts +9 -0
  53. package/build/dts/server/websocket/WebSocketClient.d.ts +17 -0
  54. package/build/dts/server/websocket/WebSocketServer.d.ts +13 -0
  55. package/build/dts/server/websocket/WebSocketUtils.d.ts +9 -0
  56. package/build/dts/utils/ArrayBufferUtils.d.ts +7 -0
  57. package/build/dts/utils/ArrayUtils.d.ts +2 -0
  58. package/build/dts/utils/CenterOfPressureHelper.d.ts +15 -0
  59. package/build/dts/utils/Console.d.ts +34 -0
  60. package/build/dts/utils/EventDispatcher.d.ts +50 -0
  61. package/build/dts/utils/EventUtils.d.ts +6 -0
  62. package/build/dts/utils/MathUtils.d.ts +21 -0
  63. package/build/dts/utils/ParseUtils.d.ts +5 -0
  64. package/build/dts/utils/RangeHelper.d.ts +8 -0
  65. package/build/dts/utils/Text.d.ts +6 -0
  66. package/build/dts/utils/Timer.d.ts +14 -0
  67. package/build/dts/utils/TypeScriptUtils.d.ts +19 -0
  68. package/build/dts/utils/cbor.d.ts +6 -0
  69. package/build/dts/utils/checksum.d.ts +3 -0
  70. package/build/dts/utils/environment.d.ts +13 -0
  71. package/build/dts/utils/mcumgr.d.ts +88 -0
  72. package/build/dts/utils/stringUtils.d.ts +2 -0
  73. package/build/dts/vibration/VibrationManager.d.ts +45 -0
  74. package/build/dts/vibration/VibrationWaveformEffects.d.ts +2 -0
  75. package/build/index.d.ts +908 -0
  76. package/build/index.node.d.ts +908 -0
  77. package/examples/3d/index.html +109 -0
  78. package/examples/3d/scene.html +57 -0
  79. package/examples/3d/script.js +419 -0
  80. package/examples/balance/index.html +138 -0
  81. package/examples/balance/script.js +243 -0
  82. package/examples/basic/index.html +327 -0
  83. package/examples/basic/script.js +1093 -0
  84. package/examples/center-of-pressure/index.html +132 -0
  85. package/examples/center-of-pressure/script.js +207 -0
  86. package/examples/device-pair/index.html +72 -0
  87. package/examples/device-pair/script.js +187 -0
  88. package/examples/edge-impulse/index.html +94 -0
  89. package/examples/edge-impulse/script.js +1033 -0
  90. package/examples/graph/index.html +83 -0
  91. package/examples/graph/script.js +469 -0
  92. package/examples/machine-learning/index.html +366 -0
  93. package/examples/machine-learning/script.js +1774 -0
  94. package/examples/pressure/index.html +145 -0
  95. package/examples/pressure/script.js +201 -0
  96. package/examples/recording/index.html +187 -0
  97. package/examples/recording/script.js +736 -0
  98. package/examples/server/index.html +266 -0
  99. package/examples/server/script.js +925 -0
  100. package/examples/utils/aframe/fingertip-button-component.js +201 -0
  101. package/examples/utils/aframe/fingertip-collider-target-component.js +102 -0
  102. package/examples/utils/aframe/fingertip-colliders-component.js +147 -0
  103. package/examples/utils/three/three.module.min.js +24846 -0
  104. package/examples/webxr/index.html +221 -0
  105. package/examples/webxr/script.js +1127 -0
  106. package/package.json +83 -0
  107. package/src/BS.ts +68 -0
  108. package/src/Device.ts +734 -0
  109. package/src/DeviceInformationManager.ts +146 -0
  110. package/src/DeviceManager.ts +354 -0
  111. package/src/FileTransferManager.ts +452 -0
  112. package/src/FirmwareManager.ts +357 -0
  113. package/src/InformationManager.ts +283 -0
  114. package/src/TfliteManager.ts +450 -0
  115. package/src/connection/BaseConnectionManager.ts +255 -0
  116. package/src/connection/ClientConnectionManager.ts +120 -0
  117. package/src/connection/bluetooth/BluetoothConnectionManager.ts +34 -0
  118. package/src/connection/bluetooth/NobleConnectionManager.ts +302 -0
  119. package/src/connection/bluetooth/WebBluetoothConnectionManager.ts +269 -0
  120. package/src/connection/bluetooth/bluetoothUUIDs.ts +218 -0
  121. package/src/devicePair/DevicePair.ts +253 -0
  122. package/src/devicePair/DevicePairPressureSensorDataManager.ts +82 -0
  123. package/src/devicePair/DevicePairSensorDataManager.ts +90 -0
  124. package/src/scanner/BaseScanner.ts +189 -0
  125. package/src/scanner/NobleScanner.ts +195 -0
  126. package/src/scanner/Scanner.ts +16 -0
  127. package/src/sensor/BarometerSensorDataManager.ts +41 -0
  128. package/src/sensor/MotionSensorDataManager.ts +151 -0
  129. package/src/sensor/PressureSensorDataManager.ts +112 -0
  130. package/src/sensor/SensorConfigurationManager.ts +177 -0
  131. package/src/sensor/SensorDataManager.ts +166 -0
  132. package/src/server/BaseClient.ts +368 -0
  133. package/src/server/BaseServer.ts +344 -0
  134. package/src/server/ServerUtils.ts +93 -0
  135. package/src/server/udp/UDPServer.ts +229 -0
  136. package/src/server/udp/UDPUtils.ts +20 -0
  137. package/src/server/websocket/WebSocketClient.ts +179 -0
  138. package/src/server/websocket/WebSocketServer.ts +184 -0
  139. package/src/server/websocket/WebSocketUtils.ts +20 -0
  140. package/src/utils/ArrayBufferUtils.ts +88 -0
  141. package/src/utils/ArrayUtils.ts +15 -0
  142. package/src/utils/CenterOfPressureHelper.ts +39 -0
  143. package/src/utils/Console.ts +156 -0
  144. package/src/utils/EventDispatcher.ts +153 -0
  145. package/src/utils/EventUtils.ts +41 -0
  146. package/src/utils/MathUtils.ts +53 -0
  147. package/src/utils/ParseUtils.ts +46 -0
  148. package/src/utils/RangeHelper.ts +38 -0
  149. package/src/utils/Text.ts +30 -0
  150. package/src/utils/Timer.ts +72 -0
  151. package/src/utils/TypeScriptUtils.ts +22 -0
  152. package/src/utils/cbor.js +429 -0
  153. package/src/utils/checksum.ts +41 -0
  154. package/src/utils/environment.ts +46 -0
  155. package/src/utils/mcumgr.js +444 -0
  156. package/src/utils/stringUtils.ts +11 -0
  157. package/src/vibration/VibrationManager.ts +308 -0
  158. package/src/vibration/VibrationWaveformEffects.ts +128 -0
@@ -0,0 +1,452 @@
1
+ import { createConsole } from "./utils/Console.ts";
2
+ import { crc32 } from "./utils/checksum.ts";
3
+ import { getFileBuffer } from "./utils/ArrayBufferUtils.ts";
4
+ import { FileLike } from "./utils/ArrayBufferUtils.ts";
5
+ import Device, { SendMessageCallback } from "./Device.ts";
6
+ import EventDispatcher from "./utils/EventDispatcher.ts";
7
+ import autoBind from "auto-bind";
8
+
9
+ const _console = createConsole("FileTransferManager", { log: true });
10
+
11
+ export const FileTransferMessageTypes = [
12
+ "maxFileLength",
13
+ "getFileType",
14
+ "setFileType",
15
+ "getFileLength",
16
+ "setFileLength",
17
+ "getFileChecksum",
18
+ "setFileChecksum",
19
+ "setFileTransferCommand",
20
+ "fileTransferStatus",
21
+ "getFileBlock",
22
+ "setFileBlock",
23
+ "fileBytesTransferred",
24
+ ] as const;
25
+ export type FileTransferMessageType = (typeof FileTransferMessageTypes)[number];
26
+
27
+ export const FileTypes = ["tflite"] as const;
28
+ export type FileType = (typeof FileTypes)[number];
29
+
30
+ export const FileTransferStatuses = ["idle", "sending", "receiving"] as const;
31
+ export type FileTransferStatus = (typeof FileTransferStatuses)[number];
32
+
33
+ export const FileTransferCommands = ["startSend", "startReceive", "cancel"] as const;
34
+ export type FileTransferCommand = (typeof FileTransferCommands)[number];
35
+
36
+ export const FileTransferDirections = ["sending", "receiving"] as const;
37
+ export type FileTransferDirection = (typeof FileTransferDirections)[number];
38
+
39
+ export const FileTransferEventTypes = [
40
+ ...FileTransferMessageTypes,
41
+ "fileTransferProgress",
42
+ "fileTransferComplete",
43
+ "fileReceived",
44
+ ] as const;
45
+ export type FileTransferEventType = (typeof FileTransferEventTypes)[number];
46
+
47
+ export interface FileTransferEventMessages {
48
+ maxFileLength: { maxFileLength: number };
49
+ getFileType: { fileType: FileType };
50
+ getFileLength: { fileLength: number };
51
+ getFileChecksum: { fileChecksum: number };
52
+ fileTransferStatus: { fileTransferStatus: FileTransferStatus };
53
+ getFileBlock: { fileTransferBlock: DataView };
54
+ fileTransferProgress: { progress: number };
55
+ fileTransferComplete: { direction: FileTransferDirection };
56
+ fileReceived: { file: File | Blob };
57
+ }
58
+
59
+ export type FileTransferEventDispatcher = EventDispatcher<Device, FileTransferEventType, FileTransferEventMessages>;
60
+ export type SendFileTransferMessageCallback = SendMessageCallback<FileTransferMessageType>;
61
+
62
+ class FileTransferManager {
63
+ constructor() {
64
+ autoBind(this);
65
+ }
66
+ sendMessage!: SendFileTransferMessageCallback;
67
+
68
+ eventDispatcher!: FileTransferEventDispatcher;
69
+ get addEventListener() {
70
+ return this.eventDispatcher.addEventListener;
71
+ }
72
+ get #dispatchEvent() {
73
+ return this.eventDispatcher.dispatchEvent;
74
+ }
75
+ get removeEventListener() {
76
+ return this.eventDispatcher.removeEventListener;
77
+ }
78
+ get waitForEvent() {
79
+ return this.eventDispatcher.waitForEvent;
80
+ }
81
+
82
+ #assertValidType(type: FileType) {
83
+ _console.assertEnumWithError(type, FileTypes);
84
+ }
85
+ #assertValidTypeEnum(typeEnum: number) {
86
+ _console.assertWithError(typeEnum in FileTypes, `invalid typeEnum ${typeEnum}`);
87
+ }
88
+
89
+ #assertValidStatusEnum(statusEnum: number) {
90
+ _console.assertWithError(statusEnum in FileTransferStatuses, `invalid statusEnum ${statusEnum}`);
91
+ }
92
+ #assertValidCommand(command: FileTransferCommand) {
93
+ _console.assertEnumWithError(command, FileTransferCommands);
94
+ }
95
+
96
+ static #MaxLength = 0; // kB
97
+ static get MaxLength() {
98
+ return this.#MaxLength;
99
+ }
100
+ #maxLength = FileTransferManager.MaxLength;
101
+ /** kB */
102
+ get maxLength() {
103
+ return this.#maxLength;
104
+ }
105
+ #parseMaxLength(dataView: DataView) {
106
+ _console.log("parseFileMaxLength", dataView);
107
+ const maxLength = dataView.getUint32(0, true);
108
+ _console.log(`maxLength: ${maxLength / 1024}kB`);
109
+ this.#updateMaxLength(maxLength);
110
+ }
111
+ #updateMaxLength(maxLength: number) {
112
+ _console.log({ maxLength });
113
+ this.#maxLength = maxLength;
114
+ this.#dispatchEvent("maxFileLength", { maxFileLength: maxLength });
115
+ }
116
+ #assertValidLength(length: number) {
117
+ _console.assertWithError(
118
+ length <= this.maxLength,
119
+ `file length ${length}kB too large - must be ${this.maxLength}kB or less`
120
+ );
121
+ }
122
+
123
+ #type: FileType | undefined;
124
+ get type() {
125
+ return this.#type;
126
+ }
127
+ #parseType(dataView: DataView) {
128
+ _console.log("parseFileType", dataView);
129
+ const typeEnum = dataView.getUint8(0);
130
+ this.#assertValidTypeEnum(typeEnum);
131
+ const type = FileTypes[typeEnum];
132
+ this.#updateType(type);
133
+ }
134
+ #updateType(type: FileType) {
135
+ _console.log({ fileTransferType: type });
136
+ this.#type = type;
137
+ this.#dispatchEvent("getFileType", { fileType: type });
138
+ }
139
+ async #setType(newType: FileType, sendImmediately?: boolean) {
140
+ this.#assertValidType(newType);
141
+ if (this.type == newType) {
142
+ _console.log(`redundant type assignment ${newType}`);
143
+ return;
144
+ }
145
+
146
+ const promise = this.waitForEvent("getFileType");
147
+
148
+ const typeEnum = FileTypes.indexOf(newType);
149
+ this.sendMessage([{ type: "setFileType", data: Uint8Array.from([typeEnum]).buffer }], sendImmediately);
150
+
151
+ await promise;
152
+ }
153
+
154
+ #length = 0;
155
+ get length() {
156
+ return this.#length;
157
+ }
158
+ #parseLength(dataView: DataView) {
159
+ _console.log("parseFileLength", dataView);
160
+ const length = dataView.getUint32(0, true);
161
+
162
+ this.#updateLength(length);
163
+ }
164
+ #updateLength(length: number) {
165
+ _console.log(`length: ${length / 1024}kB`);
166
+ this.#length = length;
167
+ this.#dispatchEvent("getFileLength", { fileLength: length });
168
+ }
169
+ async #setLength(newLength: number, sendImmediately: boolean) {
170
+ _console.assertTypeWithError(newLength, "number");
171
+ this.#assertValidLength(newLength);
172
+ if (this.length == newLength) {
173
+ _console.log(`redundant length assignment ${newLength}`);
174
+ return;
175
+ }
176
+
177
+ const promise = this.waitForEvent("getFileLength");
178
+
179
+ const dataView = new DataView(new ArrayBuffer(4));
180
+ dataView.setUint32(0, newLength, true);
181
+ this.sendMessage([{ type: "setFileLength", data: dataView.buffer }], sendImmediately);
182
+
183
+ await promise;
184
+ }
185
+
186
+ #checksum = 0;
187
+ get checksum() {
188
+ return this.#checksum;
189
+ }
190
+ #parseChecksum(dataView: DataView) {
191
+ _console.log("checksum", dataView);
192
+ const checksum = dataView.getUint32(0, true);
193
+ this.#updateChecksum(checksum);
194
+ }
195
+ #updateChecksum(checksum: number) {
196
+ _console.log({ checksum });
197
+ this.#checksum = checksum;
198
+ this.#dispatchEvent("getFileChecksum", { fileChecksum: checksum });
199
+ }
200
+ async #setChecksum(newChecksum: number, sendImmediately: boolean) {
201
+ _console.assertTypeWithError(newChecksum, "number");
202
+ if (this.checksum == newChecksum) {
203
+ _console.log(`redundant checksum assignment ${newChecksum}`);
204
+ return;
205
+ }
206
+
207
+ const promise = this.waitForEvent("getFileChecksum");
208
+
209
+ const dataView = new DataView(new ArrayBuffer(4));
210
+ dataView.setUint32(0, newChecksum, true);
211
+ this.sendMessage([{ type: "setFileChecksum", data: dataView.buffer }], sendImmediately);
212
+
213
+ await promise;
214
+ }
215
+
216
+ async #setCommand(command: FileTransferCommand, sendImmediately?: boolean) {
217
+ this.#assertValidCommand(command);
218
+
219
+ const promise = this.waitForEvent("fileTransferStatus");
220
+
221
+ const commandEnum = FileTransferCommands.indexOf(command);
222
+ this.sendMessage(
223
+ [{ type: "setFileTransferCommand", data: Uint8Array.from([commandEnum]).buffer }],
224
+ sendImmediately
225
+ );
226
+
227
+ await promise;
228
+ }
229
+
230
+ #status: FileTransferStatus = "idle";
231
+ get status() {
232
+ return this.#status;
233
+ }
234
+ #parseStatus(dataView: DataView) {
235
+ _console.log("parseFileStatus", dataView);
236
+ const statusEnum = dataView.getUint8(0);
237
+ this.#assertValidStatusEnum(statusEnum);
238
+ const status = FileTransferStatuses[statusEnum];
239
+ this.#updateStatus(status);
240
+ }
241
+ #updateStatus(status: FileTransferStatus) {
242
+ _console.log({ status });
243
+ this.#status = status;
244
+ this.#dispatchEvent("fileTransferStatus", { fileTransferStatus: status });
245
+ this.#receivedBlocks.length = 0;
246
+ }
247
+ #assertIsIdle() {
248
+ _console.assertWithError(this.#status == "idle", "status is not idle");
249
+ }
250
+ #assertIsNotIdle() {
251
+ _console.assertWithError(this.#status != "idle", "status is idle");
252
+ }
253
+
254
+ // BLOCK
255
+
256
+ #receivedBlocks: ArrayBuffer[] = [];
257
+
258
+ async #parseBlock(dataView: DataView) {
259
+ _console.log("parseFileBlock", dataView);
260
+ this.#receivedBlocks.push(dataView.buffer);
261
+
262
+ const bytesReceived = this.#receivedBlocks.reduce((sum, arrayBuffer) => (sum += arrayBuffer.byteLength), 0);
263
+ const progress = bytesReceived / this.#length;
264
+
265
+ _console.log(`received ${bytesReceived} of ${this.#length} bytes (${progress * 100}%)`);
266
+
267
+ this.#dispatchEvent("fileTransferProgress", { progress });
268
+
269
+ if (bytesReceived != this.#length) {
270
+ const dataView = new DataView(new ArrayBuffer(4));
271
+ dataView.setUint32(0, bytesReceived, true);
272
+
273
+ if (this.isServerSide) {
274
+ return;
275
+ }
276
+ await this.sendMessage([{ type: "fileBytesTransferred", data: dataView.buffer }]);
277
+ return;
278
+ }
279
+
280
+ _console.log("file transfer complete");
281
+
282
+ let fileName = new Date().toLocaleString();
283
+ switch (this.type) {
284
+ case "tflite":
285
+ fileName += ".tflite";
286
+ break;
287
+ }
288
+
289
+ let file: File | Blob;
290
+ if (typeof File !== "undefined") {
291
+ file = new File(this.#receivedBlocks, fileName);
292
+ } else {
293
+ file = new Blob(this.#receivedBlocks);
294
+ }
295
+
296
+ const arrayBuffer = await file.arrayBuffer();
297
+ const checksum = crc32(arrayBuffer);
298
+ _console.log({ checksum });
299
+
300
+ if (checksum != this.#checksum) {
301
+ _console.error(`wrong checksum - expected ${this.#checksum}, got ${checksum}`);
302
+ return;
303
+ }
304
+
305
+ _console.log("received file", file);
306
+
307
+ this.#dispatchEvent("getFileBlock", { fileTransferBlock: dataView });
308
+ this.#dispatchEvent("fileTransferComplete", { direction: "receiving" });
309
+ this.#dispatchEvent("fileReceived", { file });
310
+ }
311
+
312
+ parseMessage(messageType: FileTransferMessageType, dataView: DataView) {
313
+ _console.log({ messageType });
314
+
315
+ switch (messageType) {
316
+ case "maxFileLength":
317
+ this.#parseMaxLength(dataView);
318
+ break;
319
+ case "getFileType":
320
+ case "setFileType":
321
+ this.#parseType(dataView);
322
+ break;
323
+ case "getFileLength":
324
+ case "setFileLength":
325
+ this.#parseLength(dataView);
326
+ break;
327
+ case "getFileChecksum":
328
+ case "setFileChecksum":
329
+ this.#parseChecksum(dataView);
330
+ break;
331
+ case "fileTransferStatus":
332
+ this.#parseStatus(dataView);
333
+ break;
334
+ case "getFileBlock":
335
+ this.#parseBlock(dataView);
336
+ break;
337
+ case "fileBytesTransferred":
338
+ this.#parseBytesTransferred(dataView);
339
+ break;
340
+ default:
341
+ throw Error(`uncaught messageType ${messageType}`);
342
+ }
343
+ }
344
+
345
+ async send(type: FileType, file: FileLike) {
346
+ this.#assertIsIdle();
347
+
348
+ this.#assertValidType(type);
349
+ const fileBuffer = await getFileBuffer(file);
350
+
351
+ const promises: Promise<any>[] = [];
352
+
353
+ promises.push(this.#setType(type, false));
354
+ const fileLength = fileBuffer.byteLength;
355
+ promises.push(this.#setLength(fileLength, false));
356
+ const checksum = crc32(fileBuffer);
357
+ promises.push(this.#setChecksum(checksum, false));
358
+ promises.push(this.#setCommand("startSend", false));
359
+
360
+ this.sendMessage();
361
+
362
+ await Promise.all(promises);
363
+
364
+ await this.#send(fileBuffer);
365
+ }
366
+
367
+ #buffer?: ArrayBuffer;
368
+ #bytesTransferred = 0;
369
+ async #send(buffer: ArrayBuffer) {
370
+ this.#buffer = buffer;
371
+ this.#bytesTransferred = 0;
372
+ return this.#sendBlock();
373
+ }
374
+
375
+ mtu!: number;
376
+ async #sendBlock(): Promise<void> {
377
+ if (this.status != "sending") {
378
+ return;
379
+ }
380
+ if (!this.#buffer) {
381
+ _console.error("no buffer defined");
382
+ return;
383
+ }
384
+
385
+ const buffer = this.#buffer;
386
+ let offset = this.#bytesTransferred;
387
+
388
+ const slicedBuffer = buffer.slice(offset, offset + (this.mtu - 3 - 3));
389
+ _console.log("slicedBuffer", slicedBuffer);
390
+ const bytesLeft = buffer.byteLength - offset;
391
+
392
+ const progress = 1 - bytesLeft / buffer.byteLength;
393
+ _console.log(
394
+ `sending bytes ${offset}-${offset + slicedBuffer.byteLength} of ${buffer.byteLength} bytes (${progress * 100}%)`
395
+ );
396
+ this.#dispatchEvent("fileTransferProgress", { progress });
397
+ if (slicedBuffer.byteLength == 0) {
398
+ _console.log("finished sending buffer");
399
+ this.#dispatchEvent("fileTransferComplete", { direction: "sending" });
400
+ } else {
401
+ await this.sendMessage([{ type: "setFileBlock", data: slicedBuffer }]);
402
+ this.#bytesTransferred = offset + slicedBuffer.byteLength;
403
+ //return this.#sendBlock(buffer, offset + slicedBuffer.byteLength);
404
+ }
405
+ }
406
+
407
+ async #parseBytesTransferred(dataView: DataView) {
408
+ _console.log("parseBytesTransferred", dataView);
409
+ const bytesTransferred = dataView.getUint32(0, true);
410
+ _console.log({ bytesTransferred });
411
+ if (this.status != "sending") {
412
+ _console.error(`not currently sending file`);
413
+ return;
414
+ }
415
+ if (!this.isServerSide && this.#bytesTransferred != bytesTransferred) {
416
+ _console.error(`bytesTransferred are not equal - got ${bytesTransferred}, expected ${this.#bytesTransferred}`);
417
+ this.cancel();
418
+ return;
419
+ }
420
+ this.#sendBlock();
421
+ }
422
+
423
+ async receive(type: FileType) {
424
+ this.#assertIsIdle();
425
+
426
+ this.#assertValidType(type);
427
+
428
+ await this.#setType(type);
429
+ await this.#setCommand("startReceive");
430
+ }
431
+
432
+ async cancel() {
433
+ this.#assertIsNotIdle();
434
+ await this.#setCommand("cancel");
435
+ }
436
+
437
+ // SERVER SIDE
438
+ #isServerSide = false;
439
+ get isServerSide() {
440
+ return this.#isServerSide;
441
+ }
442
+ set isServerSide(newIsServerSide) {
443
+ if (this.#isServerSide == newIsServerSide) {
444
+ _console.log("redundant isServerSide assignment");
445
+ return;
446
+ }
447
+ _console.log({ newIsServerSide });
448
+ this.#isServerSide = newIsServerSide;
449
+ }
450
+ }
451
+
452
+ export default FileTransferManager;