53 lines
2.8 KiB
TypeScript
53 lines
2.8 KiB
TypeScript
// Project utility files retain their directory structure in OPFS.
|
|
export async function writeProjectUtilityFiles(directory: string,
|
|
files: Array<{ filename: string; contentsBase64: string }>): Promise<void> {
|
|
if (!directory.trim() || /[\\/]/.test(directory) || [".", ".."].includes(directory))
|
|
throw new Error("Choose a project folder name");
|
|
const root = await navigator.storage.getDirectory();
|
|
const projects = await root.getDirectoryHandle("freecad-project-utility", { create: true });
|
|
const destination = await projects.getDirectoryHandle(directory, { create: true });
|
|
for (const file of files) {
|
|
const parts = file.filename.split("/");
|
|
if (parts.some(part => !part || part === "." || part === ".." || part.includes("\\")))
|
|
throw new Error("Invalid project file path");
|
|
let parent = destination;
|
|
for (const part of parts.slice(0, -1)) parent = await parent.getDirectoryHandle(part, { create: true });
|
|
const handle = await parent.getFileHandle(parts[parts.length - 1], { create: true });
|
|
const writer = await handle.createWritable();
|
|
try {
|
|
await writer.write(Uint8Array.from(atob(file.contentsBase64), char => char.charCodeAt(0)));
|
|
await writer.close();
|
|
} catch (error) { await writer.abort().catch(() => undefined); throw error; }
|
|
}
|
|
}
|
|
|
|
export async function readProjectUtilityFiles(directory: string): Promise<Array<{ filename: string; contentsBase64: string }>> {
|
|
if (!directory.trim() || /[\\/]/.test(directory) || [".", ".."].includes(directory))
|
|
throw new Error("Choose a project folder name");
|
|
const root = await navigator.storage.getDirectory();
|
|
const projects = await root.getDirectoryHandle("freecad-project-utility");
|
|
const source = await projects.getDirectoryHandle(directory);
|
|
const files: Array<{ filename: string; contentsBase64: string }> = [];
|
|
async function visit(handle: FileSystemDirectoryHandle, prefix: string): Promise<void> {
|
|
// The iterable DOM declaration is not available in every TypeScript DOM lib.
|
|
const iterable = handle as FileSystemDirectoryHandle & {
|
|
entries(): AsyncIterableIterator<[string, FileSystemHandle]>;
|
|
};
|
|
for await (const [name, entry] of iterable.entries()) {
|
|
if (entry.kind === "directory") await visit(entry as FileSystemDirectoryHandle, prefix + name + "/");
|
|
else files.push({ filename: prefix + name,
|
|
contentsBase64: await encodeProjectFile(await (entry as FileSystemFileHandle).getFile()) });
|
|
}
|
|
}
|
|
await visit(source, "");
|
|
return files;
|
|
}
|
|
|
|
export async function encodeProjectFile(file: Blob): Promise<string> {
|
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
let binary = "";
|
|
for (let offset = 0; offset < bytes.length; offset += 8192)
|
|
binary += String.fromCharCode(...bytes.subarray(offset, offset + 8192));
|
|
return btoa(binary);
|
|
}
|