js-dos 8.1.4 → 8.1.6

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 (141) hide show
  1. package/README.md +1 -1
  2. package/dist/emulators/emulators.js +2 -0
  3. package/dist/emulators/emulators.js.map +1 -0
  4. package/dist/emulators/types/build.d.ts +28 -0
  5. package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
  6. package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
  7. package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
  8. package/dist/emulators/types/emulators.d.ts +76 -0
  9. package/dist/emulators/types/http.d.ts +9 -0
  10. package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
  11. package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
  12. package/dist/emulators/types/impl/modules.d.ts +38 -0
  13. package/dist/emulators/types/libzip/libzip.d.ts +16 -0
  14. package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
  15. package/dist/emulators/types/protocol/protocol.d.ts +128 -0
  16. package/dist/emulators/wdosbox-x.js +55 -0
  17. package/dist/emulators/wdosbox-x.js.symbols +8760 -0
  18. package/dist/emulators/wdosbox-x.wasm +0 -0
  19. package/dist/emulators/wdosbox.js +55 -0
  20. package/dist/emulators/wdosbox.js.symbols +3001 -0
  21. package/dist/emulators/wdosbox.wasm +0 -0
  22. package/dist/emulators/wlibzip.js +21 -0
  23. package/dist/emulators/wlibzip.js.symbols +268 -0
  24. package/dist/emulators/wlibzip.wasm +0 -0
  25. package/dist/js-dos.css +1 -0
  26. package/dist/js-dos.js +22 -0
  27. package/dist/js-dos.js.map +1 -0
  28. package/package.json +1 -1
  29. package/release.zip +0 -0
  30. package/.eslintrc.json +0 -43
  31. package/.github/workflows/build.yml +0 -51
  32. package/.gitmodules +0 -4
  33. package/index.html +0 -110
  34. package/postcss.config.cjs +0 -8
  35. package/src/app.css +0 -14
  36. package/src/base.css +0 -10
  37. package/src/components/checkbox.tsx +0 -41
  38. package/src/components/close-button.tsx +0 -17
  39. package/src/components/components.css +0 -28
  40. package/src/components/dos-option-checkbox.tsx +0 -94
  41. package/src/components/dos-option-select.tsx +0 -108
  42. package/src/components/dos-option-slider.tsx +0 -35
  43. package/src/components/error.tsx +0 -16
  44. package/src/components/loading.tsx +0 -26
  45. package/src/components/lock.tsx +0 -10
  46. package/src/components/select.tsx +0 -33
  47. package/src/components/slider.tsx +0 -69
  48. package/src/download-file.ts +0 -18
  49. package/src/frame/account-frame.tsx +0 -156
  50. package/src/frame/editor/defaults.ts +0 -419
  51. package/src/frame/editor/editor-conf-frame.tsx +0 -227
  52. package/src/frame/editor/editor-frame.css +0 -55
  53. package/src/frame/editor/editor-fs-frame.tsx +0 -314
  54. package/src/frame/fat-drives-frame.tsx +0 -199
  55. package/src/frame/frame.css +0 -119
  56. package/src/frame/frame.tsx +0 -34
  57. package/src/frame/image-rendering-frame.tsx +0 -8
  58. package/src/frame/network-frame.tsx +0 -157
  59. package/src/frame/quick-save-frame.tsx +0 -98
  60. package/src/frame/settings-frame.tsx +0 -14
  61. package/src/frame/stats-frame.tsx +0 -87
  62. package/src/host/bundle-storage.ts +0 -91
  63. package/src/host/fullscreen.ts +0 -35
  64. package/src/host/lcache.ts +0 -203
  65. package/src/host/lstorage.ts +0 -156
  66. package/src/i18n.ts +0 -185
  67. package/src/index.css +0 -7
  68. package/src/load.ts +0 -132
  69. package/src/login/login.css +0 -9
  70. package/src/login/login.tsx +0 -77
  71. package/src/main.tsx +0 -197
  72. package/src/public/types.ts +0 -45
  73. package/src/sidebar/account-button.tsx +0 -33
  74. package/src/sidebar/cloud-save-button.tsx +0 -89
  75. package/src/sidebar/diskette-icon.tsx +0 -14
  76. package/src/sidebar/fullscreen-button.tsx +0 -44
  77. package/src/sidebar/network-button.tsx +0 -39
  78. package/src/sidebar/sidebar-button.tsx +0 -244
  79. package/src/sidebar/sidebar.css +0 -47
  80. package/src/sidebar/sidebar.tsx +0 -30
  81. package/src/sockdrive/LICENSE +0 -674
  82. package/src/sockdrive/README.md +0 -45
  83. package/src/sockdrive/include/sockdrive.h +0 -23
  84. package/src/sockdrive/js/.eslintrc.json +0 -43
  85. package/src/sockdrive/js/package.json +0 -29
  86. package/src/sockdrive/js/src/fatfs/chains.js +0 -318
  87. package/src/sockdrive/js/src/fatfs/dir.js +0 -385
  88. package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
  89. package/src/sockdrive/js/src/fatfs/index.js +0 -606
  90. package/src/sockdrive/js/src/fatfs/structs.js +0 -255
  91. package/src/sockdrive/js/src/fatfs/vol.js +0 -166
  92. package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
  93. package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
  94. package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
  95. package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
  96. package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
  97. package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
  98. package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
  99. package/src/sockdrive/js/src/test/test.ts +0 -289
  100. package/src/sockdrive/js/tsconfig.json +0 -11
  101. package/src/sockdrive/js/webpack.config.js +0 -68
  102. package/src/sockdrive/js/yarn.lock +0 -1808
  103. package/src/store/auth.ts +0 -115
  104. package/src/store/dos.ts +0 -305
  105. package/src/store/editor.ts +0 -61
  106. package/src/store/init.ts +0 -48
  107. package/src/store/storage.ts +0 -32
  108. package/src/store/ui.ts +0 -191
  109. package/src/store.tsx +0 -116
  110. package/src/ui.tsx +0 -140
  111. package/src/v8/changes.ts +0 -56
  112. package/src/v8/config.ts +0 -20
  113. package/src/v8/subscriptions.ts +0 -62
  114. package/src/vite-env.d.ts +0 -5
  115. package/src/window/dos/controls/keyboard.ts +0 -32
  116. package/src/window/dos/controls/keys.ts +0 -331
  117. package/src/window/dos/controls/mouse/mount.ts +0 -99
  118. package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
  119. package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
  120. package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
  121. package/src/window/dos/controls/mouse/pointer.ts +0 -85
  122. package/src/window/dos/controls/mouse.ts +0 -21
  123. package/src/window/dos/dos-dhry2.tsx +0 -191
  124. package/src/window/dos/dos-runtime.tsx +0 -216
  125. package/src/window/dos/dos-window.tsx +0 -91
  126. package/src/window/dos/render/canvas.ts +0 -65
  127. package/src/window/dos/render/resize.ts +0 -31
  128. package/src/window/dos/render/webgl.ts +0 -173
  129. package/src/window/dos/sound/audio-node.ts +0 -148
  130. package/src/window/error-window.tsx +0 -9
  131. package/src/window/loading-window.tsx +0 -54
  132. package/src/window/prerun-window.tsx +0 -121
  133. package/src/window/select-window.tsx +0 -118
  134. package/src/window/window.css +0 -78
  135. package/src/window/window.tsx +0 -49
  136. package/src/ws/ws-sockdrive.ts +0 -123
  137. package/src/ws/ws-transport-layer.ts +0 -468
  138. package/tailwind.config.cjs +0 -48
  139. package/tsconfig.json +0 -32
  140. package/tsconfig.node.json +0 -9
  141. 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.");