Skip to content

Instantly share code, notes, and snippets.

@jlongster
Created July 22, 2021 01:03
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jlongster/ec00ddbb47b4b29897ab5939b8e32fbe to your computer and use it in GitHub Desktop.
Save jlongster/ec00ddbb47b4b29897ab5939b8e32fbe to your computer and use it in GitHub Desktop.
import {Reader, Writer} from '../shared-channel';
let FS;
let rootEntry;
let openFiles = new Map();
function openFile(filename) {
let opened = openFiles.get(filename);
if (opened) {
return opened;
}
return new Promise((resolve, reject) => {
rootEntry.getFile(
filename,
{create: true},
(entry) => {
openFiles.set(filename, entry);
resolve(entry);
},
(err) => reject(err),
);
});
}
async function handleWrites(writer, name, writes) {
let entry = await openFile(name);
for (let w of writes) {
await new Promise((resolve, reject) => {
entry.createWriter((writer) => {
writer.onwrite = resolve;
writer.onerror = reject;
writer.seek(w.pos);
writer.write(new Blob([w.data], {type: 'octet/stream'}));
});
});
}
writer.int32(0);
writer.finalize();
}
async function handleRead(writer, name, pos, length) {
let entry = await openFile(name);
let file = await new Promise((resolve, reject) =>
entry.file(resolve, reject),
);
let bytes = await new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.onerror = reject;
reader.readAsArrayBuffer(file.slice(pos, pos + length));
});
writer.bytes(bytes);
writer.finalize();
}
async function handleReadMeta(writer, name) {
let entry = await openFile(name);
let file = await new Promise((resolve, reject) => {
entry.file(resolve, reject);
});
let meta = {size: file.size, blockSize: 4096};
writer.int32(meta ? meta.size : -1);
writer.int32(meta ? meta.blockSize : -1);
writer.finalize();
}
async function handleWriteMeta(writer, name, meta) {
let entry = await openFile(name);
try {
await new Promise((resolve, reject) => {
entry.createWriter((writer) => {
writer.onwrite = resolve;
writer.onerror = reject;
writer.truncate(meta.size);
});
});
writer.int32(0);
writer.finalize();
} catch (err) {
console.log('handleWriteMeta err:', err);
writer.int32(-1);
writer.finalize();
}
}
async function listen(reader, writer) {
while (1) {
let method = reader.string();
switch (method) {
case 'writeBlocks': {
let name = reader.string();
let writes = [];
while (!reader.done()) {
let pos = reader.int32();
let data = reader.bytes();
writes.push({pos, data});
}
await handleWrites(writer, name, writes);
break;
}
case 'readBlock': {
let name = reader.string();
let pos = reader.int32();
let length = reader.int32();
reader.done();
await handleRead(writer, name, pos, length);
break;
}
case 'readMeta': {
let name = reader.string();
reader.done();
await handleReadMeta(writer, name);
break;
}
case 'writeMeta': {
let name = reader.string();
let size = reader.int32();
let blockSize = reader.int32();
reader.done();
await handleWriteMeta(writer, name, {size, blockSize});
break;
}
}
}
}
self.onmessage = async (msg) => {
switch (msg.data.type) {
case 'init': {
let quota = msg.data.quota;
if (quota === 0) {
postMessage({type: 'no-filesystem'});
return;
}
FS = await new Promise((resolve, reject) => {
self.webkitRequestFileSystem(
self.PERSISTENT,
quota,
(fs) => {
resolve(fs);
},
(err) => {
postMessage({type: 'no-filesystem'});
reject(err);
},
);
});
rootEntry = await new Promise((resolve, reject) => {
FS.root.getDirectory(
'dbs',
{create: true},
(entry) => {
resolve(entry);
},
(err) => {
postMessage({type: 'no-filesystem'});
reject(err);
},
);
});
postMessage({type: 'worker-ready'});
let [argBuffer, resultBuffer] = msg.data.buffers;
let reader = new Reader(argBuffer, {name: 'args', debug: false});
let writer = new Writer(resultBuffer, {name: 'results', debug: false});
listen(reader, writer);
break;
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment