zen-fs / core

A filesystem, anywhere.
https://zenfs.dev/core/
MIT License
134 stars 20 forks source link

Setting up OPFS with Asyncmirror #37

Closed philipp-strack closed 7 months ago

philipp-strack commented 7 months ago

Hello,

I am trying to setup OPFS to be mounted into the Filesystem of a binary compiled with emscriptem in a webworker. I am thus trying to use AsyncMirror.

import { configure, fs } from '@zenfs/core';
import { FileSystemAccess } from '@zenfs/dom';

function initializeAsyncFS(opfs) {
  return new Promise((resolve, reject) => {
    console.log('navigator storage loaded')
    configure({
      backend: 'AsyncMirror',
      options: {
        sync: { backend: 'InMemory' },
        async: { backend: 'FileSystemAccess', handle: opfs } 
      }   
    }, function(e) {
      if (e) { reject(e); }
      console.log('resolve promise')
      resolve();
    }); 
  });
}

const initializeOPFS = navigator.storage.getDirectory().then(initializeAsyncFS);

This code fails with the error message:

Error: EINVAL: Missing or invalid backend

am I loading this in a wrong way? Thank you!

james-pre commented 7 months ago

@philipp-strack,

As of v0.4.0, "built-in" backends cannot be used (i.e. using a string for a backend) this was done to make the code easier to maintain.

Please use configure like this example:

import { configure, fs, InMemory, AsyncMirror } from '@zenfs/core';
import { FileSystemAccess } from '@zenfs/dom';

// using fs here works, but will use the defaults, since configure has not been called yet

await configure({
    backend: AsyncMirror,
    sync: InMemory,
    async: {
        backend: FileSystemAccess,
        handle: await navigator.storage.getDirectory()
    } 
});

// fs is configured here

This is the most concise way of configuring.

I also cleaned up some of the asynchronous operations. If top-level await is not supported in your environment, you can also use promises. I recommend using an async function to avoid an ugly .then chain:

import { configure, fs, InMemory, AsyncMirror } from '@zenfs/core';
import { FileSystemAccess } from '@zenfs/dom';

async function setupFS() {
    const handle = await navigator.storage.getDirectory();
    // using fs here works, but will use the defaults, since configure has not been called yet
    await configure({
        backend: AsyncMirror,
        sync: InMemory,
        async: {
             backend: FileSystemAccess,
             handle
        } 
    });
    // fs is configured here
}

// fs is NOT configured here

setupFS().then(() => {
    // fs is configured here
});

// fs is NOT configured here. It will be after the async functions runs, however that can't be detected in a synchronous manner.

Also, please note that configure returns a promise and does not support callbacks.

I should have @zenfs/worker completed and published in the next few weeks, however the Emscripten package may take longer.

Has your issue been resolved?

philipp-strack commented 7 months ago

@james-pre Thank you! This indeed resolved the error. Please excuse the naive question, but how can I mount this filesystem into a filesystem generated by emscripten? Thank you!

james-pre commented 7 months ago

I should have @zenfs/worker completed and published in the next few weeks, however the Emscripten package may take longer.

Once the Emscripten package is finished, you will be able to mount the Emscripten filesystem on ZenFS.

james-pre commented 7 months ago

I'm closing this since your original issue has been resolved.

I will try to get the Emscripten backend out soon.

philipp-strack commented 7 months ago

@james-pre Thank you!