@fairdatasociety/fairdrive-opfs
Version:
Fairdrive OPFS - integrate data sources from Web 2.0 or Web 3.0
213 lines (212 loc) • 6 kB
JavaScript
import { getOriginPrivateDirectory } from 'file-system-access';
const { GONE } = errors;
import { errors } from 'file-system-access/lib/util.js';
import { Subject } from 'rxjs';
import { FileSync } from './file-sync';
/**
* FdpConnectProvider is the base class for all providers.
*/
export class FdpConnectProvider {
constructor(config) {
this.config = config;
this.onMount = new Subject();
}
initialize(options) {
Object.assign(this, options);
}
/**
* Get the current mount point.
* @returns Current mount point
*/
getCurrentMount() {
return this.mount;
}
/**
* getFSHandler returns a FileSystemDirectoryHandle for the given provider.
* @param mount - mount point
* @returns a FileSystemDirectoryHandle
*/
async getFSHandler(mount) {
const adapter = await import('./adapter'); // FdpConnectAdapter(mount, this.filesystemDriver)
this.mount = mount;
this.onMount.next(mount);
return getOriginPrivateDirectory(adapter, { mount, driver: this.filesystemDriver });
}
/**
* getTransferHandler returns a FileSync for the given provider.
* @returns a FileSync
*/
getTransferHandler() {
return new FileSync(this.filesystemDriver);
}
}
const File = globalThis.File;
class Sink {
constructor(mount, driver, file) {
this.mount = mount;
this.driver = driver;
this.file = file;
}
/**
* Returns true if the file exists, else false
* @param key
* @param options
* @returns
*/
async has(key) {
try {
return this.driver.exists(key, this.mount);
}
catch (e) {
return false;
}
}
/**
* Write a chunk to the file
*/
async write(chunk) {
this.file = chunk;
}
/**
* Close the file
*/
async close() {
return new Promise(async (resolve, reject) => {
try {
await this.driver.upload(this.file, this.mount, {});
resolve();
}
catch (e) {
reject(e);
}
});
}
}
// FS File Handle
export class FileHandle {
constructor(mount, driver, name) {
this.kind = 'file';
this.writable = true;
this.mount = mount;
this.driver = driver;
this.name = name;
}
/**
* Get the file
*/
async getFile() {
try {
const data = await this.driver.download(`${this.mount.path}${this.name}`, this.mount, {});
return new File([data.buffer], this.name);
}
catch (e) {
throw new DOMException(...GONE);
}
}
/**
* Create a writable stream
*/
async createWritable(opts) {
let file;
if (opts && !opts.keepExistingData) {
file = new File([], this.name);
}
else {
file = await this.getFile();
}
return new Sink(this.mount, this.driver, file);
}
/**
* Check if the file is the same as the other file
*/
async isSameEntry(other) {
return this.name === other.name;
}
}
// FS Folder Handle
export class FolderHandle {
constructor(mount, driver) {
this.kind = 'directory';
this.writable = true;
this.readable = true;
this.mount = mount;
this.driver = driver;
this.name = this.mount.name;
this.path = this.mount.path;
}
/**
* Entries returns a list of files and directories
*/
async *entries() {
const entries = await this.driver.read(this.mount);
if (entries && entries.dirs && entries.dirs.length > 0) {
for (const entry of entries.dirs) {
yield [entry, new FolderHandle(this.mount, this.driver)];
}
}
if (entries && entries.files && entries.files.length > 0) {
for (const entry of entries.files) {
yield [entry, new FileHandle(this.mount, this.driver, entry)];
}
}
}
/**
* Check if the folder is the same as the other folder
*/
async isSameEntry(other) {
return this.path === other.path;
}
/**
* GetDirectoryHandle returns a directory handle
*/
async getDirectoryHandle(name, opts = {}) {
return new Promise(async (resolve, reject) => {
if (opts.create) {
await this.driver.createDir(`${this.mount.path}${name}`, this.mount);
resolve(new FolderHandle(this.mount, this.driver));
}
else {
try {
const entries = await this.driver.read(this.mount);
if (entries.files.length > 0 || entries.dirs.length > 0) {
resolve(new FolderHandle(this.mount, this.driver));
}
}
catch (e) {
reject(new DOMException(...GONE));
}
}
});
}
/**
* GetFileHandle returns a file handle
*/
async getFileHandle(name, opts = {}) {
return new Promise(async (resolve, reject) => {
try {
if (opts.create) {
resolve(new FileHandle(this.mount, this.driver, name));
}
else {
resolve(new FileHandle(this.mount, this.driver, name));
}
}
catch (e) {
reject(new DOMException(...GONE));
}
});
}
/**
* Removes a file
*/
async removeEntry(name, opts = {}) {
return new Promise(async (resolve, reject) => {
try {
await this.driver.delete(`${this.mount.path}${name}`, this.mount);
}
catch (e) {
reject(new DOMException(...GONE));
}
});
}
}