aboutsummaryrefslogtreecommitdiffhomepage
path: root/worker/swift/exec.go
diff options
context:
space:
mode:
Diffstat (limited to 'worker/swift/exec.go')
-rw-r--r--worker/swift/exec.go175
1 files changed, 109 insertions, 66 deletions
diff --git a/worker/swift/exec.go b/worker/swift/exec.go
index 37f542b..8ad5615 100644
--- a/worker/swift/exec.go
+++ b/worker/swift/exec.go
@@ -12,35 +12,20 @@ import (
const (
dataRootDir = "/app/data"
- // Stores *.swift files.
- dataSwiftRootDir = dataRootDir + "/swift"
- // Stores *.wasm files.
- dataWasmRootDir = dataRootDir + "/wasm"
- // Stores *.cwasm files (compiled wasm generated by "wasmtime compile").
- dataCwasmRootDir = dataRootDir + "/cwasm"
wasmMaxMemorySize = 10 * 1024 * 1024 // 10 MiB
)
func prepareDirectories() error {
- if err := os.MkdirAll(dataSwiftRootDir, 0755); err != nil {
- return err
- }
- if err := os.MkdirAll(dataWasmRootDir, 0755); err != nil {
- return err
- }
- if err := os.MkdirAll(dataCwasmRootDir, 0755); err != nil {
+ if err := os.MkdirAll(dataRootDir, 0755); err != nil {
return err
}
return nil
}
-func calcFilePath(hash, ext string) string {
- return fmt.Sprintf("%s/%s/%s.%s", dataRootDir, ext, hash, ext)
-}
-
func execCommandWithTimeout(
ctx context.Context,
+ workingDir string,
maxDuration time.Duration,
makeCmd func(context.Context) *exec.Cmd,
) (string, string, error) {
@@ -48,6 +33,7 @@ func execCommandWithTimeout(
defer cancel()
cmd := makeCmd(ctx)
+ cmd.Dir = workingDir
var stdout bytes.Buffer
var stderr bytes.Buffer
@@ -67,114 +53,171 @@ func execCommandWithTimeout(
}
}
-func convertCommandErrorToResultType(err error, isCompile bool) string {
+func convertCommandErrorToResultType(err error, defaultErrorStatus string) string {
if err != nil {
if err == context.DeadlineExceeded {
return resultTimeout
}
- if isCompile {
- return resultCompileError
- }
- return resultRuntimeError
+ return defaultErrorStatus
}
return resultSuccess
}
-func execSwiftCompile(
- ctx context.Context,
- code string,
- codeHash string,
- maxDuration time.Duration,
-) swiftCompileResponseData {
- inPath := calcFilePath(codeHash, "swift")
- outPath := calcFilePath(codeHash, "wasm")
-
- if err := os.WriteFile(inPath, []byte(code), 0644); err != nil {
- return swiftCompileResponseData{
+func prepareWorkingDir(workingDir string) execResponseData {
+ err := os.MkdirAll(workingDir, 0755)
+ if err != nil {
+ return execResponseData{
Status: resultInternalError,
Stdout: "",
- Stderr: err.Error(),
+ Stderr: "Failed to create project directory",
}
}
+ return execResponseData{
+ Status: resultSuccess,
+ Stdout: "",
+ Stderr: "",
+ }
+}
+
+func removeWorkingDir(workingDir string) {
+ err := os.RemoveAll(workingDir)
+ _ = err
+}
+func initSwiftProject(
+ ctx context.Context,
+ workingDir string,
+ maxDuration time.Duration,
+) execResponseData {
stdout, stderr, err := execCommandWithTimeout(
ctx,
+ workingDir,
maxDuration,
func(ctx context.Context) *exec.Cmd {
return exec.CommandContext(
ctx,
- "swiftc",
- "-target", "wasm32-unknown-wasi",
- "-o", outPath,
- inPath,
+ "swift",
+ "package",
+ "init",
+ "--type", "executable",
)
},
)
-
- return swiftCompileResponseData{
- Status: convertCommandErrorToResultType(err, true),
+ return execResponseData{
+ Status: convertCommandErrorToResultType(err, resultInternalError),
Stdout: stdout,
Stderr: stderr,
}
}
-func execWasmCompile(
+func putSwiftSourceFile(
+ workingDir string,
+ code string,
+) execResponseData {
+ err := os.WriteFile(workingDir+"/Sources/main.swift", []byte(code), 0644)
+
+ if err != nil {
+ return execResponseData{
+ Status: convertCommandErrorToResultType(err, resultInternalError),
+ Stdout: "",
+ Stderr: "Failed to copy source file",
+ }
+ }
+ return execResponseData{
+ Status: resultSuccess,
+ Stdout: "",
+ Stderr: "",
+ }
+}
+
+func buildSwiftProject(
ctx context.Context,
- codeHash string,
+ workingDir string,
maxDuration time.Duration,
-) wasmCompileResponseData {
- inPath := calcFilePath(codeHash, "wasm")
- outPath := calcFilePath(codeHash, "cwasm")
-
+) execResponseData {
stdout, stderr, err := execCommandWithTimeout(
ctx,
+ workingDir,
maxDuration,
func(ctx context.Context) *exec.Cmd {
return exec.CommandContext(
ctx,
- "wasmtime", "compile",
- "-O", "opt-level=0",
- "-C", "cache=n",
- "-W", fmt.Sprintf("max-memory-size=%d", wasmMaxMemorySize),
- "-o", outPath,
- inPath,
+ "swift",
+ "build",
+ "--swift-sdk", "wasm32-unknown-wasi",
)
},
)
-
- return wasmCompileResponseData{
- Status: convertCommandErrorToResultType(err, true),
+ return execResponseData{
+ Status: convertCommandErrorToResultType(err, resultCompileError),
Stdout: stdout,
Stderr: stderr,
}
}
-func execTestRun(
+func runWasm(
ctx context.Context,
+ workingDir string,
codeHash string,
stdin string,
maxDuration time.Duration,
-) testRunResponseData {
- inPath := calcFilePath(codeHash, "cwasm")
-
+) execResponseData {
stdout, stderr, err := execCommandWithTimeout(
ctx,
+ workingDir,
maxDuration,
func(ctx context.Context) *exec.Cmd {
cmd := exec.CommandContext(
ctx,
- "wasmtime", "run",
- "--allow-precompiled",
- inPath,
+ "wasmtime",
+ "-W", fmt.Sprintf("max-memory-size=%d", wasmMaxMemorySize),
+ ".build/wasm32-unknown-wasi/debug/"+codeHash+".wasm",
)
cmd.Stdin = strings.NewReader(stdin)
return cmd
},
)
-
- return testRunResponseData{
- Status: convertCommandErrorToResultType(err, false),
+ return execResponseData{
+ Status: convertCommandErrorToResultType(err, resultRuntimeError),
Stdout: stdout,
Stderr: stderr,
}
}
+
+func doExec(
+ ctx context.Context,
+ code string,
+ codeHash string,
+ stdin string,
+ maxDuration time.Duration,
+) execResponseData {
+ workingDir := dataRootDir + "/" + codeHash
+
+ res := prepareWorkingDir(workingDir)
+ if !res.success() {
+ return res
+ }
+ defer removeWorkingDir(workingDir)
+
+ res = initSwiftProject(ctx, workingDir, maxDuration)
+ if !res.success() {
+ return res
+ }
+
+ res = putSwiftSourceFile(workingDir, code)
+ if !res.success() {
+ return res
+ }
+
+ res = buildSwiftProject(ctx, workingDir, maxDuration)
+ if !res.success() {
+ return res
+ }
+
+ res = runWasm(ctx, workingDir, codeHash, stdin, maxDuration)
+ if !res.success() {
+ return res
+ }
+
+ return res
+}