Skip to content

Commit

Permalink
feat: 🎸 implement initial version of .open() mehtod
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 20, 2023
1 parent e046128 commit b3983df
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 10 deletions.
56 changes: 48 additions & 8 deletions src/fsa-to-node/FsaNodeFs.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { createPromisesApi } from '../node/promises';
import { getDefaultOptsAndCb, getMkdirOptions, getReadFileOptions, getRmOptsAndCb, getRmdirOptions, optsAndCbGenerator } from '../node/options';
import { createError, flagsToNumber, genRndStr6, nullCheck, pathToFilename, validateCallback } from '../node/util';
import { createError, flagsToNumber, genRndStr6, modeToNumber, nullCheck, pathToFilename, validateCallback } from '../node/util';
import { pathToLocation } from './util';
import { MODE } from '../node/constants';
import { strToEncoding } from '../encoding';
import { FsaToNodeConstants } from './constants';
import {bufferToEncoding} from '../volume';
import {FsaNodeFsOpenFile} from './FsaNodeFsOpenFile';
import type { FsCallbackApi, FsPromisesApi } from '../node/types';
import type * as misc from '../node/types/misc';
import type * as opts from '../node/types/options';
import type * as fsa from '../fsa/types';
import {bufferToEncoding} from '../volume';

// const notImplemented: (...args: unknown[]) => unknown = () => {
// throw new Error('Not implemented');
Expand All @@ -20,11 +21,24 @@ import {bufferToEncoding} from '../volume';
* [`FileSystemDirectoryHandle` object](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
*/
export class FsaNodeFs implements FsCallbackApi {
public static fd: number = 0x7fffffff;

public readonly promises: FsPromisesApi = createPromisesApi(this);
public readonly fs = new Map<number, fsa.IFileSystemFileHandle>();
public readonly fds = new Map<number, FsaNodeFsOpenFile>();

public constructor(protected readonly root: fsa.IFileSystemDirectoryHandle) {}

/**
* A list of reusable (opened and closed) file descriptors, that should be
* used first before creating a new file descriptor.
*/
releasedFds: number[] = [];

private newFdNumber(): number {
const releasedFd = this.releasedFds.pop();
return typeof releasedFd === 'number' ? releasedFd : FsaNodeFs.fd--;
}

/**
* @param path Path from root to the new folder.
* @param create Whether to create the folders if they don't exist.
Expand All @@ -48,13 +62,42 @@ export class FsaNodeFs implements FsCallbackApi {
return file;
}

private async getFileById(id: misc.TFileId, funcName?: string): Promise<fsa.IFileSystemFileHandle> {
if (typeof id === 'number') {
const file = this.fds.get(id);
if (!file) throw createError('EBADF', funcName);
return file.file;
}
const filename = pathToFilename(id);
const [folder, name] = pathToLocation(filename);
return await this.getFile(folder, name, funcName);
}

public readonly open: FsCallbackApi['open'] = (
path: misc.PathLike,
flags: misc.TFlags,
a?: misc.TMode | misc.TCallback<number>,
b?: misc.TCallback<number> | string,
) => {
throw new Error('Not implemented');
let mode: misc.TMode = a as misc.TMode;
let callback: misc.TCallback<number> = b as misc.TCallback<number>;
if (typeof a === 'function') {
mode = MODE.DEFAULT;
callback = a;
}
mode = mode || MODE.DEFAULT;
const modeNum = modeToNumber(mode);
const filename = pathToFilename(path);
const flagsNum = flagsToNumber(flags);
const [folder, name] = pathToLocation(filename);
this.getFile(folder, name, 'open')
.then((file) => {
const fd = this.newFdNumber();
const openFile = new FsaNodeFsOpenFile(fd, modeNum, flagsNum, file);
this.fds.set(fd, openFile);
callback(null, fd);
})
.catch((error) => callback(error));
};

public readonly close: FsCallbackApi['close'] = (fd: number, callback: misc.TCallback<void>): void => {
Expand All @@ -79,10 +122,7 @@ export class FsaNodeFs implements FsCallbackApi {
) => {
const [opts, callback] = optsAndCbGenerator<opts.IReadFileOptions, misc.TDataOut>(getReadFileOptions)(a, b);
const flagsNum = flagsToNumber(opts.flag);
if (typeof id === 'number') throw new Error('Not implemented');
const filename = pathToFilename(id);
const [folder, name] = pathToLocation(filename);
return this.getFile(folder, name, 'readFile')
return this.getFileById(id, 'readFile')
.then(file => file.getFile())
.then(file => file.arrayBuffer())
.then(data => {
Expand Down
11 changes: 11 additions & 0 deletions src/fsa-to-node/FsaNodeFsOpenFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type * as fsa from '../fsa/types';
import type * as misc from '../node/types/misc';

export class FsaNodeFsOpenFile {
public constructor (
public readonly fd: number,
public readonly mode: misc.TMode,
public readonly flags: number,
public readonly file: fsa.IFileSystemFileHandle,
) {}
}
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 @@ -198,5 +198,12 @@ describe('.readFile()', () => {
const data = await fs.promises.readFile('/folder/file');
expect(data.toString()).toBe('test');
});

test('can read file by file descriptor', async () => {
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
const fd = await fs.promises.open('/folder/file');
const data = await fs.promises.readFile(fd);
expect(data.toString()).toBe('test');
});
});

2 changes: 1 addition & 1 deletion src/node/promises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function createPromisesApi(vol: FsCallbackApi): FsPromisesApi {
return promisify(vol, 'mkdtemp')(prefix, options);
},

open(path: misc.PathLike, flags: misc.TFlags, mode?: misc.TMode) {
open(path: misc.PathLike, flags: misc.TFlags = 'r', mode?: misc.TMode) {
return promisify(vol, 'open', fd => new FileHandle(vol, fd))(path, flags, mode);
},

Expand Down
2 changes: 1 addition & 1 deletion src/node/types/promises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface FsPromisesApi {
lstat(path: misc.PathLike, options?: opts.IStatOptions): Promise<misc.IStats>;
mkdir(path: misc.PathLike, options?: misc.TMode | opts.IMkdirOptions): Promise<void>;
mkdtemp(prefix: string, options?: opts.IOptions): Promise<misc.TDataOut>;
open(path: misc.PathLike, flags: misc.TFlags, mode?: misc.TMode): Promise<misc.IFileHandle>;
open(path: misc.PathLike, flags?: misc.TFlags, mode?: misc.TMode): Promise<misc.IFileHandle>;
readdir(path: misc.PathLike, options?: opts.IReaddirOptions | string): Promise<misc.TDataOut[] | misc.IDirent[]>;
readFile(id: misc.TFileHandle, options?: opts.IReadFileOptions | string): Promise<misc.TDataOut>;
readlink(path: misc.PathLike, options?: opts.IOptions): Promise<misc.TDataOut>;
Expand Down

0 comments on commit b3983df

Please sign in to comment.