webkitFileSystem.backend.js

July 22, 2021 ยท View on GitHub

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;
}

} };