Skip to content

Commit

Permalink
Merge pull request #678 from axone-protocol/refactor/logic-vfs
Browse files Browse the repository at this point in the history
Refactor/logic vfs
  • Loading branch information
ccamel authored Jun 20, 2024
2 parents bcffe2f + 2c41f3c commit d8b5710
Show file tree
Hide file tree
Showing 20 changed files with 916 additions and 373 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,8 @@ mock: ## Generate all the mocks (for tests)
@mockgen -source=x/vesting/types/expected_keepers.go -package testutil -destination x/vesting/testutil/expected_keepers_mocks.go
@mockgen -source=x/logic/types/expected_keepers.go -package testutil -destination x/logic/testutil/expected_keepers_mocks.go
@mockgen -destination x/logic/testutil/gas_mocks.go -package testutil cosmossdk.io/store/types GasMeter
@mockgen -destination x/logic/testutil/fs_mocks.go -package testutil io/fs FS
@mockgen -destination x/logic/testutil/read_file_fs_mocks.go -package testutil io/fs ReadFileFS

## Release:
.PHONY: release-assets
Expand Down
10 changes: 7 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ import (
axonewasm "github.com/axone-protocol/axoned/v8/app/wasm"
"github.com/axone-protocol/axoned/v8/docs"
logicmodule "github.com/axone-protocol/axoned/v8/x/logic"
logicfs "github.com/axone-protocol/axoned/v8/x/logic/fs"
"github.com/axone-protocol/axoned/v8/x/logic/fs/composite"
wasm2 "github.com/axone-protocol/axoned/v8/x/logic/fs/wasm"
logicmodulekeeper "github.com/axone-protocol/axoned/v8/x/logic/keeper"
logicmoduletypes "github.com/axone-protocol/axoned/v8/x/logic/types"
"github.com/axone-protocol/axoned/v8/x/mint"
Expand Down Expand Up @@ -1161,6 +1162,9 @@ func (app *App) SimulationManager() *module.SimulationManager {
// provideFS is used to provide the virtual file system used for the logic module
// to load external file.
func (app *App) provideFS(ctx context.Context) fs.FS {
wasmHandler := logicfs.NewWasmHandler(app.WasmKeeper)
return logicfs.NewVirtualFS(ctx, []logicfs.URIHandler{wasmHandler})
vfs := composite.NewFS()

vfs.Mount(wasm2.Scheme, wasm2.NewFS(ctx, app.WasmKeeper))

return vfs
}
124 changes: 124 additions & 0 deletions x/logic/fs/composite/fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package composite

import (
"errors"
"fmt"
"io"
"io/fs"
"net/url"
"sort"

"golang.org/x/exp/maps"
)

type FS interface {
fs.ReadFileFS

// Mount mounts a filesystem to the given mount point.
// The mount point is the scheme of the URI.
Mount(mountPoint string, fs fs.FS)
// ListMounts returns a list of all mount points in sorted order.
ListMounts() []string
}

type vfs struct {
mounted map[string]fs.FS
}

var (
_ fs.FS = (*vfs)(nil)
_ fs.ReadFileFS = (*vfs)(nil)
)

func NewFS() FS {
return &vfs{mounted: make(map[string]fs.FS)}
}

func (f *vfs) Open(name string) (fs.File, error) {
uri, err := f.validatePath(name)
if err != nil {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
}

vfs, err := f.resolve(uri)
if err != nil {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
}
return vfs.Open(name)
}

func (f *vfs) ReadFile(name string) ([]byte, error) {
uri, err := f.validatePath(name)
if err != nil {
return nil, &fs.PathError{Op: "readfile", Path: name, Err: fs.ErrInvalid}
}

vfs, err := f.resolve(uri)
if err != nil {
return nil, &fs.PathError{Op: "readfile", Path: name, Err: fs.ErrNotExist}
}

if vfs, ok := vfs.(fs.ReadFileFS); ok {
content, err := vfs.ReadFile(name)
if err != nil {
return nil, &fs.PathError{Op: "readfile", Path: name, Err: getUnderlyingError(err)}
}

return content, nil
}

file, err := vfs.Open(name)
if err != nil {
return nil, &fs.PathError{Op: "readfile", Path: name, Err: getUnderlyingError(err)}
}
defer file.Close()

content, err := io.ReadAll(file)
if err != nil {
return nil, &fs.PathError{Op: "readfile", Path: name, Err: getUnderlyingError(err)}
}

return content, nil
}

func (f *vfs) Mount(mountPoint string, fs fs.FS) {
f.mounted[mountPoint] = fs
}

func (f *vfs) ListMounts() []string {
mounts := maps.Keys(f.mounted)
sort.Strings(mounts)

return mounts
}

// validatePath checks if the provided path is a valid URL and returns its URI.
func (f *vfs) validatePath(name string) (*url.URL, error) {
uri, err := url.Parse(name)
if err != nil {
return nil, err
}
if uri.Scheme == "" {
return nil, fmt.Errorf("missing scheme in path: %s", name)
}
return uri, nil
}

// resolve returns the filesystem mounted at the given URI scheme.
func (f *vfs) resolve(uri *url.URL) (fs.FS, error) {
vfs, ok := f.mounted[uri.Scheme]
if !ok {
return nil, fmt.Errorf("no filesystem mounted at: %s", uri.Scheme)
}
return vfs, nil
}

// getUnderlyingError returns the underlying error of a path error.
// If it's not a path error it returns the error itself.
func getUnderlyingError(err error) error {
var pathErr *fs.PathError
if errors.As(err, &pathErr) {
return pathErr.Err
}
return err
}
Loading

0 comments on commit d8b5710

Please sign in to comment.