| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- //go:build wasm
- // +build wasm
- // Package indexeddb contains a WebAssembly compatible file system. Uses IndexedDB under the hood.
- package indexeddb
- import (
- "context"
- "time"
- "github.com/hack-pad/go-indexeddb/idb"
- "github.com/hack-pad/hackpadfs"
- "github.com/hack-pad/hackpadfs/keyvalue"
- "github.com/hack-pad/safejs"
- )
- const (
- fsVersion = 1
- contentsStore = "contents"
- infoStore = "info"
- parentKey = "Parent"
- )
- // FS is a browser-based file system, storing files and metadata inside IndexedDB.
- type FS struct {
- kv *keyvalue.FS
- db *idb.Database
- }
- // Options provides configuration options for a new FS.
- type Options struct {
- Factory *idb.Factory
- TransactionDurability idb.TransactionDurability
- }
- // NewFS returns a new FS.
- func NewFS(ctx context.Context, name string, options Options) (*FS, error) {
- if options.Factory == nil {
- options.Factory = idb.Global()
- }
- openRequest, err := options.Factory.Open(ctx, name, fsVersion, func(db *idb.Database, _, _ uint) error {
- _, err := db.CreateObjectStore(contentsStore, idb.ObjectStoreOptions{})
- if err != nil {
- return err
- }
- infos, err := db.CreateObjectStore(infoStore, idb.ObjectStoreOptions{})
- if err != nil {
- return err
- }
- jsParentKey, err := safejs.ValueOf(parentKey)
- if err != nil {
- return err
- }
- _, err = infos.CreateIndex(parentKey, safejs.Unsafe(jsParentKey), idb.IndexOptions{})
- return err
- })
- if err != nil {
- return nil, err
- }
- db, err := openRequest.Await(ctx)
- if err != nil {
- return nil, err
- }
- kv, err := keyvalue.NewFS(newStore(db, options))
- return &FS{
- kv: kv,
- db: db,
- }, err
- }
- // Clear dangerously destroys all data inside this FS. Use with caution.
- func (fs *FS) Clear(ctx context.Context) error {
- stores := []string{contentsStore, infoStore}
- txn, err := fs.db.Transaction(idb.TransactionReadWrite, stores[0], stores[1:]...)
- if err != nil {
- return err
- }
- for _, name := range stores {
- store, err := txn.ObjectStore(name)
- if err != nil {
- return err
- }
- _, err = store.Clear()
- if err != nil {
- return err
- }
- }
- err = txn.Commit()
- if err != nil {
- return err
- }
- err = txn.Await(ctx)
- if err != nil {
- return err
- }
- return fs.Mkdir(".", 0o666)
- }
- // Open implements hackpadfs.FS
- func (fs *FS) Open(name string) (hackpadfs.File, error) {
- return fs.kv.Open(name)
- }
- // OpenFile implements hackpadfs.OpenFileFS
- func (fs *FS) OpenFile(name string, flag int, perm hackpadfs.FileMode) (hackpadfs.File, error) {
- return fs.kv.OpenFile(name, flag, perm)
- }
- // Mkdir implements hackpadfs.MkdirFS
- func (fs *FS) Mkdir(name string, perm hackpadfs.FileMode) error {
- return fs.kv.Mkdir(name, perm)
- }
- // MkdirAll implements hackpadfs.MkdirAllFS
- func (fs *FS) MkdirAll(path string, perm hackpadfs.FileMode) error {
- return fs.kv.MkdirAll(path, perm)
- }
- // Remove implements hackpadfs.RemoveFS
- func (fs *FS) Remove(name string) error {
- return fs.kv.Remove(name)
- }
- // Rename implements hackpadfs.RenameFS
- func (fs *FS) Rename(oldname, newname string) error {
- return fs.kv.Rename(oldname, newname)
- }
- // Stat implements hackpadfs.StatFS
- func (fs *FS) Stat(name string) (hackpadfs.FileInfo, error) {
- return fs.kv.Stat(name)
- }
- // Chmod implements hackpadfs.ChmodFS
- func (fs *FS) Chmod(name string, mode hackpadfs.FileMode) error {
- return fs.kv.Chmod(name, mode)
- }
- // Chtimes implements hackpadfs.ChtimesFS
- func (fs *FS) Chtimes(name string, atime time.Time, mtime time.Time) error {
- return fs.kv.Chtimes(name, atime, mtime)
- }
|