js-dos 8.1.5 → 8.1.7

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 (140) hide show
  1. package/dist/emulators/emulators.js +2 -0
  2. package/dist/emulators/emulators.js.map +1 -0
  3. package/dist/emulators/types/build.d.ts +28 -0
  4. package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
  5. package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
  6. package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
  7. package/dist/emulators/types/emulators.d.ts +76 -0
  8. package/dist/emulators/types/http.d.ts +9 -0
  9. package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
  10. package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
  11. package/dist/emulators/types/impl/modules.d.ts +38 -0
  12. package/dist/emulators/types/libzip/libzip.d.ts +16 -0
  13. package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
  14. package/dist/emulators/types/protocol/protocol.d.ts +128 -0
  15. package/dist/emulators/wdosbox-x.js +55 -0
  16. package/dist/emulators/wdosbox-x.js.symbols +8760 -0
  17. package/dist/emulators/wdosbox-x.wasm +0 -0
  18. package/dist/emulators/wdosbox.js +55 -0
  19. package/dist/emulators/wdosbox.js.symbols +3001 -0
  20. package/dist/emulators/wdosbox.wasm +0 -0
  21. package/dist/emulators/wlibzip.js +21 -0
  22. package/dist/emulators/wlibzip.js.symbols +268 -0
  23. package/dist/emulators/wlibzip.wasm +0 -0
  24. package/dist/js-dos.css +1 -0
  25. package/dist/js-dos.js +22 -0
  26. package/dist/js-dos.js.map +1 -0
  27. package/package.json +1 -1
  28. package/release.zip +0 -0
  29. package/.eslintrc.json +0 -43
  30. package/.github/workflows/build.yml +0 -51
  31. package/.gitmodules +0 -4
  32. package/index.html +0 -110
  33. package/postcss.config.cjs +0 -8
  34. package/src/app.css +0 -14
  35. package/src/base.css +0 -10
  36. package/src/components/checkbox.tsx +0 -41
  37. package/src/components/close-button.tsx +0 -17
  38. package/src/components/components.css +0 -28
  39. package/src/components/dos-option-checkbox.tsx +0 -94
  40. package/src/components/dos-option-select.tsx +0 -108
  41. package/src/components/dos-option-slider.tsx +0 -35
  42. package/src/components/error.tsx +0 -16
  43. package/src/components/loading.tsx +0 -26
  44. package/src/components/lock.tsx +0 -10
  45. package/src/components/select.tsx +0 -33
  46. package/src/components/slider.tsx +0 -69
  47. package/src/download-file.ts +0 -18
  48. package/src/frame/account-frame.tsx +0 -156
  49. package/src/frame/editor/defaults.ts +0 -419
  50. package/src/frame/editor/editor-conf-frame.tsx +0 -227
  51. package/src/frame/editor/editor-frame.css +0 -55
  52. package/src/frame/editor/editor-fs-frame.tsx +0 -314
  53. package/src/frame/fat-drives-frame.tsx +0 -199
  54. package/src/frame/frame.css +0 -119
  55. package/src/frame/frame.tsx +0 -34
  56. package/src/frame/image-rendering-frame.tsx +0 -8
  57. package/src/frame/network-frame.tsx +0 -157
  58. package/src/frame/quick-save-frame.tsx +0 -98
  59. package/src/frame/settings-frame.tsx +0 -14
  60. package/src/frame/stats-frame.tsx +0 -87
  61. package/src/host/bundle-storage.ts +0 -91
  62. package/src/host/fullscreen.ts +0 -35
  63. package/src/host/lcache.ts +0 -203
  64. package/src/host/lstorage.ts +0 -156
  65. package/src/i18n.ts +0 -185
  66. package/src/index.css +0 -7
  67. package/src/load.ts +0 -132
  68. package/src/login/login.css +0 -9
  69. package/src/login/login.tsx +0 -77
  70. package/src/main.tsx +0 -197
  71. package/src/public/types.ts +0 -45
  72. package/src/sidebar/account-button.tsx +0 -33
  73. package/src/sidebar/cloud-save-button.tsx +0 -89
  74. package/src/sidebar/diskette-icon.tsx +0 -14
  75. package/src/sidebar/fullscreen-button.tsx +0 -44
  76. package/src/sidebar/network-button.tsx +0 -39
  77. package/src/sidebar/sidebar-button.tsx +0 -244
  78. package/src/sidebar/sidebar.css +0 -47
  79. package/src/sidebar/sidebar.tsx +0 -30
  80. package/src/sockdrive/LICENSE +0 -674
  81. package/src/sockdrive/README.md +0 -45
  82. package/src/sockdrive/include/sockdrive.h +0 -23
  83. package/src/sockdrive/js/.eslintrc.json +0 -43
  84. package/src/sockdrive/js/package.json +0 -29
  85. package/src/sockdrive/js/src/fatfs/chains.js +0 -318
  86. package/src/sockdrive/js/src/fatfs/dir.js +0 -385
  87. package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
  88. package/src/sockdrive/js/src/fatfs/index.js +0 -606
  89. package/src/sockdrive/js/src/fatfs/structs.js +0 -255
  90. package/src/sockdrive/js/src/fatfs/vol.js +0 -166
  91. package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
  92. package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
  93. package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
  94. package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
  95. package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
  96. package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
  97. package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
  98. package/src/sockdrive/js/src/test/test.ts +0 -289
  99. package/src/sockdrive/js/tsconfig.json +0 -11
  100. package/src/sockdrive/js/webpack.config.js +0 -68
  101. package/src/sockdrive/js/yarn.lock +0 -1808
  102. package/src/store/auth.ts +0 -115
  103. package/src/store/dos.ts +0 -305
  104. package/src/store/editor.ts +0 -61
  105. package/src/store/init.ts +0 -48
  106. package/src/store/storage.ts +0 -32
  107. package/src/store/ui.ts +0 -191
  108. package/src/store.tsx +0 -116
  109. package/src/ui.tsx +0 -140
  110. package/src/v8/changes.ts +0 -56
  111. package/src/v8/config.ts +0 -20
  112. package/src/v8/subscriptions.ts +0 -62
  113. package/src/vite-env.d.ts +0 -5
  114. package/src/window/dos/controls/keyboard.ts +0 -32
  115. package/src/window/dos/controls/keys.ts +0 -331
  116. package/src/window/dos/controls/mouse/mount.ts +0 -99
  117. package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
  118. package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
  119. package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
  120. package/src/window/dos/controls/mouse/pointer.ts +0 -85
  121. package/src/window/dos/controls/mouse.ts +0 -21
  122. package/src/window/dos/dos-dhry2.tsx +0 -191
  123. package/src/window/dos/dos-runtime.tsx +0 -216
  124. package/src/window/dos/dos-window.tsx +0 -91
  125. package/src/window/dos/render/canvas.ts +0 -65
  126. package/src/window/dos/render/resize.ts +0 -31
  127. package/src/window/dos/render/webgl.ts +0 -173
  128. package/src/window/dos/sound/audio-node.ts +0 -148
  129. package/src/window/error-window.tsx +0 -9
  130. package/src/window/loading-window.tsx +0 -54
  131. package/src/window/prerun-window.tsx +0 -121
  132. package/src/window/select-window.tsx +0 -118
  133. package/src/window/window.css +0 -78
  134. package/src/window/window.tsx +0 -49
  135. package/src/ws/ws-sockdrive.ts +0 -123
  136. package/src/ws/ws-transport-layer.ts +0 -468
  137. package/tailwind.config.cjs +0 -48
  138. package/tsconfig.json +0 -32
  139. package/tsconfig.node.json +0 -9
  140. package/vite.config.ts +0 -25
@@ -1,87 +0,0 @@
1
- import { useSelector } from "react-redux";
2
- import { State } from "../store";
3
-
4
- export function StatsFrame() {
5
- const startedAt = useSelector((state: State) => state.dos.ciStartedAt);
6
- const stats = useSelector((state: State) => state.dos.stats);
7
- const cycles = Math.round(useSelector((state: State) => state.dos.stats.cyclesPerMs) / 1000);
8
- const driveRecvMb = Math.round(stats.driveRecv / 1024 / 1024 * 100) / 100;
9
- const driveSpeedMb = (stats.driveRecvTime / 1000) > 1 ?
10
- Math.round(driveRecvMb / stats.driveRecvTime * 1000 * 100) / 100 : 0;
11
- return <div class="stats-frame frame-root items-start px-4">
12
- <div class="w-full overflow-x-auto">
13
- <table class="table table-compact w-full">
14
- <thead>
15
- <tr>
16
- <th>Metric</th>
17
- <th>Value</th>
18
- </tr>
19
- </thead>
20
- <tbody>
21
- <tr>
22
- <td>Uptime</td>
23
- <td>{Math.round((Date.now() - startedAt) / 100) / 10} s</td>
24
- </tr>
25
- <tr>
26
- <td>Cycles/ms</td>
27
- { cycles <= 0 && <td>~ K</td> }
28
- { cycles > 0 && cycles <= 1000 && <td>{cycles} K</td> }
29
- { cycles > 1000 && <td>{Math.round(cycles / 1000)} KK</td> }
30
- </tr>
31
- <tr>
32
- <td>NonSkipSleep COUNT/s</td>
33
- <td>{stats.nonSkippableSleepPreSec}</td>
34
- </tr>
35
- <tr>
36
- <td>Sleep COUNT/s</td>
37
- <td>{stats.sleepPerSec}</td>
38
- </tr>
39
- <tr>
40
- <td>Sleep TIME/s</td>
41
- <td>{stats.sleepTimePerSec}</td>
42
- </tr>
43
- <tr>
44
- <td>Msg FRAME/s</td>
45
- <td>{stats.framePerSec}</td>
46
- </tr>
47
- <tr>
48
- <td>Msg SOUND/s</td>
49
- <td>{stats.soundPerSec}</td>
50
- </tr>
51
- <tr>
52
- <td>Msg SENT/s</td>
53
- <td>{stats.msgSentPerSec}</td>
54
- </tr>
55
- <tr>
56
- <td>Msg RECV/s</td>
57
- <td>{stats.msgRecvPerSec}</td>
58
- </tr>
59
- <tr>
60
- <td>Net SENT/s</td>
61
- <td>{Math.round(stats.netSent / 1024 * 100) / 100}Kb</td>
62
- </tr>
63
- <tr>
64
- <td>Net RECV/s</td>
65
- <td>{Math.round(stats.netRecv / 1024 * 100) / 100}Kb</td>
66
- </tr>
67
- <tr>
68
- <td>HDD RECV/s</td>
69
- <td>{driveRecvMb}Mb (~{driveSpeedMb}Mb/s)</td>
70
- </tr>
71
- <tr>
72
- <td>HDD SENT/s</td>
73
- <td>{Math.round(stats.driveSent / 1024 / 1024 * 100) / 100}Mb</td>
74
- </tr>
75
- <tr>
76
- <td>HDD Cache</td>
77
- <td>{Math.round(stats.driveCacheUsed / 1024 / 1024 * 100) / 100}Mb</td>
78
- </tr>
79
- <tr>
80
- <td>HDD Cache Hit/Miss</td>
81
- <td>{stats.driveCacheHit} / {stats.driveCacheMiss}</td>
82
- </tr>
83
- </tbody>
84
- </table>
85
- </div>
86
- </div>;
87
- }
@@ -1,91 +0,0 @@
1
- import { storageSlice } from "../store/storage";
2
- import { Account } from "../store/auth";
3
- import { brCdn } from "../v8/config";
4
- import { Store, getNonSerializableStore } from "../store";
5
-
6
- export function bundleFromFile(file: File, store: Store): Promise<Uint8Array> {
7
- return new Promise<Uint8Array>((resolve) => {
8
- store.dispatch(storageSlice.actions.reset());
9
- const reader = new FileReader();
10
- reader.addEventListener("load", async (e) => {
11
- resolve(new Uint8Array(reader.result as ArrayBuffer));
12
- });
13
- reader.addEventListener("progress", (e) => {
14
- store.dispatch(storageSlice.actions.progress([e.loaded, e.total]));
15
- });
16
- reader.readAsArrayBuffer(file);
17
- });
18
- }
19
-
20
-
21
- export async function bundleFromChanges(url: string, account: Account | null,
22
- store: Store): Promise<Uint8Array | null> {
23
- if (account === null || !account.premium) {
24
- return await getNonSerializableStore(store).cache.get(url).catch(() => null);
25
- }
26
-
27
- try {
28
- const response = await fetch(url, {
29
- cache: "no-cache",
30
- });
31
-
32
- if (response.status !== 200) {
33
- throw new Error("Resource not avalible (" + response.status + "): " + response.statusText);
34
- }
35
-
36
- return response.arrayBuffer().then((b) => new Uint8Array(b));
37
- } catch (e: any) {
38
- return await getNonSerializableStore(store).cache.get(url).catch(() => null);
39
- }
40
- }
41
-
42
- export async function bundleFromUrl(url: string, store: Store): Promise<Uint8Array> {
43
- try {
44
- return await getNonSerializableStore(store).cache.get(url);
45
- } catch (e: any) {
46
- // ignore
47
- }
48
-
49
- store.dispatch(storageSlice.actions.reset());
50
- const response = await fetch(url, {
51
- cache: "no-store",
52
- });
53
-
54
- if (response.status !== 200) {
55
- throw new Error("Resource not avalible (" + response.status + "): " + response.statusText);
56
- }
57
-
58
- const lenHeader = response.headers.get("Content-Length");
59
- const length = lenHeader === null ? 0 :
60
- Number.parseInt(lenHeader);
61
- const reader = response.body!.getReader();
62
-
63
- let received = 0;
64
- const chunks: Uint8Array[] = [];
65
- while (true) {
66
- const { done, value } = await reader.read();
67
-
68
- if (done) {
69
- break;
70
- }
71
-
72
- chunks.push(value);
73
- received += value.length;
74
-
75
- const bytes = Math.min(url.startsWith(brCdn) ? received / 2 : received, length);
76
- store.dispatch(storageSlice.actions.progress([bytes, length]));
77
- }
78
-
79
- let offset = 0;
80
- const complete = new Uint8Array(received);
81
- for (const next of chunks) {
82
- complete.set(next, offset);
83
- offset += next.length;
84
- }
85
-
86
- getNonSerializableStore(store).cache
87
- .put(url, complete)
88
- .catch(console.error);
89
-
90
- return complete;
91
- };
@@ -1,35 +0,0 @@
1
- import { Store, getNonSerializableStore } from "../store";
2
- import { uiSlice } from "../store/ui";
3
-
4
- export function browserSetFullScreen(fullScreen: boolean, store: Store) {
5
- const root = getNonSerializableStore(store).root as any;
6
- if (fullScreen) {
7
- if (root.requestFullscreen) {
8
- root.requestFullscreen();
9
- } else if (root.webkitRequestFullscreen) {
10
- root.webkitRequestFullscreen();
11
- } else if (root.mozRequestFullScreen) {
12
- root.mozRequestFullScreen();
13
- } else if (root.msRequestFullscreen) {
14
- root.msRequestFullscreen();
15
- } else if (root.webkitEnterFullscreen) {
16
- root.webkitEnterFullscreen();
17
- } else {
18
- root.classList.add("jsdos-fullscreen-workaround");
19
- }
20
- } else {
21
- if (root.classList.contains("jsdos-fullscreen-workaround")) {
22
- root.classList.remove("jsdos-fullscreen-workaround");
23
- } else if (document.exitFullscreen) {
24
- document.exitFullscreen();
25
- } else if ((document as any).webkitExitFullscreen) {
26
- (document as any).webkitExitFullscreen();
27
- } else if ((document as any).mozCancelFullScreen) {
28
- (document as any).mozCancelFullScreen();
29
- } else if ((document as any).msExitFullscreen) {
30
- (document as any).msExitFullscreen();
31
- }
32
- }
33
-
34
- store.dispatch(uiSlice.actions.setFullScreen(fullScreen));
35
- }
@@ -1,203 +0,0 @@
1
- /* eslint @typescript-eslint/no-unused-vars: 0 */
2
-
3
- export interface Cache {
4
- readonly owner: string;
5
- put: (key: string, data: Uint8Array) => Promise<void>;
6
- get: (key: string, defaultValue?: Uint8Array) => Promise<Uint8Array>;
7
- del: (key: string) => Promise<void>;
8
- keys: () => Promise<string[]>;
9
- forEach: (each: (key: string, value: Uint8Array) => void) => Promise<void>;
10
- close: () => void;
11
- }
12
-
13
- export class CacheNoop implements Cache {
14
- public owner = "";
15
-
16
- public close() {
17
- }
18
-
19
- public put(key: string, data: Uint8Array): Promise<void> {
20
- return Promise.resolve();
21
- }
22
-
23
- public get(key: string, defaultValue?: Uint8Array): Promise<Uint8Array> {
24
- if (defaultValue !== undefined) {
25
- return Promise.resolve(defaultValue);
26
- }
27
- return Promise.reject(new Error("Cache is not supported on this host"));
28
- }
29
-
30
- public del(key: string): Promise<void> {
31
- return Promise.resolve();
32
- }
33
-
34
- public keys(): Promise<string[]> {
35
- return Promise.resolve([]);
36
- }
37
-
38
- public forEach(each: (key: string, value: Uint8Array) => void) {
39
- return Promise.resolve();
40
- }
41
- }
42
-
43
- class LCache implements Cache {
44
- public owner: string;
45
- private storeName = "files";
46
- private indexedDB: IDBFactory;
47
- private db: IDBDatabase | null = null;
48
-
49
- constructor(owner: string,
50
- onready: (cache: Cache) => void,
51
- onerror: (msg: string) => void) {
52
- this.owner = owner;
53
- this.indexedDB = (typeof window === "undefined" ? undefined : window.indexedDB ||
54
- (window as any).mozIndexedDB ||
55
- (window as any).webkitIndexedDB || (window as any).msIndexedDB) as any;
56
-
57
- if (!this.indexedDB) {
58
- onerror("Indexed db is not supported on this host");
59
- return;
60
- }
61
-
62
- try {
63
- const openRequest = this.indexedDB.open("js-dos-cache (" + owner + ")", 1);
64
- openRequest.onerror = (event) => {
65
- onerror("Can't open cache database: " + openRequest.error?.message);
66
- };
67
- openRequest.onsuccess = (event) => {
68
- this.db = openRequest.result;
69
- onready(this);
70
- };
71
- openRequest.onupgradeneeded = (event) => {
72
- try {
73
- this.db = openRequest.result;
74
- this.db.onerror = (event) => {
75
- onerror("Can't upgrade cache database");
76
- };
77
-
78
- const objectStore = this.db.createObjectStore(this.storeName);
79
- objectStore.createIndex("key", "", {
80
- unique: true,
81
- multiEntry: false,
82
- });
83
- } catch (e) {
84
- onerror("Can't upgrade cache database");
85
- }
86
- };
87
- } catch (e: any) {
88
- onerror("Can't open cache database: " + e.message);
89
- }
90
- }
91
-
92
- public close() {
93
- if (this.db !== null) {
94
- this.db.close();
95
- this.db = null;
96
- }
97
- }
98
-
99
- public put(key: string, data: Uint8Array): Promise<void> {
100
- return new Promise<void>((resolve, reject) => {
101
- if (this.db === null) {
102
- resolve();
103
- return;
104
- }
105
-
106
- const transaction = this.db.transaction(this.storeName, "readwrite");
107
- const request = transaction.objectStore(this.storeName).put(data.buffer, key);
108
- request.onerror = () => reject;
109
- request.onsuccess = () => resolve();
110
- });
111
- }
112
-
113
- public del(key: string): Promise<void> {
114
- return new Promise<void>((resolve, reject) => {
115
- if (this.db === null) {
116
- resolve();
117
- return;
118
- }
119
-
120
- const transaction = this.db.transaction(this.storeName, "readwrite");
121
- const request = transaction.objectStore(this.storeName).delete(key);
122
- request.onerror = () => reject;
123
- request.onsuccess = () => resolve();
124
- });
125
- }
126
-
127
- public get(key: string, defaultValue?: Uint8Array): Promise<Uint8Array> {
128
- return new Promise<Uint8Array>((resolve, reject) => {
129
- function rejectOrResolve(message: string) {
130
- if (defaultValue === undefined) {
131
- reject(new Error(message));
132
- } else {
133
- resolve(defaultValue);
134
- }
135
- }
136
-
137
-
138
- if (this.db === null) {
139
- rejectOrResolve("db is not initalized");
140
- return;
141
- }
142
-
143
- const transaction = this.db.transaction(this.storeName, "readonly");
144
- const request = transaction.objectStore(this.storeName).get(key) as IDBRequest<ArrayBuffer>;
145
- request.onerror = () => reject(new Error("Can't read value for key '" + key + "'"));
146
- request.onsuccess = () => {
147
- if (request.result) {
148
- resolve(new Uint8Array(request.result));
149
- } else {
150
- rejectOrResolve("Result is empty for key '" + key + "', result: " + request.result);
151
- }
152
- };
153
- });
154
- }
155
-
156
- public keys(): Promise<string[]> {
157
- return new Promise<string[]>((resolve, reject) => {
158
- if (this.db === null) {
159
- resolve([]);
160
- return;
161
- }
162
-
163
- const transaction = this.db.transaction(this.storeName, "readonly");
164
- const request = transaction.objectStore(this.storeName).index("key").getAllKeys();
165
- request.onerror = () => reject;
166
- request.onsuccess = (event) => {
167
- const keys = (event.target as any).result as string[];
168
- resolve(keys);
169
- };
170
- });
171
- }
172
-
173
- public forEach(each: (key: string, value: Uint8Array) => void): Promise<void> {
174
- return new Promise<void>((resolve, reject) => {
175
- if (this.db === null) {
176
- resolve();
177
- return;
178
- }
179
-
180
- const transaction = this.db.transaction(this.storeName, "readonly");
181
- const request = transaction.objectStore(this.storeName).openCursor();
182
- request.onerror = () => reject;
183
- request.onsuccess = (event) => {
184
- const cursor = (event.target as any).result as IDBCursorWithValue;
185
- if (cursor) {
186
- each(cursor.key.toString(), new Uint8Array(cursor.value));
187
- cursor.continue();
188
- } else {
189
- resolve();
190
- }
191
- };
192
- });
193
- }
194
- }
195
-
196
- export function getCache(owner: string): Promise<Cache> {
197
- return new Promise((resolve) => {
198
- new LCache(owner, resolve, (msg: string) => {
199
- console.error("Can't open IndexedDB cache", msg);
200
- resolve(new CacheNoop());
201
- });
202
- });
203
- }
@@ -1,156 +0,0 @@
1
- const MAX_VALUE_SIZE = 1024;
2
- const NEXT_PART_SYMBOL = "@";
3
- const NEXT_PART_SYFFIX = ".";
4
-
5
- class MemStorage implements Storage {
6
- length = 0;
7
-
8
- private storage: {[key: string]: string} = {};
9
-
10
- setItem(key: string, value: string): void {
11
- this.storage[key] = value;
12
- this.length = Object.keys(this.storage).length;
13
- }
14
-
15
- getItem(key: string): string | null {
16
- const value = this.storage[key];
17
- return value === undefined ? null : value;
18
- }
19
-
20
- removeItem(key: string): void {
21
- delete this.storage[key];
22
- this.length = Object.keys(this.storage).length;
23
- }
24
-
25
- key(index: number): string | null {
26
- const keys = Object.keys(this.storage);
27
- return keys[index] === undefined ? null : keys[index];
28
- }
29
-
30
- clear() {
31
- this.length = 0;
32
- this.storage = {};
33
- }
34
- }
35
-
36
-
37
- class LStorage implements Storage {
38
- private backend: Storage;
39
- length: number;
40
- prefix: string;
41
-
42
- constructor(backend: Storage | undefined, prefix: string) {
43
- this.prefix = prefix;
44
-
45
- try {
46
- this.backend = backend || localStorage;
47
- this.testBackend();
48
- } catch (e) {
49
- this.backend = new MemStorage();
50
- }
51
-
52
- this.length = this.backend.length;
53
-
54
- if (typeof this.backend.sync === "function") {
55
- (this as any).sync = (callback: any) => {
56
- this.backend.sync(callback);
57
- };
58
- }
59
- }
60
-
61
- private testBackend() {
62
- const testKey = this.prefix + ".test.record";
63
- const testValue = "123";
64
- this.backend.setItem(testKey, testValue);
65
- const readedValue = this.backend.getItem(testKey);
66
- this.backend.removeItem(testKey);
67
- const valid = readedValue === testValue && this.backend.getItem(testKey) === null;
68
-
69
- if (!valid) {
70
- throw new Error("Storage backend is not working properly");
71
- }
72
- }
73
-
74
- setLocalStoragePrefix(prefix: string) {
75
- this.prefix = prefix;
76
- }
77
-
78
- clear(): void {
79
- if (!this.backend.length) {
80
- return;
81
- }
82
-
83
- const toRemove: string[] = [];
84
- for (let i = 0; i < this.backend.length; ++i) {
85
- const next = this.backend.key(i);
86
- if (next && next.startsWith(this.prefix)) {
87
- toRemove.push(next);
88
- }
89
- }
90
-
91
- for (const next of toRemove) {
92
- this.backend.removeItem(next);
93
- }
94
- this.length = this.backend.length;
95
- }
96
-
97
- key(index: number): string | null {
98
- return this.backend.key(index);
99
- }
100
-
101
- setItem(key: string, value: string): void {
102
- if (!value || value.length === undefined || value.length === 0) {
103
- this.writeStringToKey(key, "");
104
- return;
105
- }
106
-
107
- let offset = 0;
108
- while (offset < value.length) {
109
- let substr = value.substr(offset, MAX_VALUE_SIZE);
110
- offset += substr.length;
111
-
112
- if (offset < value.length) {
113
- substr += NEXT_PART_SYMBOL;
114
- }
115
-
116
- this.writeStringToKey(key, substr);
117
- key += NEXT_PART_SYFFIX;
118
- }
119
- }
120
-
121
- getItem(key: string): string | null {
122
- let value = this.readStringFromKey(key);
123
- if (value === null) {
124
- return null;
125
- }
126
-
127
- if (value.length === 0) {
128
- return value;
129
- }
130
-
131
- while (value[value.length - 1] === NEXT_PART_SYMBOL) {
132
- value = value.substr(0, value.length - 1);
133
- key += NEXT_PART_SYFFIX;
134
- const next = this.readStringFromKey(key);
135
- value += next === null ? "" : next;
136
- }
137
-
138
- return value;
139
- }
140
-
141
- removeItem(key: string): void {
142
- this.backend.removeItem(this.prefix + key);
143
- this.length = this.backend.length;
144
- }
145
-
146
- private writeStringToKey(key: string, value: string) {
147
- this.backend.setItem(this.prefix + key, value);
148
- this.length = this.backend.length;
149
- }
150
-
151
- private readStringFromKey(key: string) {
152
- return this.backend.getItem(this.prefix + key);
153
- }
154
- }
155
-
156
- export const lStorage = new LStorage(undefined, "jsdos.8.");