@zenfs/core 0.6.0 → 0.7.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.
@@ -1,253 +0,0 @@
1
- import { FileSystem, Sync } from '../filesystem.js';
2
- import { ApiError, ErrorCode } from '../ApiError.js';
3
- import { PreloadFile, parseFlag } from '../file.js';
4
- import { join } from '../emulation/path.js';
5
- import { rootCred } from '../cred.js';
6
- /**
7
- * We define our own file to interpose on syncSync() for mirroring purposes.
8
- * @internal
9
- */
10
- export class MirrorFile extends PreloadFile {
11
- constructor(fs, path, flag, stat, data) {
12
- super(fs, path, flag, stat, data);
13
- }
14
- async sync() {
15
- this.syncSync();
16
- }
17
- syncSync() {
18
- if (this.isDirty()) {
19
- this.fs.syncSync(this.path, this._buffer, this.stats);
20
- this.resetDirty();
21
- }
22
- }
23
- async close() {
24
- this.closeSync();
25
- }
26
- closeSync() {
27
- this.syncSync();
28
- }
29
- }
30
- /**
31
- * AsyncMirrorFS mirrors a synchronous filesystem into an asynchronous filesystem
32
- * by:
33
- *
34
- * * Performing operations over the in-memory copy, while asynchronously pipelining them
35
- * to the backing store.
36
- * * During application loading, the contents of the async file system can be reloaded into
37
- * the synchronous store, if desired.
38
- *
39
- * The two stores will be kept in sync. The most common use-case is to pair a synchronous
40
- * in-memory filesystem with an asynchronous backing store.
41
- *
42
- */
43
- export class AsyncMirrorFS extends Sync(FileSystem) {
44
- async ready() {
45
- await this._ready;
46
- return this;
47
- }
48
- /**
49
- *
50
- * Mirrors the synchronous file system into the asynchronous file system.
51
- *
52
- * @param sync The synchronous file system to mirror the asynchronous file system to.
53
- * @param async The asynchronous file system to mirror.
54
- */
55
- constructor({ sync, async }) {
56
- super();
57
- /**
58
- * Queue of pending asynchronous operations.
59
- */
60
- this._queue = [];
61
- this._queueRunning = false;
62
- this._isInitialized = false;
63
- this._sync = sync;
64
- this._async = async;
65
- this._ready = this._initialize();
66
- }
67
- metadata() {
68
- return {
69
- ...super.metadata(),
70
- name: AsyncMirrorFS.name,
71
- synchronous: true,
72
- supportsProperties: this._sync.metadata().supportsProperties && this._async.metadata().supportsProperties,
73
- };
74
- }
75
- syncSync(path, data, stats) {
76
- this._sync.syncSync(path, data, stats);
77
- this.enqueue({
78
- apiMethod: 'sync',
79
- arguments: [path, data, stats],
80
- });
81
- }
82
- openFileSync(path, flag, cred) {
83
- return this._sync.openFileSync(path, flag, cred);
84
- }
85
- createFileSync(path, flag, mode, cred) {
86
- const file = this._sync.createFileSync(path, flag, mode, cred);
87
- this.enqueue({
88
- apiMethod: 'createFile',
89
- arguments: [path, flag, mode, cred],
90
- });
91
- const stats = file.statSync();
92
- const buffer = new Uint8Array(stats.size);
93
- file.readSync(buffer);
94
- return new MirrorFile(this, path, flag, stats, buffer);
95
- }
96
- linkSync(srcpath, dstpath, cred) {
97
- this._sync.linkSync(srcpath, dstpath, cred);
98
- this.enqueue({
99
- apiMethod: 'link',
100
- arguments: [srcpath, dstpath, cred],
101
- });
102
- }
103
- renameSync(oldPath, newPath, cred) {
104
- this._sync.renameSync(oldPath, newPath, cred);
105
- this.enqueue({
106
- apiMethod: 'rename',
107
- arguments: [oldPath, newPath, cred],
108
- });
109
- }
110
- statSync(p, cred) {
111
- return this._sync.statSync(p, cred);
112
- }
113
- unlinkSync(p, cred) {
114
- this._sync.unlinkSync(p, cred);
115
- this.enqueue({
116
- apiMethod: 'unlink',
117
- arguments: [p, cred],
118
- });
119
- }
120
- rmdirSync(p, cred) {
121
- this._sync.rmdirSync(p, cred);
122
- this.enqueue({
123
- apiMethod: 'rmdir',
124
- arguments: [p, cred],
125
- });
126
- }
127
- mkdirSync(p, mode, cred) {
128
- this._sync.mkdirSync(p, mode, cred);
129
- this.enqueue({
130
- apiMethod: 'mkdir',
131
- arguments: [p, mode, cred],
132
- });
133
- }
134
- readdirSync(p, cred) {
135
- return this._sync.readdirSync(p, cred);
136
- }
137
- existsSync(p, cred) {
138
- return this._sync.existsSync(p, cred);
139
- }
140
- /**
141
- * @internal
142
- */
143
- async crossCopyDirectory(p, mode) {
144
- if (p !== '/') {
145
- const stats = await this._async.stat(p, rootCred);
146
- this._sync.mkdirSync(p, mode, stats.cred());
147
- }
148
- const files = await this._async.readdir(p, rootCred);
149
- for (const file of files) {
150
- await this.crossCopy(join(p, file));
151
- }
152
- }
153
- /**
154
- * @internal
155
- */
156
- async crossCopyFile(p, mode) {
157
- const asyncFile = await this._async.openFile(p, parseFlag('r'), rootCred);
158
- const syncFile = this._sync.createFileSync(p, parseFlag('w'), mode, rootCred);
159
- try {
160
- const { size } = await asyncFile.stat();
161
- const buffer = new Uint8Array(size);
162
- await asyncFile.read(buffer);
163
- syncFile.writeSync(buffer);
164
- }
165
- finally {
166
- await asyncFile.close();
167
- syncFile.closeSync();
168
- }
169
- }
170
- /**
171
- * @internal
172
- */
173
- async crossCopy(p) {
174
- const stats = await this._async.stat(p, rootCred);
175
- if (stats.isDirectory()) {
176
- await this.crossCopyDirectory(p, stats.mode);
177
- }
178
- else {
179
- await this.crossCopyFile(p, stats.mode);
180
- }
181
- }
182
- /**
183
- * Called once to load up files from async storage into sync storage.
184
- */
185
- async _initialize() {
186
- if (this._isInitialized) {
187
- return;
188
- }
189
- try {
190
- await this.crossCopy('/');
191
- this._isInitialized = true;
192
- }
193
- catch (e) {
194
- this._isInitialized = false;
195
- throw e;
196
- }
197
- }
198
- /**
199
- * @internal
200
- */
201
- async _next() {
202
- if (this._queue.length == 0) {
203
- this._queueRunning = false;
204
- return;
205
- }
206
- const op = this._queue.shift();
207
- try {
208
- // @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
209
- await this._async[op.apiMethod](...op.arguments);
210
- }
211
- catch (e) {
212
- throw new ApiError(ErrorCode.EIO, 'AsyncMirror desync: ' + e);
213
- }
214
- await this._next();
215
- }
216
- /**
217
- * @internal
218
- */
219
- enqueue(op) {
220
- this._queue.push(op);
221
- if (this._queueRunning) {
222
- return;
223
- }
224
- this._queueRunning = true;
225
- this._next();
226
- }
227
- }
228
- export const AsyncMirror = {
229
- name: 'AsyncMirror',
230
- options: {
231
- sync: {
232
- type: 'object',
233
- required: true,
234
- description: 'The synchronous file system to mirror the asynchronous file system to.',
235
- validator: async (backend) => {
236
- if ('metadata' in backend && !backend.metadata().synchronous) {
237
- throw new ApiError(ErrorCode.EINVAL, '"sync" option must be a file system that supports synchronous operations');
238
- }
239
- },
240
- },
241
- async: {
242
- type: 'object',
243
- required: true,
244
- description: 'The asynchronous file system to mirror.',
245
- },
246
- },
247
- isAvailable() {
248
- return true;
249
- },
250
- create(options) {
251
- return new AsyncMirrorFS(options);
252
- },
253
- };