-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathexec_wasmtime.go
More file actions
123 lines (116 loc) · 3.14 KB
/
exec_wasmtime.go
File metadata and controls
123 lines (116 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//go:build wasmtime
package main
import (
"context"
"io"
"log/slog"
"os"
"path/filepath"
"github.com/bytecodealliance/wasmtime-go"
)
// WasmtimeRunner implements CGI Runner execute by wasmtime
type WasmtimeRunner struct {
}
// Run implements Runner.Run
func (runner WasmtimeRunner) Run(conf SrvConfig, cmdname string, envvar map[string]string,
stdin io.ReadCloser, stdout io.Writer, stderr io.Writer, ctx context.Context) error {
fn := filepath.Join(conf.BaseDir, cmdname)
bytecode, err := os.ReadFile(fn)
if err != nil {
slog.Error("read bytecode", "error", err, "filename", fn)
return err
}
slog.Debug("bytecode read", "length", len(bytecode), "filename", fn)
engine := wasmtime.NewEngine()
module, err := wasmtime.NewModule(engine, bytecode)
if err != nil {
slog.Error("wasmtime module", "error", err)
return err
}
linker := wasmtime.NewLinker(engine)
err = linker.DefineWasi()
if err != nil {
slog.Error("define wasi", "error", err)
return err
}
wasiConfig := wasmtime.NewWasiConfig()
keys := []string{}
vals := []string{}
for k, v := range envvar {
keys = append(keys, k)
vals = append(vals, v)
}
wasiConfig.SetEnv(keys, vals)
dir, err := os.MkdirTemp("", "out")
if err != nil {
slog.Error("mkdtemp", "error", err)
return err
}
defer os.RemoveAll(dir)
slog.Debug("tmp dir", "dir", dir)
stdoutPath := filepath.Join(dir, "stdout")
stderrPath := filepath.Join(dir, "stderr")
stdinPath := filepath.Join(dir, "stdin")
stdinFp, err := os.OpenFile(stdinPath, os.O_WRONLY|os.O_CREATE, 0755)
if err != nil {
slog.Error("open stdin", "error", err)
return err
}
io.Copy(stdinFp, stdin)
err = stdinFp.Close()
if err != nil {
slog.Error("stdin close", "error", err)
return err
}
wasiConfig.SetStdinFile(stdinPath)
wasiConfig.SetStdoutFile(stdoutPath)
wasiConfig.SetStderrFile(stderrPath)
store := wasmtime.NewStore(engine)
store.SetWasi(wasiConfig)
instance, err := linker.Instantiate(store, module)
if err != nil {
slog.Error("wasmtime instantiate", "error", err)
return err
}
cgi := instance.GetFunc(store, "_start")
res, err := cgi.Call(store)
if err != nil {
slog.Error("wasmtime run", "error", err)
}
if res != nil {
slog.Debug("result", "res", res)
} else {
slog.Debug("result(nil)")
}
stdoutContent, err := os.ReadFile(stdoutPath)
if err != nil {
slog.Error("reading stdout", "error", err)
return err
}
cnt, err := stdout.Write(stdoutContent)
if err != nil {
slog.Error("writing stdout", "error", err)
} else {
slog.Debug("stdout", "cnt", cnt)
}
stderrContent, err := os.ReadFile(stderrPath)
if err != nil {
slog.Error("reading stderr", "error", err)
} else if len(stderrContent) != 0 {
cnt, err := stderr.Write(stderrContent)
if err != nil {
slog.Error("writing stderr", "error", err, "content", string(stderrContent))
} else {
slog.Debug("stderr", "cnt", cnt, "content", string(stderrContent))
}
}
return nil
}
func (runner WasmtimeRunner) Exists(conf SrvConfig, path string, ctx context.Context) (string, string, error) {
return splitPathInfo(conf.BaseDir, path, conf.Suffix)
}
func init() {
runnerMap["wasmtime"] = func(SrvConfig) Runner {
return WasmtimeRunner{}
}
}