@peterspackman/occjs
Version:
JavaScript/WebAssembly bindings for OCC - a quantum chemistry and crystallography library
190 lines (171 loc) • 5.14 kB
JavaScript
// Module worker exposing filesystem operations on a persistent OCC instance.
// Spawn with: new Worker('occ-worker.js', { type: 'module' })
import createOccCliModule from '../dist/occ.js';
let Module = null;
let moduleReady = false;
const modulePromise = createOccCliModule({
print: (text) => self.postMessage({ type: 'output', text }),
printErr: (text) => self.postMessage({ type: 'error', text }),
onAbort: (msg) => {
self.postMessage({ type: 'error', text: `Module aborted: ${msg}` });
self.postMessage({ type: 'exit', code: 1 });
},
noInitialRun: true,
locateFile: (path) => new URL(`../dist/${path}`, import.meta.url).href,
})
.then((m) => {
Module = m;
// Create default water.xyz in root directory
const waterXyz = `3
Water molecule
O 0.00000 0.00000 0.11779
H 0.00000 0.75545 -0.47116
H 0.00000 -0.75545 -0.47116
`;
Module.FS.writeFile('/water.xyz', waterXyz);
moduleReady = true;
self.postMessage({ type: 'ready' });
})
.catch((error) => {
self.postMessage({ type: 'error', text: `Failed to load occ.js: ${error.message}` });
self.postMessage({ type: 'exit', code: 1 });
});
self.onmessage = async function (e) {
const { type, data } = e.data;
if (!moduleReady) {
await modulePromise;
if (!moduleReady) {
self.postMessage({ type: 'error', text: 'Module not ready' });
return;
}
}
switch (type) {
case 'ls':
executeLs(data);
break;
case 'cat':
executeCat(data);
break;
case 'mkdir':
executeMkdir(data);
break;
case 'cd':
executeCd(data);
break;
case 'pwd':
self.postMessage({ type: 'pwd', path: Module.FS.cwd() });
break;
case 'writeFile':
executeWriteFile(data);
break;
case 'getFiles':
executeGetFiles(data);
break;
case 'syncFiles':
executeSyncFiles(data);
break;
}
};
function executeGetFiles(data) {
const { path } = data;
try {
const files = {};
function collectFiles(dir) {
const contents = Module.FS.readdir(dir);
for (const item of contents) {
if (item === '.' || item === '..') continue;
const fullPath = dir === '/' ? '/' + item : dir + '/' + item;
try {
const stat = Module.FS.stat(fullPath);
if (Module.FS.isDir(stat.mode)) {
collectFiles(fullPath);
} else {
files[fullPath] = Module.FS.readFile(fullPath);
}
} catch (e) {
// Skip files we can't read
}
}
}
collectFiles(path || '/');
self.postMessage({ type: 'getFiles', files });
} catch (e) {
self.postMessage({ type: 'error', text: `getFiles: ${e.message}` });
}
}
function executeSyncFiles(data) {
const { files } = data;
try {
for (const [path, content] of Object.entries(files)) {
// Create parent directories if needed
const parts = path.split('/').filter((p) => p);
let currentPath = '/';
for (let i = 0; i < parts.length - 1; i++) {
currentPath += parts[i];
try {
Module.FS.mkdir(currentPath);
} catch (e) {
// Directory might already exist
}
currentPath += '/';
}
// Write the file
Module.FS.writeFile(path, content);
}
self.postMessage({ type: 'syncFiles', success: true });
} catch (e) {
self.postMessage({ type: 'error', text: `syncFiles: ${e.message}` });
}
}
function executeLs(data) {
const { path } = data;
try {
const stat = Module.FS.stat(path);
let files = [];
if (Module.FS.isDir(stat.mode)) {
const contents = Module.FS.readdir(path);
files = contents.filter((f) => f !== '.' && f !== '..');
} else {
files = [path.split('/').pop()];
}
self.postMessage({ type: 'ls', files });
} catch (e) {
self.postMessage({ type: 'error', text: `ls: cannot access '${path}': No such file or directory` });
}
}
function executeCat(data) {
const { path } = data;
try {
const content = Module.FS.readFile(path, { encoding: 'utf8' });
self.postMessage({ type: 'cat', content });
} catch (e) {
self.postMessage({ type: 'error', text: `cat: ${path}: No such file or directory` });
}
}
function executeMkdir(data) {
const { path } = data;
try {
Module.FS.mkdir(path);
self.postMessage({ type: 'mkdir', success: true });
} catch (e) {
self.postMessage({ type: 'error', text: `mkdir: cannot create directory '${path}': ${e.message}` });
}
}
function executeCd(data) {
const { path } = data;
try {
Module.FS.chdir(path);
self.postMessage({ type: 'cd', path: Module.FS.cwd() });
} catch (e) {
self.postMessage({ type: 'error', text: `cd: ${path}: No such file or directory` });
}
}
function executeWriteFile(data) {
const { path, content } = data;
try {
Module.FS.writeFile(path, content);
self.postMessage({ type: 'writeFile', success: true });
} catch (e) {
self.postMessage({ type: 'error', text: `write: ${path}: ${e.message}` });
}
}