js-dos 7.4.9 → 8.1.0

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 (155) hide show
  1. package/.github/workflows/build.yml +51 -0
  2. package/.gitmodules +4 -0
  3. package/README.deployment.md +11 -0
  4. package/README.md +29 -89
  5. package/index.html +106 -0
  6. package/package.json +46 -71
  7. package/postcss.config.cjs +8 -0
  8. package/src/app.css +14 -0
  9. package/src/base.css +10 -0
  10. package/src/components/checkbox.tsx +41 -0
  11. package/src/components/close-button.tsx +17 -0
  12. package/src/components/components.css +28 -0
  13. package/src/components/dos-option-checkbox.tsx +94 -0
  14. package/src/components/dos-option-select.tsx +108 -0
  15. package/src/components/dos-option-slider.tsx +35 -0
  16. package/src/components/error.tsx +16 -0
  17. package/src/components/loading.tsx +26 -0
  18. package/src/components/lock.tsx +10 -0
  19. package/src/components/select.tsx +33 -0
  20. package/src/components/slider.tsx +69 -0
  21. package/src/download-file.ts +18 -0
  22. package/src/frame/account-frame.tsx +156 -0
  23. package/src/frame/editor/defaults.ts +419 -0
  24. package/src/frame/editor/editor-conf-frame.tsx +226 -0
  25. package/src/frame/editor/editor-frame.css +55 -0
  26. package/src/frame/editor/editor-fs-frame.tsx +314 -0
  27. package/src/frame/fat-drives-frame.tsx +135 -0
  28. package/src/frame/frame.css +119 -0
  29. package/src/frame/frame.tsx +34 -0
  30. package/src/frame/image-rendering-frame.tsx +8 -0
  31. package/src/frame/network-frame.tsx +157 -0
  32. package/src/frame/quick-save-frame.tsx +96 -0
  33. package/src/frame/settings-frame.tsx +14 -0
  34. package/src/frame/stats-frame.tsx +87 -0
  35. package/src/host/bundle-storage.ts +91 -0
  36. package/src/host/fullscreen.ts +35 -0
  37. package/src/host/lcache.ts +203 -0
  38. package/src/host/lstorage.ts +156 -0
  39. package/src/i18n.ts +179 -0
  40. package/src/index.css +7 -0
  41. package/src/load.ts +132 -0
  42. package/src/login/login.css +9 -0
  43. package/src/login/login.tsx +77 -0
  44. package/src/main.tsx +197 -0
  45. package/src/public/types.ts +41 -0
  46. package/src/sidebar/account-button.tsx +33 -0
  47. package/src/sidebar/cloud-save-button.tsx +89 -0
  48. package/src/sidebar/diskette-icon.tsx +14 -0
  49. package/src/sidebar/fullscreen-button.tsx +44 -0
  50. package/src/sidebar/network-button.tsx +39 -0
  51. package/src/sidebar/sidebar-button.tsx +244 -0
  52. package/src/sidebar/sidebar.css +47 -0
  53. package/src/sidebar/sidebar.tsx +30 -0
  54. package/src/sockdrive/LICENSE +674 -0
  55. package/src/sockdrive/README.md +45 -0
  56. package/src/sockdrive/include/sockdrive.h +23 -0
  57. package/src/sockdrive/js/.eslintrc.json +43 -0
  58. package/src/sockdrive/js/package.json +29 -0
  59. package/src/sockdrive/js/src/fatfs/chains.js +318 -0
  60. package/src/sockdrive/js/src/fatfs/dir.js +385 -0
  61. package/src/sockdrive/js/src/fatfs/helpers.js +210 -0
  62. package/src/sockdrive/js/src/fatfs/index.js +606 -0
  63. package/src/sockdrive/js/src/fatfs/structs.js +255 -0
  64. package/src/sockdrive/js/src/fatfs/vol.js +166 -0
  65. package/src/sockdrive/js/src/sockdrive/cache.ts +133 -0
  66. package/src/sockdrive/js/src/sockdrive/drive.ts +457 -0
  67. package/src/sockdrive/js/src/sockdrive/lru.ts +221 -0
  68. package/src/sockdrive/js/src/sockdrive/types.ts +14 -0
  69. package/src/sockdrive/js/src/sockdrive-fat.d.ts +64 -0
  70. package/src/sockdrive/js/src/sockdrive-fat.ts +226 -0
  71. package/src/sockdrive/js/src/sockdrive-native.ts +100 -0
  72. package/src/sockdrive/js/src/test/test.ts +288 -0
  73. package/src/sockdrive/js/tsconfig.json +11 -0
  74. package/src/sockdrive/js/webpack.config.js +68 -0
  75. package/src/sockdrive/js/yarn.lock +1808 -0
  76. package/src/store/auth.ts +115 -0
  77. package/src/store/dos.ts +305 -0
  78. package/src/store/editor.ts +61 -0
  79. package/src/store/init.ts +48 -0
  80. package/src/store/storage.ts +32 -0
  81. package/src/store/ui.ts +186 -0
  82. package/src/store.tsx +108 -0
  83. package/src/ui.tsx +104 -0
  84. package/src/v8/changes.ts +56 -0
  85. package/src/v8/config.ts +18 -0
  86. package/src/v8/subscriptions.ts +62 -0
  87. package/src/vite-env.d.ts +2 -0
  88. package/src/window/dos/controls/keyboard.ts +32 -0
  89. package/src/window/dos/controls/keys.ts +331 -0
  90. package/src/window/dos/controls/mouse/mount.ts +99 -0
  91. package/src/window/dos/controls/mouse/mouse-locked.ts +51 -0
  92. package/src/window/dos/controls/mouse/mouse-not-locked.ts +84 -0
  93. package/src/window/dos/controls/mouse/mouse-swipe.ts +57 -0
  94. package/src/window/dos/controls/mouse/pointer.ts +85 -0
  95. package/src/window/dos/controls/mouse.ts +21 -0
  96. package/src/window/dos/dos-dhry2.tsx +191 -0
  97. package/src/window/dos/dos-runtime.tsx +214 -0
  98. package/src/window/dos/dos-window.tsx +84 -0
  99. package/src/window/dos/render/canvas.ts +65 -0
  100. package/src/window/dos/render/resize.ts +31 -0
  101. package/src/window/dos/render/webgl.ts +173 -0
  102. package/src/window/dos/sound/audio-node.ts +148 -0
  103. package/src/window/error-window.tsx +9 -0
  104. package/src/window/loading-window.tsx +54 -0
  105. package/src/window/prerun-window.tsx +123 -0
  106. package/src/window/select-window.tsx +118 -0
  107. package/src/window/window.css +78 -0
  108. package/src/window/window.tsx +49 -0
  109. package/src/ws/ws-sockdrive.ts +101 -0
  110. package/src/ws/ws-transport-layer.ts +455 -0
  111. package/tailwind.config.cjs +48 -0
  112. package/tsconfig.json +32 -0
  113. package/tsconfig.node.json +9 -0
  114. package/vite.config.ts +22 -0
  115. package/LICENSE +0 -339
  116. package/dist/emulators-ui-loader.png +0 -0
  117. package/dist/js-dos.css +0 -1690
  118. package/dist/js-dos.js +0 -17
  119. package/dist/js-dos.js.map +0 -1
  120. package/dist/types/src/backend/v7/latency.d.ts +0 -8
  121. package/dist/types/src/backend/v7/personal.d.ts +0 -2
  122. package/dist/types/src/backend/v7/v7-config.d.ts +0 -16
  123. package/dist/types/src/components/action-bar.d.ts +0 -2
  124. package/dist/types/src/components/action-hide.d.ts +0 -4
  125. package/dist/types/src/components/action-save-or-exit.d.ts +0 -4
  126. package/dist/types/src/components/client.d.ts +0 -6
  127. package/dist/types/src/components/controls.d.ts +0 -8
  128. package/dist/types/src/components/cpu-control.d.ts +0 -2
  129. package/dist/types/src/components/horizontal-slider.d.ts +0 -13
  130. package/dist/types/src/components/region.d.ts +0 -6
  131. package/dist/types/src/components/scale-control.d.ts +0 -3
  132. package/dist/types/src/components/sensitivity-control.d.ts +0 -3
  133. package/dist/types/src/components/sidebar/latency-info.d.ts +0 -7
  134. package/dist/types/src/components/sidebar/main.d.ts +0 -2
  135. package/dist/types/src/components/sidebar/networking.d.ts +0 -2
  136. package/dist/types/src/components/sidebar/token/token-add-time.d.ts +0 -2
  137. package/dist/types/src/components/sidebar/token/token-select.d.ts +0 -2
  138. package/dist/types/src/components/sidebar/token/token.d.ts +0 -17
  139. package/dist/types/src/components/sidebar.d.ts +0 -2
  140. package/dist/types/src/components/sync-control.d.ts +0 -2
  141. package/dist/types/src/components/tip.d.ts +0 -2
  142. package/dist/types/src/components/vertical-slider.d.ts +0 -12
  143. package/dist/types/src/components/volume-control.d.ts +0 -3
  144. package/dist/types/src/dom.d.ts +0 -8
  145. package/dist/types/src/hardware-transport-layer.d.ts +0 -18
  146. package/dist/types/src/icons.d.ts +0 -95
  147. package/dist/types/src/player-app.d.ts +0 -50
  148. package/dist/types/src/player.d.ts +0 -29
  149. package/dist/types/src/request.d.ts +0 -1
  150. package/dist/types/src/xhr.d.ts +0 -6
  151. package/dist/types/v7-services/src/personal.d.ts +0 -3
  152. package/dist/wdosbox.js +0 -55
  153. package/dist/wdosbox.js.symbols +0 -3174
  154. package/dist/wdosbox.wasm +0 -0
  155. package/examples/digger/index.html +0 -71
@@ -0,0 +1,457 @@
1
+ import { EmModule, Ptr, Stats } from "./types";
2
+ import { BlockCache, Cache } from "./cache";
3
+
4
+ const MAX_FRAME_SIZE = 1 * 1024 * 1024;
5
+ const MEMORY_LIMIT = 64 * 1024 * 1024;
6
+
7
+ interface Request {
8
+ type: 1 | 2, // read | write
9
+ sectors: number[],
10
+ buffer: Ptr | Uint8Array,
11
+ resolve: (result: number) => void,
12
+ }
13
+
14
+ export class Drive {
15
+ module: EmModule;
16
+ sectorSize: number;
17
+ endpoint: string;
18
+ owner: string;
19
+ drive: string;
20
+ token: string;
21
+ stats: Stats;
22
+
23
+ socket: Promise<WebSocket> = Promise.resolve(null as any);
24
+ request: Request | null;
25
+ pendingRequest: Request | null;
26
+
27
+ aheadRange: number = 0;
28
+ aheadSize: number = 0;
29
+ writeBuffer: Uint8Array;
30
+
31
+ maxRead: number = 0;
32
+ readBuffer: Uint8Array = new Uint8Array(0);
33
+ readAheadBuffer: Uint8Array = new Uint8Array(0);
34
+ readAheadPos = 0;
35
+ readAheadCompressed = 0;
36
+ readStartedAt: number = 0;
37
+ decodeBuffer: Uint8Array = new Uint8Array(0);
38
+
39
+ cache: Cache | null = null;
40
+ cleanup = () => {/**/};
41
+
42
+ openFn = (read: boolean, write: boolean, size: number, preloadQueue: number[]) => {/**/};
43
+ preloadProgressFn = (restBytes: number) => {/**/};
44
+ errorFn = (e: Error) => {/**/};
45
+
46
+ retries: number;
47
+
48
+ preloadSectors: boolean;
49
+ preloadQueue: number[] = [];
50
+
51
+ public constructor(endpoint: string,
52
+ owner: string,
53
+ drive: string,
54
+ token: string,
55
+ stats: Stats,
56
+ module: EmModule,
57
+ preloadSectors = true) {
58
+ this.sectorSize = 512;
59
+ this.module = module;
60
+ this.endpoint = endpoint;
61
+ this.owner = owner;
62
+ this.drive = drive;
63
+ this.token = token;
64
+ this.request = null;
65
+ this.pendingRequest = null;
66
+ this.writeBuffer = new Uint8Array(1 + 4 + this.sectorSize);
67
+ this.stats = stats;
68
+ this.retries = 3;
69
+ this.preloadSectors = preloadSectors;
70
+
71
+ this.reconnect();
72
+ }
73
+
74
+ public onError(errorFn: (e: Error) => void) {
75
+ this.errorFn = errorFn;
76
+ }
77
+
78
+ public onOpen(openFn: (read: boolean, write: boolean, imageSize: number, preloadQueue: number[]) => void) {
79
+ this.openFn = openFn;
80
+ }
81
+
82
+ public onPreloadProgress(progressFn: (restBytes: number) => void) {
83
+ this.preloadProgressFn = progressFn;
84
+ }
85
+
86
+ public reconnect(): void {
87
+ this.socket = new Promise<WebSocket>((resolve, reject) => {
88
+ const socket = new WebSocket(this.endpoint);
89
+ socket.binaryType = "arraybuffer";
90
+ const onMessage = this.onMessage.bind(this);
91
+ const onOpen = () => {
92
+ const onInit = (event: { data: string }) => {
93
+ socket.removeEventListener("message", onInit);
94
+ if (event.data.startsWith("write") || event.data.startsWith("read")) {
95
+ const [mode, aheadRangeStr, sizeStr] = event.data.split(",");
96
+ const aheadRange = Number.parseInt(aheadRangeStr);
97
+ this.aheadRange = aheadRange;
98
+ this.aheadSize = aheadRange * this.sectorSize;
99
+ this.maxRead = Math.floor(MAX_FRAME_SIZE / this.aheadSize);
100
+
101
+ const decodeBufferSize = this.aheadSize * this.maxRead;
102
+ this.readBuffer = new Uint8Array(1 + 4 + this.maxRead * 4);
103
+ this.readAheadBuffer = new Uint8Array(decodeBufferSize);
104
+ this.decodeBuffer = new Uint8Array(decodeBufferSize);
105
+ this.cache = new BlockCache(this.sectorSize, aheadRange, MEMORY_LIMIT);
106
+
107
+ let preloadLength = 0;
108
+ let preloadPos = 0;
109
+ let preload: Uint8Array = new Uint8Array(0);
110
+ const onPreloadMessage = (event: { data: ArrayBuffer }) => {
111
+ let data = new Uint8Array(event.data);
112
+ if (preloadLength === 0) {
113
+ preloadLength = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24);
114
+ preload = new Uint8Array(preloadLength - 4);
115
+ data = data.slice(4);
116
+ }
117
+
118
+ if (preloadPos < preloadLength) {
119
+ preload.set(data, preloadPos);
120
+ preloadPos += data.length;
121
+ }
122
+
123
+ if (preloadPos > preload.length) {
124
+ const error = new Error("Preload buffer is bigger then expected");
125
+ this.errorFn(error);
126
+ reject(error);
127
+ } else if (preloadPos == preload.length) {
128
+ this.preloadQueue = [];
129
+ if (this.preloadSectors) {
130
+ for (let i = 0; i < preload.length; i += 4) {
131
+ this.preloadQueue.push(preload[i] + (preload[i + 1] << 8) +
132
+ (preload[i + 2] << 16) + (preload[i + 3] << 24));
133
+ }
134
+ }
135
+ socket.removeEventListener("message", onPreloadMessage);
136
+ socket.addEventListener("message", onMessage);
137
+ this.openFn(true, mode === "write",
138
+ (Number.parseInt(sizeStr) ?? 2 * 1024 * 1024) * 1024,
139
+ this.preloadQueue);
140
+ resolve(socket);
141
+
142
+ if (this.preloadQueue.length > 0) {
143
+ if (this.preloadQueue.length * this.aheadSize > MEMORY_LIMIT) {
144
+ console.log("WARN! preloadQueue size is bigger then allowed",
145
+ this.preloadQueue.length * this.aheadSize / 1024 / 1024, ">",
146
+ MEMORY_LIMIT / 1024 / 1024);
147
+ this.preloadQueue = this.preloadQueue
148
+ .slice(0, Math.floor(MEMORY_LIMIT / this.aheadSize));
149
+ }
150
+ this.request = this.makeReadRequest(this.preloadQueue.shift()!);
151
+ this.executeRequest(this.request);
152
+ }
153
+ }
154
+ };
155
+ socket.addEventListener("message", onPreloadMessage);
156
+ } else {
157
+ const error = new Error(event.data ?? "Unable to establish connection");
158
+ this.errorFn(error);
159
+ reject(error);
160
+ }
161
+ };
162
+ socket.addEventListener("message", onInit);
163
+ socket.send(this.owner + "&" + this.drive + "&" + this.token);
164
+ };
165
+ const onError = (e: Event) => {
166
+ console.error("Network error", e, "will reconnect");
167
+ cleanup();
168
+ socket.close();
169
+ this.retries--;
170
+ if (this.retries === 0) {
171
+ const error = new Error("Network problem");
172
+ this.errorFn(error);
173
+ reject(error);
174
+ } else {
175
+ setTimeout(this.reconnect.bind(this), 300);
176
+ }
177
+ };
178
+ socket.addEventListener("error", onError);
179
+ socket.addEventListener("open", onOpen);
180
+ const cleanup = function() {
181
+ socket.removeEventListener("message", onMessage);
182
+ socket.removeEventListener("open", onOpen);
183
+ socket.removeEventListener("error", onError);
184
+ };
185
+ this.cleanup = cleanup;
186
+ });
187
+
188
+ if (this.request !== null) {
189
+ this.executeRequest(this.request);
190
+ }
191
+ }
192
+
193
+ private makeReadRequest(sector: number, buffer: number = -1, resolve: (res: number) => void = () => { }): Request {
194
+ const sectors: number[] = [sector];
195
+ if (this.preloadQueue.length > 0) {
196
+ this.preloadProgressFn(this.preloadQueue.length * this.aheadSize);
197
+ while (this.preloadQueue.length > 0 && sectors.length < this.maxRead) {
198
+ const preload = this.preloadQueue.shift()!;
199
+ if (preload !== sector) {
200
+ sectors.push(preload);
201
+ }
202
+ }
203
+ for (let i = 0; i < this.preloadQueue.length; ++i) {
204
+ if (this.preloadQueue[i] == sector) {
205
+ this.preloadQueue.splice(i, 1);
206
+ break;
207
+ }
208
+ }
209
+ }
210
+ return {
211
+ type: 1,
212
+ sectors,
213
+ buffer,
214
+ resolve,
215
+ };
216
+ }
217
+
218
+ public read(sector: number, buffer: Ptr, sync: boolean): Promise<number> | number {
219
+ const cached = this.cache!.read(sector);
220
+ if (cached !== null) {
221
+ if (sync) {
222
+ this.stats.cacheHit++;
223
+ }
224
+ this.module.HEAPU8.set(cached, buffer);
225
+ return sync ? 0 : Promise.resolve(0);
226
+ } else if (sync) {
227
+ return 255;
228
+ } else {
229
+ return new Promise<number>((resolve) => {
230
+ this.stats.cacheMiss++;
231
+
232
+ const request: Request = this.makeReadRequest(sector, buffer, resolve);
233
+ if (this.request !== null) {
234
+ if (this.pendingRequest === null) {
235
+ this.pendingRequest = request;
236
+ } else {
237
+ console.error("New read request while old one is still processed");
238
+ resolve(3);
239
+ }
240
+ } else {
241
+ this.request = request;
242
+ this.executeRequest(this.request);
243
+ }
244
+ });
245
+ }
246
+ }
247
+
248
+ public write(sector: number, buffer: Ptr): number {
249
+ const request: Request = {
250
+ type: 2,
251
+ sectors: [sector],
252
+ buffer: this.module.HEAPU8.slice(buffer, buffer + this.sectorSize),
253
+ resolve: () => {/**/},
254
+ };
255
+ this.cache!.write(sector, request.buffer as Uint8Array);
256
+ this.executeRequest(request);
257
+ return 0;
258
+ }
259
+
260
+ public async close() {
261
+ const socket = await this.socket;
262
+ await new Promise<void>((resolve) => {
263
+ const intervalId = setInterval(() => {
264
+ if (socket.bufferedAmount === 0) {
265
+ clearInterval(intervalId);
266
+ resolve();
267
+ }
268
+ }, 32);
269
+ });
270
+ this.cleanup();
271
+ socket.close();
272
+ }
273
+
274
+ private executeRequest(request: Request) {
275
+ this.socket.then((socket) => {
276
+ if (request.type === 1) {
277
+ const { sectors } = request;
278
+ this.readStartedAt = Date.now();
279
+ this.readAheadPos = 0;
280
+ this.readAheadCompressed = 0;
281
+ this.readBuffer[0] = 1; // read
282
+ this.readBuffer[1] = sectors.length & 0xFF;
283
+ this.readBuffer[2] = (sectors.length >> 8) & 0xFF;
284
+ this.readBuffer[3] = (sectors.length >> 16) & 0xFF;
285
+ this.readBuffer[4] = (sectors.length >> 24) & 0xFF;
286
+
287
+ for (let i = 0; i < sectors.length; ++i) {
288
+ const origin = this.cache!.getOrigin(sectors[i]);
289
+
290
+ if (i > 0 && origin !== sectors[i]) {
291
+ console.error("Assertion failed orign should equal to sector", origin, sectors[i]);
292
+ request.resolve(5);
293
+ return;
294
+ }
295
+
296
+ this.readBuffer[5 + i * 4] = origin & 0xFF;
297
+ this.readBuffer[5 + i * 4 + 1] = (origin >> 8) & 0xFF;
298
+ this.readBuffer[5 + i * 4 + 2] = (origin >> 16) & 0xFF;
299
+ this.readBuffer[5 + i * 4 + 3] = (origin >> 24) & 0xFF;
300
+ }
301
+ socket.send(this.readBuffer.slice(0, sectors.length * 4 + 5).buffer);
302
+ } else {
303
+ const { sectors, buffer, resolve } = request;
304
+ this.stats.write += this.sectorSize;
305
+ this.writeBuffer[0] = 2; // write
306
+ this.writeBuffer[1] = sectors[0] & 0xFF;
307
+ this.writeBuffer[2] = (sectors[0] >> 8) & 0xFF;
308
+ this.writeBuffer[3] = (sectors[0] >> 16) & 0xFF;
309
+ this.writeBuffer[4] = (sectors[0] >> 24) & 0xFF;
310
+ // TBD: maybe do not copy and send just slice ???
311
+ this.writeBuffer.set(buffer as Uint8Array, 5);
312
+ socket.send(this.writeBuffer.buffer);
313
+ resolve(0);
314
+ }
315
+ });
316
+ }
317
+
318
+ public onMessage(event: { data: ArrayBuffer }) {
319
+ if (this.request === null) {
320
+ console.error("Received message without request");
321
+ this.reconnect();
322
+ } else if (this.request.type === 2) {
323
+ console.error("Received read payload while write request");
324
+ this.reconnect();
325
+ } else if (event.data instanceof ArrayBuffer) {
326
+ let data = new Uint8Array(event.data);
327
+ if (this.readAheadCompressed === 0) {
328
+ this.readAheadCompressed = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24);
329
+ data = data.slice(4);
330
+ }
331
+
332
+ const { sectors, buffer, resolve } = this.request;
333
+ const restLength = this.readAheadCompressed - this.readAheadPos;
334
+ if (data.byteLength > restLength || restLength < 0) {
335
+ console.error("wrong read payload length " + data.byteLength + " instead of " + restLength);
336
+ resolve(3);
337
+ } else {
338
+ this.readAheadBuffer.set(data, this.readAheadPos);
339
+ this.readAheadPos += data.byteLength;
340
+ const expectedSize = this.aheadSize * sectors.length;
341
+
342
+ if (this.readAheadPos == this.readAheadCompressed) {
343
+ let decodeResult = expectedSize;
344
+ if (this.readAheadCompressed < expectedSize) {
345
+ const result = decodeLz4(this.readAheadBuffer, this.decodeBuffer, 0, this.readAheadCompressed);
346
+ if (result < 0) {
347
+ decodeResult = result;
348
+ } else {
349
+ this.readAheadBuffer.set(this.decodeBuffer.slice(0, expectedSize), 0);
350
+ }
351
+ }
352
+
353
+ if (decodeResult != expectedSize) {
354
+ console.error("wrong decode result " + decodeResult + " should be " + expectedSize);
355
+ resolve(4);
356
+ } else {
357
+ for (let i = 0; i < sectors.length; ++i) {
358
+ const aheadOffset = i * this.aheadSize;
359
+ const sector = sectors[i];
360
+ const origin = this.cache!.getOrigin(sector);
361
+ this.cache!.create(origin,
362
+ this.readAheadBuffer.slice(aheadOffset, aheadOffset + this.aheadSize));
363
+ if (i == 0 && buffer as number >= 0) {
364
+ const offset = sector - origin;
365
+ // aheadOffset is zero
366
+ this.module.HEAPU8.set(this.readAheadBuffer.slice(offset * this.sectorSize,
367
+ (offset + 1) * this.sectorSize), buffer as number);
368
+ }
369
+ }
370
+
371
+ this.stats.cacheUsed = this.cache!.memUsed();
372
+ this.stats.read += this.readAheadCompressed;
373
+ this.stats.readTotalTime += Date.now() - this.readStartedAt;
374
+ this.request = null;
375
+ resolve(0);
376
+
377
+ if (this.pendingRequest !== null) {
378
+ this.request = this.pendingRequest;
379
+ this.pendingRequest = null;
380
+ this.executeRequest(this.request);
381
+ } else if (this.preloadQueue.length > 0) {
382
+ this.request = this.makeReadRequest(this.preloadQueue.shift()!);
383
+ this.executeRequest(this.request);
384
+ }
385
+ }
386
+ }
387
+ }
388
+ } else {
389
+ console.error("Received non arraybuffer data");
390
+ this.reconnect();
391
+ }
392
+ }
393
+ }
394
+
395
+ /**
396
+ * Decode a block. Assumptions: input contains all sequences of a
397
+ * chunk, output is large enough to receive the decoded data.
398
+ * If the output buffer is too small, an error will be thrown.
399
+ * If the returned value is negative, an error occured at the returned offset.
400
+ *
401
+ * @param {ArrayBufferView} input input data
402
+ * @param {ArrayBufferView} output output data
403
+ * @param {number=} sIdx
404
+ * @param {number=} eIdx
405
+ * @return {number} number of decoded bytes
406
+ * @private
407
+ */
408
+ function decodeLz4(input: Uint8Array, output: Uint8Array, sIdx: number, eIdx: number) {
409
+ sIdx = sIdx || 0;
410
+ eIdx = eIdx || (input.length - sIdx);
411
+ // Process each sequence in the incoming data
412
+ let i; let n; let j;
413
+ for (i = sIdx, n = eIdx, j = 0; i < n;) {
414
+ const token = input[i++];
415
+
416
+ // Literals
417
+ let literalsLength = (token >> 4);
418
+ if (literalsLength > 0) {
419
+ // length of literals
420
+ let l = literalsLength + 240;
421
+ while (l === 255) {
422
+ l = input[i++];
423
+ literalsLength += l;
424
+ }
425
+
426
+ // Copy the literals
427
+ const end = i + literalsLength;
428
+ while (i < end) output[j++] = input[i++];
429
+
430
+ // End of buffer?
431
+ if (i === n) return j;
432
+ }
433
+
434
+ // Match copy
435
+ // 2 bytes offset (little endian)
436
+ const offset = input[i++] | (input[i++] << 8);
437
+
438
+ // XXX 0 is an invalid offset value
439
+ if (offset === 0) return j;
440
+ if (offset > j) return -(i - 2);
441
+
442
+ // length of match copy
443
+ let matchLength = (token & 0xf);
444
+ let l = matchLength + 240;
445
+ while (l === 255) {
446
+ l = input[i++];
447
+ matchLength += l;
448
+ }
449
+
450
+ // Copy the match
451
+ let pos = j - offset; // position of the match copy in the current output
452
+ const end = j + matchLength + 4; // minmatch = 4
453
+ while (j < end) output[j++] = output[pos++];
454
+ }
455
+
456
+ return j;
457
+ };
@@ -0,0 +1,221 @@
1
+ /* eslint-disable */
2
+
3
+ // This code is from https://github.com/rsms/js-lru
4
+
5
+ /**
6
+ * A doubly linked list-based Least Recently Used (LRU) cache. Will keep most
7
+ * recently used items while discarding least recently used items when its limit
8
+ * is reached.
9
+ *
10
+ * Licensed under MIT. Copyright (c) 2010 Rasmus Andersson <http://hunch.se/>
11
+ * See README.md for details.
12
+ *
13
+ * Illustration of the design:
14
+ *
15
+ * entry entry entry entry
16
+ * ______ ______ ______ ______
17
+ * | head |.newer => | |.newer => | |.newer => | tail |
18
+ * | A | | B | | C | | D |
19
+ * |______| <= older.|______| <= older.|______| <= older.|______|
20
+ *
21
+ * removed <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- added
22
+ */
23
+ const NEWER = Symbol("newer");
24
+ const OLDER = Symbol("older");
25
+
26
+ export class LRUMap {
27
+ size: number;
28
+ limit: number;
29
+ newest: any;
30
+ oldest: any;
31
+ _keymap: Map<any, any>;
32
+
33
+ constructor(limit: number, entries?: any) {
34
+ if (typeof limit !== "number") {
35
+ // called as (entries)
36
+ entries = limit;
37
+ limit = 0;
38
+ }
39
+
40
+ this.size = 0;
41
+ this.limit = limit;
42
+ this.oldest = this.newest = undefined;
43
+ this._keymap = new Map();
44
+
45
+ if (entries) {
46
+ this.assign(entries);
47
+ if (limit < 1) {
48
+ this.limit = this.size;
49
+ }
50
+ }
51
+ }
52
+
53
+ _markEntryAsUsed(entry: any) {
54
+ if (entry === this.newest) {
55
+ // Already the most recenlty used entry, so no need to update the list
56
+ return;
57
+ }
58
+ // HEAD--------------TAIL
59
+ // <.older .newer>
60
+ // <--- add direction --
61
+ // A B C <D> E
62
+ if (entry[NEWER]) {
63
+ if (entry === this.oldest) {
64
+ this.oldest = entry[NEWER];
65
+ }
66
+ entry[NEWER][OLDER] = entry[OLDER]; // C <-- E.
67
+ }
68
+ if (entry[OLDER]) {
69
+ entry[OLDER][NEWER] = entry[NEWER]; // C. --> E
70
+ }
71
+ entry[NEWER] = undefined; // D --x
72
+ entry[OLDER] = this.newest; // D. --> E
73
+ if (this.newest) {
74
+ this.newest[NEWER] = entry; // E. <-- D
75
+ }
76
+ this.newest = entry;
77
+ }
78
+
79
+ assign(entries: any) {
80
+ let entry; let limit = this.limit || Number.MAX_VALUE;
81
+ this._keymap.clear();
82
+ const it = entries[Symbol.iterator]();
83
+ for (let itv = it.next(); !itv.done; itv = it.next()) {
84
+ const e = new (Entry as any)(itv.value[0], itv.value[1]);
85
+ this._keymap.set(e.key, e);
86
+ if (!entry) {
87
+ this.oldest = e;
88
+ } else {
89
+ entry[NEWER] = e;
90
+ e[OLDER] = entry;
91
+ }
92
+ entry = e;
93
+ if (limit-- == 0) {
94
+ throw new Error("overflow");
95
+ }
96
+ }
97
+ this.newest = entry;
98
+ this.size = this._keymap.size;
99
+ }
100
+
101
+ get(key: any) {
102
+ // First, find our cache entry
103
+ const entry = this._keymap.get(key);
104
+ if (!entry) return; // Not cached. Sorry.
105
+ // As <key> was found in the cache, register it as being requested recently
106
+ this._markEntryAsUsed(entry);
107
+ return entry.value;
108
+ }
109
+
110
+ set(key: any, value: any) {
111
+ let entry = this._keymap.get(key);
112
+
113
+ if (entry) {
114
+ // update existing
115
+ entry.value = value;
116
+ this._markEntryAsUsed(entry);
117
+ return this;
118
+ }
119
+
120
+ // new entry
121
+ this._keymap.set(key, (entry = new (Entry as any)(key, value)));
122
+
123
+ if (this.newest) {
124
+ // link previous tail to the new tail (entry)
125
+ this.newest[NEWER] = entry;
126
+ entry[OLDER] = this.newest;
127
+ } else {
128
+ // we're first in -- yay
129
+ this.oldest = entry;
130
+ }
131
+
132
+ // add new entry to the end of the linked list -- it's now the freshest entry.
133
+ this.newest = entry;
134
+ ++this.size;
135
+ if (this.size > this.limit) {
136
+ // we hit the limit -- remove the head
137
+ this.shift();
138
+ }
139
+
140
+ return this;
141
+ }
142
+
143
+ shift() {
144
+ // todo: handle special case when limit == 1
145
+ const entry = this.oldest;
146
+ if (entry) {
147
+ if (this.oldest[NEWER]) {
148
+ // advance the list
149
+ this.oldest = this.oldest[NEWER];
150
+ this.oldest[OLDER] = undefined;
151
+ } else {
152
+ // the cache is exhausted
153
+ this.oldest = undefined;
154
+ this.newest = undefined;
155
+ }
156
+ // Remove last strong reference to <entry> and remove links from the purged
157
+ // entry being returned:
158
+ entry[NEWER] = entry[OLDER] = undefined;
159
+ this._keymap.delete(entry.key);
160
+ --this.size;
161
+ return [entry.key, entry.value];
162
+ }
163
+ }
164
+ }
165
+
166
+ function Entry(this: any, key: any, value: any) {
167
+ this.key = key;
168
+ this.value = value;
169
+ this[NEWER] = undefined;
170
+ this[OLDER] = undefined;
171
+ }
172
+
173
+
174
+ function EntryIterator(this: any, oldestEntry: any) {
175
+ this.entry = oldestEntry;
176
+ }
177
+ EntryIterator.prototype[Symbol.iterator] = function () {
178
+ return this;
179
+ };
180
+ EntryIterator.prototype.next = function () {
181
+ const ent = this.entry;
182
+ if (ent) {
183
+ this.entry = ent[NEWER];
184
+ return { done: false, value: [ent.key, ent.value] };
185
+ } else {
186
+ return { done: true, value: undefined };
187
+ }
188
+ };
189
+
190
+
191
+ function KeyIterator(this: any, oldestEntry: any) {
192
+ this.entry = oldestEntry;
193
+ }
194
+ KeyIterator.prototype[Symbol.iterator] = function () {
195
+ return this;
196
+ };
197
+ KeyIterator.prototype.next = function () {
198
+ const ent = this.entry;
199
+ if (ent) {
200
+ this.entry = ent[NEWER];
201
+ return { done: false, value: ent.key };
202
+ } else {
203
+ return { done: true, value: undefined };
204
+ }
205
+ };
206
+
207
+ function ValueIterator(this: any, oldestEntry: any) {
208
+ this.entry = oldestEntry;
209
+ }
210
+ ValueIterator.prototype[Symbol.iterator] = function () {
211
+ return this;
212
+ };
213
+ ValueIterator.prototype.next = function () {
214
+ const ent = this.entry;
215
+ if (ent) {
216
+ this.entry = ent[NEWER];
217
+ return { done: false, value: ent.value };
218
+ } else {
219
+ return { done: true, value: undefined };
220
+ }
221
+ };
@@ -0,0 +1,14 @@
1
+ export type Handle = number;
2
+ export type Ptr = number;
3
+ export interface Stats {
4
+ read: number,
5
+ write: number,
6
+ readTotalTime: number,
7
+ cacheHit: number,
8
+ cacheMiss: number,
9
+ cacheUsed: number,
10
+ };
11
+
12
+ export interface EmModule {
13
+ HEAPU8: Uint8Array,
14
+ };