Skip to content

Commit

Permalink
feat: 🎸 implement first version of worker
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 18, 2023
1 parent d221870 commit caf8394
Show file tree
Hide file tree
Showing 12 changed files with 383 additions and 190 deletions.
88 changes: 48 additions & 40 deletions demo/fsa/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,63 @@
(window as any).Buffer = require('buffer').Buffer;

import type * as fsa from '../../src/fsa/types';
import {fsaToNode} from '../../src/fsa-to-node';
import {SyncMessenger} from '../../src/fsa-to-node/worker/SyncMessenger';
import {encode, decode} from 'json-joy/es6/json-pack/msgpack/util';
import {FsaNodeFs, FsaNodeSyncAdapterWorker} from '../../src/fsa-to-node';

const demo = async (dir: fsa.IFileSystemDirectoryHandle) => {
const fs = fsaToNode(dir);
console.log('demo', dir);
const adapter = await FsaNodeSyncAdapterWorker.start(dir);
const fs = new FsaNodeFs(dir, adapter);

await fs.promises.writeFile('/test.txt', 'Hello world!');
const list = await fs.promises.readdir('');
console.log(list);
await fs.promises.writeFile('test.txt', 'Hello world!');
await fs.promises.mkdir('storage/a/b/c', {recursive: true});
await fs.promises.rm('storage/a/b', {recursive: true});

const stats = fs.statSync('/test.txt');
console.log('stats', stats, stats.isDirectory(), stats.isFile());
// await fs.promises.mkdir('storage/a/b/c', {recursive: true});
// await fs.promises.rm('storage/a/b', {recursive: true});


const stream = fs.createWriteStream('stream.txt');
stream.write('abc');
stream.write('def');
stream.end('ghi');
// const stream = fs.createWriteStream('stream.txt');
// stream.write('abc');
// stream.write('def');
// stream.end('ghi');

const worker = new Worker('https://localhost:9876/worker.js');
worker.onerror = (e) => {
console.log("error", e);
};
// const worker = new Worker('https://localhost:9876/worker.js');
// worker.onerror = (e) => {
// console.log("error", e);
// };

let sab: SharedArrayBuffer | undefined = undefined;
let channel: SyncMessenger | undefined = undefined;
// let sab: SharedArrayBuffer | undefined = undefined;
// let channel: SyncMessenger | undefined = undefined;

worker.onmessage = (e) => {
const data = e.data;
if (data && typeof data === 'object') {
console.log('<', data);
switch (data.type) {
case 'init': {
sab = data.sab;
channel = new SyncMessenger(sab!);
worker.postMessage({type: 'set-root', dir, id: 0});
break;
}
case 'root-set': {
console.log('READY');
const request = encode({type: 'readdir', path: ''});
console.log('call sync', request);
const response = channel!.callSync(request);
const responseDecoded = decode(response as any);
console.log('response', responseDecoded);
break;
}
}
}
};
// worker.onmessage = (e) => {
// const data = e.data;
// if (data && typeof data === 'object') {
// console.log('<', data);
// switch (data.type) {
// case 'init': {
// sab = data.sab;
// channel = new SyncMessenger(sab!);
// worker.postMessage({type: 'set-root', dir, id: 0});
// break;
// }
// case 'root-set': {
// console.log('READY');

// const request = encode({type: 'readdir', path: ''});
// console.log('call sync', request);
// const response = channel!.callSync(request);
// const responseDecoded = decode(response as any);
// console.log('response', responseDecoded);
// console.log('READY');


// break;
// }
// }
// }
// };



Expand Down
34 changes: 5 additions & 29 deletions demo/fsa/worker.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,6 @@
import {SyncMessenger} from "../../src/fsa-to-node/worker/SyncMessenger";
import {encode, decode} from 'json-joy/es6/json-pack/msgpack/util';
import {IFileSystemDirectoryHandle} from "../../src/fsa/types";
import {FsaNodeSyncWorker} from "../../src/fsa-to-node/worker/FsaNodeSyncWorker";

const sab: SharedArrayBuffer = new SharedArrayBuffer(1024 * 32);
const messenger = new SyncMessenger(sab);

onmessage = (e) => {
const data = e.data;
console.log('>', data);
if (data && typeof data === 'object') {
switch (data.type) {
case 'set-root': {
postMessage({type: 'root-set', id: data.id});
const dir = data.dir as IFileSystemDirectoryHandle;
messenger.serveAsync(async (request) => {
const message = decode(request as any);
const list: string[] = [];
for await (const key of dir.keys()) {
list.push(key);
}
return encode(list);
});
break;
}
}
}
};

postMessage({type: 'init', sab});
if (typeof window === 'undefined') {
const worker = new FsaNodeSyncWorker();
worker.start();
}
121 changes: 121 additions & 0 deletions src/fsa-to-node/FsaNodeCore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import {
createError,
isFd,
pathToFilename,
} from '../node/util';
import { pathToLocation} from './util';
import { ERRSTR} from '../node/constants';
import { FsaToNodeConstants } from './constants';
import { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile';
import { FLAG } from '../consts/FLAG';
import type * as fsa from '../fsa/types';
import type * as misc from '../node/types/misc';
import type {FsaNodeSyncAdapter} from './types';

export class FsaNodeCore {
protected static fd: number = 0x7fffffff;
protected readonly fds = new Map<number, FsaNodeFsOpenFile>();

public constructor(
protected readonly root: fsa.IFileSystemDirectoryHandle,
protected syncAdapter?: FsaNodeSyncAdapter,
) {}

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

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

/**
* @param path Path from root to the new folder.
* @param create Whether to create the folders if they don't exist.
*/
protected async getDir(path: string[], create: boolean, funcName?: string): Promise<fsa.IFileSystemDirectoryHandle> {
let curr: fsa.IFileSystemDirectoryHandle = this.root;

const options: fsa.GetDirectoryHandleOptions = { create };

try {
for (const name of path) {
curr = await curr.getDirectoryHandle(name, options);
}
} catch (error) {
if (error && typeof error === 'object' && error.name === 'TypeMismatchError')
throw createError('ENOTDIR', funcName, path.join(FsaToNodeConstants.Separator));
throw error;
}
return curr;
}

protected async getFile(
path: string[],
name: string,
funcName?: string,
create?: boolean,
): Promise<fsa.IFileSystemFileHandle> {
const dir = await this.getDir(path, false, funcName);
const file = await dir.getFileHandle(name, { create });
return file;
}

protected async getFileOrDir(
path: string[],
name: string,
funcName?: string,
create?: boolean,
): Promise<fsa.IFileSystemFileHandle | fsa.IFileSystemDirectoryHandle> {
const dir = await this.getDir(path, false, funcName);
try {
const file = await dir.getFileHandle(name);
return file;
} catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
return await dir.getDirectoryHandle(name);
case 'NotFoundError':
throw createError('ENOENT', funcName, path.join(FsaToNodeConstants.Separator));
}
}
throw error;
}
}

protected async getFileByFd(fd: number, funcName?: string): Promise<FsaNodeFsOpenFile> {
if (!isFd(fd)) throw TypeError(ERRSTR.FD);
const file = this.fds.get(fd);
if (!file) throw createError('EBADF', funcName);
return file;
}

protected async getFileById(id: misc.TFileId, funcName?: string, create?: boolean): Promise<fsa.IFileSystemFileHandle> {
if (typeof id === 'number') return (await this.getFileByFd(id, funcName)).file;
const filename = pathToFilename(id);
const [folder, name] = pathToLocation(filename);
return await this.getFile(folder, name, funcName, create);
}

protected async getFileByIdOrCreate(id: misc.TFileId, funcName?: string): Promise<fsa.IFileSystemFileHandle> {
if (typeof id === 'number') return (await this.getFileByFd(id, funcName)).file;
const filename = pathToFilename(id);
const [folder, name] = pathToLocation(filename);
const dir = await this.getDir(folder, false, funcName);
return await dir.getFileHandle(name, { create: true });
}

protected async __open(filename: string, flags: number, mode: number): Promise<FsaNodeFsOpenFile> {
const [folder, name] = pathToLocation(filename);
const createIfMissing = !!(flags & FLAG.O_CREAT);
const fsaFile = await this.getFile(folder, name, 'open', createIfMissing);
const fd = this.newFdNumber();
const file = new FsaNodeFsOpenFile(fd, mode, flags, fsaFile);
this.fds.set(fd, file);
return file;
}
}
Loading

0 comments on commit caf8394

Please sign in to comment.