Skip to content

Commit

Permalink
feat: 🎸 add appendFileSync() method
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 18, 2023
1 parent da028c4 commit 27411e4
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 11 deletions.
4 changes: 4 additions & 0 deletions demo/fsa/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ const demo = async (dir: fsa.IFileSystemDirectoryHandle) => {
console.log('writeFileSync() - can write text to a new file');
fs.writeFileSync('/cool.txt', 'worlds');
strictEqual(fs.readFileSync('/cool.txt', 'utf8'), 'worlds');

console.log('appendFileSync() - can append to an existing file');
fs.appendFileSync('/cool.txt', '!');
strictEqual(fs.readFileSync('/cool.txt', 'utf8'), 'worlds!');
};

const main = async () => {
Expand Down
12 changes: 11 additions & 1 deletion src/fsa-to-node/FsaNodeFs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getWriteFileOptions,
getOptions,
getStatOptions,
getAppendFileOpts,
} from '../node/options';
import {
bufToUint8,
Expand All @@ -29,6 +30,7 @@ import {
pathToFilename,
validateCallback,
validateFd,
isFd,
} from '../node/util';
import { pathToLocation, testDirectoryIsWritable } from './util';
import { ERRSTR, MODE } from '../node/constants';
Expand Down Expand Up @@ -815,6 +817,15 @@ export class FsaNodeFs extends FsaNodeCore implements FsCallbackApi, FsSynchrono
adapter.call('writeFile', { filename, data: bufToUint8(buf), opts });
};

public readonly appendFileSync: FsSynchronousApi['appendFileSync'] = (id: misc.TFileId, data: misc.TData, options?: opts.IAppendFileOptions | string) => {
const opts = getAppendFileOpts(options);
if (!opts.flag || isFd(id)) opts.flag = 'a';
const filename = this.getFileName(id);
const buf = dataToBuffer(data, opts.encoding);
const adapter = this.getSyncAdapter();
adapter.call('appendFile', { filename, data: bufToUint8(buf), opts });
};

public readonly closeSync: FsSynchronousApi['closeSync'] = (fd: number) => {
validateFd(fd);
const file = this.getFileByFd(fd, 'close');
Expand All @@ -832,7 +843,6 @@ export class FsaNodeFs extends FsaNodeCore implements FsCallbackApi, FsSynchrono
}
};

public readonly appendFileSync: FsSynchronousApi['appendFileSync'] = notSupported;
public readonly copyFileSync: FsSynchronousApi['copyFileSync'] = notSupported;
public readonly ftruncateSync: FsSynchronousApi['ftruncateSync'] = notSupported;
public readonly linkSync: FsSynchronousApi['linkSync'] = notSupported;
Expand Down
7 changes: 7 additions & 0 deletions src/fsa-to-node/__tests__/FsaNodeFs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,13 @@ onlyOnNode20('FsaNodeFs', () => {
await fs.promises.appendFile('file', 'x');
expect(mfs.readFileSync('/mountpoint/file', 'utf8')).toBe('123x');
});

test('can append to a file - 2', async () => {
const { fs, mfs } = setup({ file: '123' });
await fs.promises.writeFile('cool.txt', 'worlds');
await fs.promises.appendFile('cool.txt', '!');
expect(mfs.readFileSync('/mountpoint/cool.txt', 'utf8')).toBe('worlds!');
});
});

describe('.write()', () => {
Expand Down
1 change: 1 addition & 0 deletions src/fsa-to-node/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface FsaNodeSyncAdapterApi {
access(req: { filename: string; mode: number }): void;
readFile(req: { filename: string; opts?: opts.IReadFileOptions }): Uint8Array;
writeFile(req: { filename: string; data: Uint8Array; opts?: opts.IWriteFileOptions }): void;
appendFile(req: { filename: string; data: Uint8Array; opts?: opts.IAppendFileOptions }): void;
}

export interface FsaNodeSyncAdapter {
Expand Down
3 changes: 3 additions & 0 deletions src/fsa-to-node/worker/FsaNodeSyncWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,8 @@ export class FsaNodeSyncWorker {
writeFile: async ({ filename, data, opts }): Promise<void> => {
await this.fs.promises.writeFile(filename, data, { ...opts, encoding: 'buffer' });
},
appendFile: async ({ filename, data, opts }): Promise<void> => {
await this.fs.promises.appendFile(filename, data, { ...opts, encoding: 'buffer' });
},
};
}
21 changes: 11 additions & 10 deletions src/fsa-to-node/worker/SyncMessenger.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
export type AsyncCallback = (request: Uint8Array) => Promise<Uint8Array>;

const microSleepSync = () => {
/** @todo Replace this by synchronous XHR call. */
Math.random();
// Math.random();
};

const sleepUntilSync = (condition: () => boolean) => {
Expand Down Expand Up @@ -38,12 +37,13 @@ export class SyncMessenger {
public callSync(data: Uint8Array): Uint8Array {
const requestLength = data.length;
const headerSize = this.headerSize;
this.int32[1] = 0;
this.int32[2] = requestLength;
const int32 = this.int32;
int32[1] = 0;
int32[2] = requestLength;
this.uint8.set(data, headerSize);
Atomics.notify(this.int32, 0);
sleepUntilSync(() => this.int32[1] === 1);
const responseLength = this.int32[2];
Atomics.notify(int32, 0);
sleepUntilSync(() => int32[1] === 1);
const responseLength = int32[2];
const response = this.uint8.slice(headerSize, headerSize + responseLength);
return response;
}
Expand All @@ -52,15 +52,16 @@ export class SyncMessenger {
const headerSize = this.headerSize;
(async () => {
try {
const res = Atomics.wait(this.int32, 0, 0);
const int32 = this.int32;
const res = Atomics.wait(int32, 0, 0);
if (res !== 'ok') throw new Error(`Unexpected Atomics.wait result: ${res}`);
const requestLength = this.int32[2];
const request = this.uint8.slice(headerSize, headerSize + requestLength);
const response = await callback(request);
const responseLength = response.length;
this.int32[2] = responseLength;
int32[2] = responseLength;
this.uint8.set(response, headerSize);
this.int32[1] = 1;
int32[1] = 1;
} catch {}
this.serveAsync(callback);
})().catch(() => {});
Expand Down

0 comments on commit 27411e4

Please sign in to comment.