Files
daedalOS/contexts/fileSystem/functions.ts

144 lines
3.6 KiB
TypeScript
Raw Normal View History

import { get } from "idb-keyval";
2022-02-15 12:53:07 -08:00
import { join } from "path";
2022-03-20 19:04:03 -07:00
import index from "public/.index/fs.9p.json";
2022-02-15 12:53:07 -08:00
import { FS_HANDLES } from "utils/constants";
2022-03-20 19:04:03 -07:00
type BFSFS = { [key: string]: BFSFS | null };
type FS9PV3 = [
string,
number,
number,
number,
number,
number,
FS9PV3[] | string
];
type FS9PV4 = [string, number, number, FS9PV4[] | string | undefined];
type FS9P = {
fsroot: FS9PV3[];
size: number;
version: 3;
};
const IDX_MTIME = 2;
const IDX_TARGET = 3;
const fsroot = index.fsroot as FS9PV4[];
const reduceObjects = <T>(a: T, b: T): T => ({ ...a, ...b });
export const get9pModifiedTime = (path: string): number => {
let fsPath = fsroot;
let mTime = 0;
path
.split("/")
.filter(Boolean)
.forEach((pathPart) => {
const pathBranch = fsPath.find(([name]) => name === pathPart);
if (pathBranch) {
const isBranch = Array.isArray(pathBranch[IDX_TARGET]);
if (!isBranch) mTime = pathBranch[IDX_MTIME];
fsPath = isBranch ? (pathBranch[IDX_TARGET] as FS9PV4[]) : [];
}
});
return mTime;
};
// eslint-disable-next-line unicorn/no-unreadable-array-destructuring
const parse9pEntry = ([name, , , pathOrArray]: FS9PV4): BFSFS => ({
[name]: Array.isArray(pathOrArray)
? // eslint-disable-next-line unicorn/no-array-callback-reference
pathOrArray.map(parse9pEntry).reduce(reduceObjects)
: // eslint-disable-next-line unicorn/no-null
null,
});
export const fs9pToBfs = (): BFSFS =>
// eslint-disable-next-line unicorn/no-array-callback-reference
fsroot.map(parse9pEntry).reduce(reduceObjects);
const parse9pV4ToV3 = (fs9p: FS9PV4[], path = "/"): FS9PV3[] =>
fs9p.map(([name, mtime, size, target]) => {
const targetPath = join(path, name);
const newTarget = Array.isArray(target)
? parse9pV4ToV3(target, targetPath)
: target || targetPath;
return [name, mtime, size, 33206, 0, 0, newTarget] as FS9PV3;
});
export const fs9pV4ToV3 = (): FS9P =>
index.version === 4
? {
fsroot: parse9pV4ToV3(fsroot),
size: index.size,
version: 3,
}
: (index as FS9P);
export const supportsIndexedDB = (): Promise<boolean> =>
new Promise((resolve) => {
2022-03-13 21:30:24 -07:00
const db = window.indexedDB.open("");
db.addEventListener("error", () => resolve(false));
2022-03-18 21:32:53 -07:00
db.addEventListener("success", () => {
resolve(true);
try {
db.result.close();
window.indexedDB.deleteDatabase("");
} catch {
// Ignore errors to close/delete the test database
}
});
});
2022-02-15 19:45:43 -08:00
export const getFileSystemHandles = async (): Promise<
Record<string, FileSystemDirectoryHandle>
> => ((await supportsIndexedDB()) && (await get(FS_HANDLES))) || {};
2022-02-15 19:45:43 -08:00
export const addFileSystemHandle = async (
2022-02-15 12:53:07 -08:00
directory: string,
handle: FileSystemDirectoryHandle
): Promise<void> => {
if (!(await supportsIndexedDB())) return;
const { set } = await import("idb-keyval");
2022-03-14 22:02:26 -07:00
await set(FS_HANDLES, {
...(await getFileSystemHandles()),
[join(directory, handle.name)]: handle,
});
};
2022-02-15 12:53:07 -08:00
2022-02-15 19:45:43 -08:00
export const removeFileSystemHandle = async (
directory: string
): Promise<void> => {
if (!(await supportsIndexedDB())) return;
2022-02-15 19:45:43 -08:00
const { [directory]: _, ...handles } = await getFileSystemHandles();
const { set } = await import("idb-keyval");
2022-02-15 19:45:43 -08:00
2022-03-14 22:02:26 -07:00
await set(FS_HANDLES, handles);
2022-02-15 19:45:43 -08:00
};
2022-03-03 21:56:11 -08:00
export const requestPermission = async (
url: string
): Promise<PermissionState | false> => {
const fsHandles = await getFileSystemHandles();
const handle = fsHandles[url];
if (handle) {
if ((await handle.queryPermission()) === "prompt") {
await handle.requestPermission();
}
return handle.queryPermission();
}
return false;
};