package main import ( gcontext "context" "errors" "io" "os" "reflect" "github.com/Xe/ln" "github.com/go-interpreter/wagon/exec" "github.com/go-interpreter/wagon/validate" "github.com/go-interpreter/wagon/wasm" ) // Process is a larger level wrapper around a webassembly VM that gives it // system call access. type Process struct { id int32 vm *exec.VM mod *wasm.Module } // NewProcess constructs a new webassembly process based on the input webassembly module as a reader. func NewProcess(fin io.Reader) (*Process, error) { p := &Process{} mod, err := wasm.ReadModule(fin, p.importer) if err != nil { return nil, err } if mod.Memory == nil { return nil, errors.New("must declare a memory, sorry :(") } vm, err := exec.NewVM(mod) if err != nil { return nil, err } p.mod = mod p.vm = vm return p, nil } func (p *Process) importer(name string) (*wasm.Module, error) { switch name { case "env": m := wasm.NewModule() m.Types = &wasm.SectionTypes{ Entries: []wasm.FunctionSig{ { Form: 0, ParamTypes: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, ReturnTypes: []wasm.ValueType{wasm.ValueTypeI32}, }, }, } m.FunctionIndexSpace = []wasm.Function{ { Sig: &m.Types.Entries[0], Host: reflect.ValueOf(p.log), Body: &wasm.FunctionBody{}, }, } m.Export = &wasm.SectionExports{ Entries: map[string]wasm.ExportEntry{ "log": { FieldStr: "log", Kind: wasm.ExternalFunction, Index: 0, }, }, } return m, nil default: f, err := os.Open(name + ".wasm") if err != nil { return nil, err } defer f.Close() m, err := wasm.ReadModule(f, nil) if err != nil { return nil, err } err = validate.VerifyModule(m) if err != nil { return nil, err } return m, nil } } // ID returns the process ID. func (p Process) ID() int32 { return p.id } // VM returns the webassembly VM used to execute code. This isn't thread-safe. func (p Process) VM() *exec.VM { return p.vm } func (p *Process) log(ptr int32, len int32) int32 { mem := p.vm.Memory() if mem == nil { panic("memory is nil, wtf") } data := mem[ptr : ptr+len] ln.Log(gcontext.Background(), ln.F{"data": data, "data_string": string(data), "pid": p.id}) return 0 }