简体   繁体   中英

How to serialize / deserialize a FileSystemHandle JavaScript object with Dart in IndexedDB storage?

I'm using js-interop to use the File System Access API with Dart in a web environment. I would like to store a FileSystemDirectoryHandle in IndexedDB to reuse it later.

When storing an instance of FileSystemDirectoryHandle in IndexedDB, the data is a Dart object (Symbol when exploring the value in DevTools). When I read back, value is not a FileSystemDirectoryHandle and all informations of the object is lost and useless.

I did not find a way to store a handle into IndexedDB and read it back as a FileSystemDirectoryHandle .

Below is parts of the code I declare with js-interop:

// Only to keep track of API's types definitions.
typedef Promise<T> = dynamic;

// FileSystemHandle and *Options are declared in the same way.
@JS()
class FileSystemDirectoryHandle extends FileSystemHandle {
  external Promise<FileSystemFileHandle> getFileHandle(String name, [FileSystemGetFileOptions? options]);
  external Promise<FileSystemDirectoryHandle> getDirectoryHandle(String name, [FileSystemGetDirectoryOptions? options]);
  external Promise<void> removeEntry(String name, [FileSystemRemoveOptions? options]);
  external Promise<List<String>?> resolve(FileSystemHandle possibleDescendant);
}

Here is what I'm trying to achieve:

final handle = await js.promiseToFuture(window.showDirectoryPicker());

// Storage use dart:indexed_db in a homebrew implementation (tested and works fine with 
// primitive types).
await storage.set("dir", handle);

// Reload page...

// Dynamic only
final directory = await storage.get("dir");

print(directory.name);

// Typed
FileSystemDirectoryHandle dirHandle = directory as FileSystemDirectoryHandle;

print(dirHandle.name);

Calling dynamic directory.name throws a NoSuchMethodError :

Uncaught (in promise) Error: NoSuchMethodError: 'name'

method not found

Receiver: Instance of 'LinkedMap<dynamic, dynamic>'

Calling typed dirHandle.name throws an Error :

Error: Expected a value of type 'FileSystemDirectoryHandle', but got one of type 'LinkedMap<dynamic, dynamic>'

Screenshot of IndexedDB in DevTools, when storing from Dart, and storing from JavaScript

My understanding of js-interop is that it translates JavaScript object into a Dart proxy. As I'm sending a Dart object, it does not serialize the JavaScript object, but the Dart proxy object. Therefore the JavaScript object is lost in the process.

Is there a way to pass the JavaScript object to IndexedDB from Dart? Or at least serialize the native JavaScript object from Dart proxy and then send it into IndexedDB?

Any guidance would be much appreciated.

Issue on dart-lang/sdk repository #50621

More on this repository , usage in example here , and js-interop here .

It will throw a NoSuchMethodError as the instance returned from IndexedDB is not a FileSystemDirectoryHandle.

Are you saying directory.name throws a NoSuchMethodError ? What is the static type of directory here? Is it possible you need to cast the result to storage.set to FileSystemDirectoryHandle ?

My understanding of js-interop is that it translates JavaScript object into a Dart proxy. As I'm sending a Dart object, it does not serialize the JavaScript object, but the Dart proxy object. Therefore the JavaScript object is lost in the process.

This shouldn't be the case. The object is still a JavaScript object, you're just using a Dart type to interact with that object. So, you can use the Dart members you declared for it, but we don't wrap that object if you just write a @JS() interface for it.

A workaround is available in issue linked in original post. Problem comes from dart:indexed_db package.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM