js-dos 0.80.25

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 (119) hide show
  1. package/.eslintrc.json +43 -0
  2. package/.github/workflows/build.yml +43 -0
  3. package/.gitmodules +4 -0
  4. package/README.md +24 -0
  5. package/index.html +106 -0
  6. package/package.json +48 -0
  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 +72 -0
  14. package/src/components/dos-option-select.tsx +94 -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 +155 -0
  23. package/src/frame/editor/defaults.ts +344 -0
  24. package/src/frame/editor/editor-conf-frame.tsx +42 -0
  25. package/src/frame/editor/editor-frame.css +55 -0
  26. package/src/frame/editor/editor-fs-frame.tsx +315 -0
  27. package/src/frame/frame.css +127 -0
  28. package/src/frame/frame.tsx +34 -0
  29. package/src/frame/host-cache-frame.tsx +124 -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 +95 -0
  33. package/src/frame/settings-frame.tsx +14 -0
  34. package/src/frame/stats-frame.tsx +82 -0
  35. package/src/host/bundle-storage.ts +91 -0
  36. package/src/host/fullscreen.ts +36 -0
  37. package/src/host/lcache.ts +203 -0
  38. package/src/host/lstorage.ts +156 -0
  39. package/src/i18n.ts +167 -0
  40. package/src/index.css +7 -0
  41. package/src/load.ts +139 -0
  42. package/src/login/login.css +9 -0
  43. package/src/login/login.tsx +77 -0
  44. package/src/main.tsx +195 -0
  45. package/src/non-serializable-store.ts +35 -0
  46. package/src/public/types.ts +39 -0
  47. package/src/sidebar/account-button.tsx +32 -0
  48. package/src/sidebar/cloud-save-button.tsx +89 -0
  49. package/src/sidebar/diskette-icon.tsx +14 -0
  50. package/src/sidebar/fullscreen-button.tsx +44 -0
  51. package/src/sidebar/network-button.tsx +39 -0
  52. package/src/sidebar/sidebar-button.tsx +243 -0
  53. package/src/sidebar/sidebar.css +47 -0
  54. package/src/sidebar/sidebar.tsx +30 -0
  55. package/src/sockdrive/LICENSE +674 -0
  56. package/src/sockdrive/README.md +22 -0
  57. package/src/sockdrive/SDL2/LRUCache11.hpp +240 -0
  58. package/src/sockdrive/SDL2/sockdrive.cpp +207 -0
  59. package/src/sockdrive/include/sockdrive.h +23 -0
  60. package/src/sockdrive/js/.eslintrc.json +43 -0
  61. package/src/sockdrive/js/README.md +70 -0
  62. package/src/sockdrive/js/package.json +29 -0
  63. package/src/sockdrive/js/src/fatfs/chains.js +318 -0
  64. package/src/sockdrive/js/src/fatfs/dir.js +385 -0
  65. package/src/sockdrive/js/src/fatfs/helpers.js +210 -0
  66. package/src/sockdrive/js/src/fatfs/index.js +606 -0
  67. package/src/sockdrive/js/src/fatfs/structs.js +255 -0
  68. package/src/sockdrive/js/src/fatfs/vol.js +166 -0
  69. package/src/sockdrive/js/src/sockdrive/cache.ts +133 -0
  70. package/src/sockdrive/js/src/sockdrive/drive.ts +364 -0
  71. package/src/sockdrive/js/src/sockdrive/lru.ts +221 -0
  72. package/src/sockdrive/js/src/sockdrive/types.ts +10 -0
  73. package/src/sockdrive/js/src/sockdrive-fat.d.ts +64 -0
  74. package/src/sockdrive/js/src/sockdrive-fat.ts +228 -0
  75. package/src/sockdrive/js/src/sockdrive-native.ts +98 -0
  76. package/src/sockdrive/js/src/test/test.ts +186 -0
  77. package/src/sockdrive/js/tsconfig.json +11 -0
  78. package/src/sockdrive/js/webpack.config.js +68 -0
  79. package/src/sockdrive/js/yarn.lock +1808 -0
  80. package/src/sockdrive/lz4/lz4.c +2773 -0
  81. package/src/sockdrive/lz4/lz4.h +862 -0
  82. package/src/store/auth.ts +104 -0
  83. package/src/store/dos.ts +284 -0
  84. package/src/store/editor.ts +59 -0
  85. package/src/store/storage.ts +30 -0
  86. package/src/store/ui.ts +183 -0
  87. package/src/store.ts +27 -0
  88. package/src/ui.tsx +103 -0
  89. package/src/v8/changes.ts +56 -0
  90. package/src/v8/config.ts +18 -0
  91. package/src/v8/subscriptions.ts +62 -0
  92. package/src/vite-env.d.ts +2 -0
  93. package/src/window/dos/controls/keyboard.ts +32 -0
  94. package/src/window/dos/controls/keys.ts +331 -0
  95. package/src/window/dos/controls/mouse/mount.ts +99 -0
  96. package/src/window/dos/controls/mouse/mouse-locked.ts +51 -0
  97. package/src/window/dos/controls/mouse/mouse-not-locked.ts +84 -0
  98. package/src/window/dos/controls/mouse/mouse-swipe.ts +57 -0
  99. package/src/window/dos/controls/mouse/pointer.ts +85 -0
  100. package/src/window/dos/controls/mouse.ts +21 -0
  101. package/src/window/dos/dos-dhry2.tsx +191 -0
  102. package/src/window/dos/dos-runtime.tsx +185 -0
  103. package/src/window/dos/dos-window.tsx +82 -0
  104. package/src/window/dos/render/canvas.ts +65 -0
  105. package/src/window/dos/render/resize.ts +31 -0
  106. package/src/window/dos/render/webgl.ts +173 -0
  107. package/src/window/dos/sound/audio-node.ts +148 -0
  108. package/src/window/error-window.tsx +9 -0
  109. package/src/window/loading-window.tsx +54 -0
  110. package/src/window/prerun-window.tsx +98 -0
  111. package/src/window/select-window.tsx +118 -0
  112. package/src/window/window.css +78 -0
  113. package/src/window/window.tsx +49 -0
  114. package/src/ws/ws-sockdrive.ts +102 -0
  115. package/src/ws/ws-transport-layer.ts +457 -0
  116. package/tailwind.config.cjs +48 -0
  117. package/tsconfig.json +32 -0
  118. package/tsconfig.node.json +9 -0
  119. package/vite.config.ts +22 -0
@@ -0,0 +1,228 @@
1
+ import { createFileSystem } from "./fatfs";
2
+
3
+ const toBuffer = require("typedarray-to-buffer");
4
+ import { Drive } from "./sockdrive/drive";
5
+ import { Stats as SockdriveStats } from "./sockdrive/types";
6
+
7
+ export interface Driver {
8
+ sectorSize: number,
9
+ numSectors: number,
10
+ readSectors: (sector: number, dst: Uint8Array, cb: (error: Error | null, dst: Uint8Array) => void) => void,
11
+ writeSectors: (sector: number, src: Uint8Array, cb: (error: Error | null) => void) => void,
12
+ }
13
+
14
+ type Callback = (error: Error | null) => void;
15
+ type CallbackT<T> = (error: Error | null, t: T) => void;
16
+
17
+ export type FileDescriptor = number;
18
+
19
+ export interface FileSystemApi {
20
+ mkdir(path: string, cb: Callback): void;
21
+ readdir(path: string, cb: CallbackT<string[]>): void;
22
+ open(path: string, flags: string | number, mode: number, cb: CallbackT<FileDescriptor>): void;
23
+ read(fd: FileDescriptor, buf: Buffer, offset: number,
24
+ length: number, pos: number | null, cb: CallbackT<number>): void;
25
+ write(fd: FileDescriptor, buf: Buffer, offset: number,
26
+ length: number, pos: number | null, cb: CallbackT<number>): void;
27
+ fstat(fd: FileDescriptor, cb: CallbackT<Stats>): void;
28
+ close(fd: FileDescriptor, cb: Callback): void;
29
+ }
30
+
31
+ export type CreateFileSystemApi = (driver: Driver, opts: {
32
+ ro?: boolean,
33
+ noatime?: boolean,
34
+ modmode?: number,
35
+ umask?: number,
36
+ uid?: number,
37
+ gid?: number,
38
+ }, event: (event: "ready" | "error", reason: Error | null) => void) => FileSystemApi;
39
+ export type CreateSockdriveFileSystem = typeof createSockdriveFileSystem;
40
+
41
+
42
+ export class FileSystem {
43
+ fs: FileSystemApi;
44
+ constructor(fs: FileSystemApi) {
45
+ this.fs = fs;
46
+ }
47
+
48
+ private promisify<T>(fn: any, ...args: any[]): Promise<T> {
49
+ return new Promise<T>((resolve, reject) => {
50
+ fn.call(this.fs, ...args, (err: Error | null, res: T) => {
51
+ if (!err) {
52
+ resolve(res);
53
+ } else {
54
+ reject(err);
55
+ }
56
+ });
57
+ });
58
+ }
59
+
60
+ mkdir(path: string) {
61
+ return this.promisify<void>(this.fs.mkdir, path);
62
+ }
63
+ readdir(path: string) {
64
+ return this.promisify<string[]>(this.fs.readdir, path);
65
+ }
66
+ fopen(path: string, flags: string | number, mode: number) {
67
+ return this.promisify<FileDescriptor>(this.fs.open, path, flags, mode);
68
+ }
69
+ fread(fd: FileDescriptor, buf: Uint8Array, offset: number,
70
+ length: number, pos: number | null) {
71
+ return this.promisify<number>(this.fs.read, fd, toBuffer(buf),
72
+ offset, length, pos);
73
+ }
74
+ fwrite(fd: FileDescriptor, buf: Uint8Array, offset: number,
75
+ length: number, pos: number | null) {
76
+ return this.promisify<number>(this.fs.write, fd, toBuffer(buf),
77
+ offset, length, pos);
78
+ }
79
+ fstat(fd: FileDescriptor) {
80
+ return this.promisify<Stats>(this.fs.fstat, fd);
81
+ }
82
+ fclose(fd: FileDescriptor) {
83
+ return this.promisify<void>(this.fs.close, fd);
84
+ }
85
+
86
+ // helpers
87
+ async stat(path: string) {
88
+ const fd: number | null = await (this.fopen(path, "\\r", 0o666)
89
+ .catch((e: Error & { code: string }) => {
90
+ if (e.code === "NOENT") {
91
+ return null;
92
+ }
93
+
94
+ throw e;
95
+ }));
96
+ if (fd === null) {
97
+ return null;
98
+ }
99
+ const stat = await this.fstat(fd);
100
+ await this.fclose(fd);
101
+ return stat;
102
+ }
103
+
104
+ async isdir(path: string) {
105
+ const stat = await this.stat(path);
106
+ return stat !== null ? stat.isDirectory() : false;
107
+ }
108
+
109
+ async exists(path: string) {
110
+ return (await this.stat(path)) !== null;
111
+ }
112
+ }
113
+
114
+ export interface StatsBase<T> {
115
+ isFile(): boolean;
116
+ isDirectory(): boolean;
117
+ isBlockDevice(): boolean;
118
+ isCharacterDevice(): boolean;
119
+ isSymbolicLink(): boolean;
120
+ isFIFO(): boolean;
121
+ isSocket(): boolean;
122
+ dev: T;
123
+ ino: T;
124
+ mode: T;
125
+ nlink: T;
126
+ uid: T;
127
+ gid: T;
128
+ rdev: T;
129
+ size: T;
130
+ blksize: T;
131
+ blocks: T;
132
+ atimeMs: T;
133
+ mtimeMs: T;
134
+ ctimeMs: T;
135
+ birthtimeMs: T;
136
+ atime: Date;
137
+ mtime: Date;
138
+ ctime: Date;
139
+ birthtime: Date;
140
+ }
141
+
142
+ export interface Stats extends StatsBase<number> { }
143
+
144
+ export async function createSockdriveFileSystem(endpoint: string,
145
+ ownerId: string,
146
+ driveId: string,
147
+ token: string,
148
+ onOpen: (read: boolean, write: boolean) => void = () => {},
149
+ onError: (e: Error) => void = () => {}) {
150
+ const stats: SockdriveStats = {
151
+ read: 0,
152
+ write: 0,
153
+ readTotalTime: 0,
154
+ cacheHit: 0,
155
+ cacheMiss: 0,
156
+ cacheUsed: 0,
157
+ };
158
+
159
+ const sectorSize = 512;
160
+ const module = {
161
+ HEAPU8: new Uint8Array(sectorSize * 255 + sectorSize),
162
+ };
163
+
164
+ // TODO: drive should provide size and disk geometry
165
+ const drive = new Drive(endpoint, ownerId, driveId, token,
166
+ stats, module, sectorSize, 255, sectorSize);
167
+ drive.onOpen(onOpen);
168
+ drive.onError(onError);
169
+ const imageSize = 2 * 1024 * 1024 * 1024; // 2GB //FIX!
170
+
171
+ // TODO: fatfs should respect boot record section
172
+ const MBR_OFFSET = 63;
173
+ const driver: Driver = {
174
+ sectorSize,
175
+ numSectors: imageSize / sectorSize,
176
+ readSectors: function(start, dst, cb) {
177
+ (async () => {
178
+ start += MBR_OFFSET;
179
+ // TODO we can avoid copying in dst.set
180
+ for (let i = 0; i < dst.length / sectorSize; ++i) {
181
+ if (drive.read(start + i, 0, true) !== 0) {
182
+ const readCode = await drive.read(start + i, 0, false);
183
+ if (readCode !== 0) {
184
+ cb(new Error("Read error, code: " + readCode), dst);
185
+ return;
186
+ }
187
+ }
188
+ dst.set(module.HEAPU8.slice(0, sectorSize), i * sectorSize);
189
+ }
190
+ })()
191
+ .then(() => cb(null, dst))
192
+ .catch((e) => cb(e, dst));
193
+ },
194
+ writeSectors: function(start, data, cb) {
195
+ start += MBR_OFFSET;
196
+ for (let i = 0; i < data.length / sectorSize; ++i) {
197
+ module.HEAPU8.set(data.slice(i * sectorSize, (i + 1) * sectorSize), 0);
198
+ const writeCode = drive.write(start + i, 0);
199
+ if (writeCode !== 0) {
200
+ cb(new Error("Write error, code: " + 0));
201
+ return;
202
+ }
203
+ }
204
+ cb(null);
205
+ },
206
+ };
207
+
208
+ const fs = await new Promise<FileSystemApi>((resolve, reject) => {
209
+ const fs = (createFileSystem as any as CreateFileSystemApi)(driver, {}, (ev, reason) => {
210
+ if (ev === "ready") {
211
+ resolve(fs);
212
+ } else {
213
+ console.error(ev, reason);
214
+ reject(reason);
215
+ }
216
+ });
217
+ });
218
+
219
+ return {
220
+ stats,
221
+ fs: new FileSystem(fs),
222
+ close: () => drive.close(),
223
+ };
224
+ }
225
+
226
+
227
+ (window as any).createSockdriveFileSystem = createSockdriveFileSystem;
228
+ (window as any).createFileSystem = createFileSystem;
@@ -0,0 +1,98 @@
1
+ import { Handle, Ptr, Stats } from "./sockdrive/types";
2
+ import { Drive } from "./sockdrive/drive";
3
+
4
+ interface EmModule {
5
+ HEAPU8: Uint8Array,
6
+ _malloc: (len: number) => Ptr,
7
+ _free: (ptr: Ptr) => void,
8
+ _decode_lz4_block?: (compressedSize: number,
9
+ decodedSize: number, ptr: Ptr) => number;
10
+ };
11
+
12
+ interface Template {
13
+ name: string,
14
+ size: number,
15
+ heads: number,
16
+ cylinders: number,
17
+ sectors: number,
18
+ sector_size: number,
19
+ }
20
+
21
+ declare const Module: EmModule & any;
22
+
23
+ (function() {
24
+ let seq = 0;
25
+ const mapping: { [handle: Handle]: Drive } = {};
26
+ const templates: { [handle: number]: Template } = {};
27
+ const stats: Stats = {
28
+ read: 0,
29
+ write: 0,
30
+ readTotalTime: 0,
31
+ cacheHit: 0,
32
+ cacheMiss: 0,
33
+ cacheUsed: 0,
34
+ };
35
+ Module.sockdrive = {
36
+ stats,
37
+ onError: (e: Error) => {
38
+ console.error(e);
39
+ },
40
+ onOpen: (drive: string, read: boolean, write: boolean) => {
41
+ // noop
42
+ },
43
+ open: async (url: string, owner: string, name: string, token: string): Promise<Handle> => {
44
+ const response = await fetch(url.replace("wss://", "https://")
45
+ .replace("ws://", "http://") + "/template/" + owner + "/" + name);
46
+ const template = await response.json();
47
+ if (template.error) {
48
+ throw new Error(template.error);
49
+ }
50
+ seq++;
51
+ templates[seq] = template;
52
+ mapping[seq] = new Drive(url, owner, name, token, stats, Module,
53
+ Module._malloc(512 * 255), 255, 512);
54
+ mapping[seq].onOpen((read, write) => {
55
+ Module.sockdrive.onOpen(owner + "/" + name, read, write);
56
+ });
57
+ mapping[seq].onError(Module.sockdrive.onError);
58
+ return seq;
59
+ },
60
+ read: (handle: Handle, sector: number, buffer: Ptr, sync: boolean): Promise<number> | number => {
61
+ if (mapping[handle]) {
62
+ return mapping[handle].read(sector, buffer, sync);
63
+ }
64
+
65
+ console.error("ERROR! sockdrive handle", handle, "not found");
66
+ return sync ? 1 : Promise.resolve(1);
67
+ },
68
+ write: (handle: Handle, sector: number, buffer: Ptr): number => {
69
+ if (mapping[handle]) {
70
+ return mapping[handle].write(sector, buffer);
71
+ }
72
+ console.error("ERROR! sockdrive handle", handle, "not found");
73
+ return 1;
74
+ },
75
+ close: (handle: Handle) => {
76
+ if (mapping[handle]) {
77
+ Module._free(mapping[handle].readAheadBuffer);
78
+ mapping[handle].close();
79
+ delete mapping[handle];
80
+ }
81
+ },
82
+ size: (handle: Handle) => {
83
+ return templates[handle]?.size ?? 0;
84
+ },
85
+ sector_size: (handle: Handle) => {
86
+ return templates[handle]?.sector_size ?? 512;
87
+ },
88
+ heads: (handle: Handle) => {
89
+ return templates[handle]?.heads ?? 1;
90
+ },
91
+ cylinders: (handle: Handle) => {
92
+ return templates[handle]?.cylinders ?? 520;
93
+ },
94
+ sectors: (handle: Handle) => {
95
+ return templates[handle]?.sectors ?? 63;
96
+ },
97
+ };
98
+ })();
@@ -0,0 +1,186 @@
1
+ import { FileSystem, FileSystemApi, CreateFileSystemApi, Driver, CreateSockdriveFileSystem } from "../sockdrive-fat";
2
+
3
+ declare const createFileSystem: CreateFileSystemApi;
4
+ declare const createSockdriveFileSystem: CreateSockdriveFileSystem;
5
+
6
+ const baseDir = "/test";
7
+ const file = baseDir + "/Simple File.txt";
8
+
9
+ async function runTests() {
10
+ const assert = chai.assert;
11
+ function createDriver(orig: Uint8Array): Driver {
12
+ const image = orig.slice(0, orig.length);
13
+ const sectorSize = 512;
14
+ return {
15
+ sectorSize,
16
+ numSectors: image.length / 512,
17
+ readSectors: function(sector, dst, cb) {
18
+ dst.set(image.slice(sector * sectorSize, sector * sectorSize + dst.length));
19
+ cb(null, dst);
20
+ },
21
+ writeSectors: function(sector, data, cb) {
22
+ image.set(data, sector * sectorSize);
23
+ cb(null);
24
+ },
25
+ };
26
+ }
27
+
28
+ const loadImage = async (url: string) => new Uint8Array(await (await fetch(url)).arrayBuffer());
29
+ const images: { [key: string]: Uint8Array } = {
30
+ fat12: await loadImage("test/fat12.img"),
31
+ fat16: await loadImage("test/fat16.img"),
32
+ fat32: await loadImage("test/fat32.img"),
33
+ };
34
+
35
+ const writeBuf = new Uint8Array(4096 * 4);
36
+ for (let i = 0; i < writeBuf.length; ++i) {
37
+ writeBuf[i] = i % 256;
38
+ }
39
+
40
+ const testRead = async (fs: FileSystem) => {
41
+ const readBuf = new Uint8Array(writeBuf.length);
42
+ const fd = await fs.fopen(file, "r", 0o666);
43
+ assert.equal((await fs.fstat(fd)).size, writeBuf.length);
44
+ assert.equal(await fs.fread(fd, readBuf, 0, readBuf.length, 0), readBuf.length);
45
+ assert.deepEqual(readBuf, writeBuf);
46
+ await fs.fclose(fd);
47
+ };
48
+
49
+ const testOpenWriteStatClose = async (fs: FileSystem) => {
50
+ try {
51
+ await fs.mkdir(baseDir);
52
+ } catch (e) {
53
+ // ignore if exists
54
+ }
55
+ const fd = await fs.fopen(file, "w", 0o666);
56
+ assert.ok(fd);
57
+ assert.equal(await fs.fwrite(fd, writeBuf, 0, writeBuf.length, null), writeBuf.length);
58
+ await fs.fclose(fd);
59
+ await testRead(fs);
60
+ };
61
+
62
+ const testHelpers = async (fs: FileSystem) => {
63
+ assert.isFalse(await fs.exists("/not-exists"), "/not-exists not exits");
64
+ assert.isTrue(await fs.exists(baseDir), "baseDir exists");
65
+ assert.isTrue(await fs.exists(file), "file exists");
66
+ assert.isTrue(await fs.isdir(baseDir), "baseDir is dir");
67
+ assert.isFalse(await fs.isdir(file), "file is file");
68
+ };
69
+
70
+ for (const name of Object.keys(images)) {
71
+ const driver = () => createDriver(images[name]);
72
+ const fs = () => new Promise<FileSystemApi>((resolve, reject) => {
73
+ const fs = createFileSystem(driver(), {}, (ev, reason) => {
74
+ if (ev === "ready") {
75
+ resolve(fs);
76
+ } else {
77
+ console.error(ev, reason);
78
+ reject(reason);
79
+ }
80
+ });
81
+ });
82
+ suite(name + ".driver");
83
+
84
+ test("create driver", () => {
85
+ assert.exists(driver());
86
+ });
87
+
88
+ test("create fs", async () => {
89
+ assert.exists(await fs());
90
+ });
91
+
92
+ const testFs = (name: string, fn: (fs: FileSystem) => Promise<void>) => {
93
+ test(name, async () => fn(new FileSystem(await fs())));
94
+ };
95
+
96
+ testFs("api", async (fs) => {
97
+ for (const method of [
98
+ "mkdir", "readdir",
99
+ // "rename", "unlink", "rmdir",
100
+ "fclose", "fopen", "fwrite", "fread", "fstat",
101
+ "stat", "exists", "isdir",
102
+ // "fsync",
103
+ // "ftruncate", "truncate",
104
+ // "readFile", "writeFile", "appendFile",
105
+
106
+ // "chown", "lchown", "fchown",
107
+ // "chmod", "lchmod", "fchmod",
108
+ // "utimes", "futimes",
109
+ // "lstat", "fstat",
110
+ // "link", "symlink", "readlink", "realpath",
111
+
112
+ // 'watchfile','unwatchfile','watch'
113
+ ]) {
114
+ assert.ok(method in fs, "fs." + method + " has implementation.");
115
+ };
116
+ });
117
+
118
+ testFs("readdir", async (fs) => {
119
+ const files = await fs.readdir("/");
120
+ assert.ok(Array.isArray(files));
121
+ assert.ok(files.length === 0, "image is empty");
122
+ });
123
+
124
+ testFs("mkdir", async (fs) => {
125
+ await fs.mkdir(baseDir);
126
+ assert.ok((await fs.readdir(baseDir)).length === 0, "base dir is empty");
127
+ const root = await fs.readdir("/");
128
+ assert.ok(root.length === 1, "root have 1 folder");
129
+ assert.equal("/" + root[0], baseDir);
130
+ });
131
+
132
+ testFs("open/write/stat/read/close", testOpenWriteStatClose);
133
+
134
+ testFs("exists/isdir", async (fs) => {
135
+ await testOpenWriteStatClose(fs);
136
+ await testHelpers(fs);
137
+ });
138
+ }
139
+
140
+ suite("sockdrive 127.0.0.1:8001");
141
+
142
+ test("error on wrong drive name", (done) => {
143
+ createSockdriveFileSystem("ws://127.0.0.1:8001", "system", "not-exists", "",
144
+ () => { },
145
+ (e) => {
146
+ assert.strictEqual(e.message, "Err: no such drive");
147
+ done();
148
+ });
149
+ });
150
+
151
+ const testSd = (name: string, fn: (fs: FileSystem) => Promise<void>, writeCheck?: number[]) => {
152
+ test(name, async () => {
153
+ const { stats, fs, close } = await createSockdriveFileSystem("ws://127.0.0.1:8001", "system", "test", "",
154
+ (read, write) => {
155
+ assert.isTrue(read, "read access");
156
+ assert.isTrue(write, "write access");
157
+ });
158
+ await fn(fs);
159
+ await new Promise<void>((resolve) => {
160
+ setTimeout(resolve, 16);
161
+ });
162
+ await close();
163
+ if (writeCheck) {
164
+ assert.isTrue(writeCheck.findIndex((v) => v === stats.write) >= 0,
165
+ "write check " + stats.write + " in " + writeCheck);
166
+ }
167
+ });
168
+ };
169
+
170
+ testSd("connect", async (fs) => {
171
+ assert.ok(fs);
172
+ });
173
+
174
+ testSd("readdir /", async (fs) => {
175
+ assert.ok(await fs.readdir("/"));
176
+ });
177
+
178
+ testSd("open/write/stat/read/close", testOpenWriteStatClose);
179
+ testSd("reconnect stat/read/close", testRead);
180
+ testSd("exists/isdir", testHelpers);
181
+
182
+
183
+ mocha.run();
184
+ }
185
+
186
+ (window as any).runTests = runTests;
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "./dist/",
4
+ "noImplicitAny": true,
5
+ "module": "es6",
6
+ "target": "es6",
7
+ "jsx": "react",
8
+ "allowJs": true,
9
+ "moduleResolution": "node"
10
+ }
11
+ }
@@ -0,0 +1,68 @@
1
+ const path = require("path");
2
+ const { Compilation, sources, ProvidePlugin } = require("webpack");
3
+ const ESLintPlugin = require("eslint-webpack-plugin");
4
+
5
+ module.exports = {
6
+ devtool: "source-map",
7
+ mode: "production",
8
+ entry: {
9
+ sockdriveFat: "./src/sockdrive-fat.ts",
10
+ sockdriveNative: "./src/sockdrive-native.ts",
11
+ test: "./src/test/test.ts",
12
+ },
13
+ module: {
14
+ rules: [
15
+ {
16
+ test: /\.tsx?$/,
17
+ use: "ts-loader",
18
+ exclude: /node_modules/,
19
+ },
20
+ ],
21
+ },
22
+ resolve: {
23
+ extensions: [".tsx", ".ts", ".js"],
24
+ fallback: {
25
+ stream: require.resolve("stream-browserify"),
26
+ buffer: require.resolve("buffer"),
27
+ },
28
+ },
29
+ output: {
30
+ filename: "[name].js",
31
+ path: path.resolve(__dirname, "dist"),
32
+ },
33
+ plugins: [
34
+ {
35
+ apply(compiler) {
36
+ compiler.hooks.thisCompilation.tap("Replace", (compilation) => {
37
+ compilation.hooks.processAssets.tap(
38
+ {
39
+ name: "R_PLUGIN",
40
+ stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH,
41
+ },
42
+ () => {
43
+ compilation.updateAsset("sockdriveNative.js",
44
+ new sources.RawSource(
45
+ "R\"'''(" +
46
+ compilation.getAsset("sockdriveNative.js").source.source() +
47
+ ")'''\""),
48
+ );
49
+ },
50
+ );
51
+ });
52
+ },
53
+ },
54
+ new ProvidePlugin({
55
+ process: "process/browser",
56
+ Buffer: ["buffer", "Buffer"],
57
+ }),
58
+ new ESLintPlugin({
59
+ fix: true,
60
+ extensions: ["ts"],
61
+ useEslintrc: false,
62
+ overrideConfigFile: ".eslintrc.json",
63
+ }),
64
+ ],
65
+ optimization: {
66
+ minimize: true,
67
+ },
68
+ };