Created
April 3, 2021 10:29
-
-
Save Ekliptor/0dfe2552191537efed12db010d7eccf5 to your computer and use it in GitHub Desktop.
Go Web Assembly compile server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func (api *CompileAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
defer r.Body.Close() | |
// Get code from params | |
type parameters struct { | |
Code string `json:"code" validate:"required"` | |
} | |
decoder := json.NewDecoder(r.Body) | |
params := parameters{} | |
err := decoder.Decode(¶ms) | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, "Couldn't decode parameters") | |
return | |
} | |
params.Code = strings.TrimSpace(params.Code) | |
// create file system location for compilation path | |
usr, err := user.Current() | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, "Couldn't get system user") | |
return | |
} | |
workingDir := filepath.Join(usr.HomeDir, ".wasm", uuid.New().String()) | |
err = os.MkdirAll(workingDir, os.ModePerm) | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, "Couldn't create directory for compilation") | |
return | |
} | |
defer func() { | |
err = os.RemoveAll(workingDir) | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, "Couldn't clean up code from compilation") | |
return | |
} | |
}() | |
f, err := os.Create(filepath.Join(workingDir, "main.go")) | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, "Couldn't create code file for compilation") | |
return | |
} | |
defer f.Close() | |
dat := []byte(params.Code) | |
_, err = f.Write(dat) | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, "Couldn't write code to file for compilation") | |
return | |
} | |
// compile the wasm | |
const outputBinary = "main.wasm" | |
os.Setenv("GOOS", "js") | |
os.Setenv("GOARCH", "wasm") | |
os.Setenv("GO111MODULE", "off") // otherwise it tries to load the main module of our project's go.mod file | |
cmd := exec.Command("go", "build", "-o", outputBinary) | |
cmd.Dir = workingDir | |
stderr, err := cmd.StderrPipe() | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, err.Error()) | |
return | |
} | |
if err := cmd.Start(); err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, err.Error()) | |
return | |
} | |
stdErr, err := ioutil.ReadAll(stderr) | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, err.Error()) | |
return | |
} | |
stdErrString := string(stdErr) | |
if stdErrString != "" { | |
parts := strings.Split(stdErrString, workingDir) | |
if len(parts) < 2 { | |
api.respondWithError(w, http.StatusInternalServerError, stdErrString) | |
return | |
} | |
api.respondWithError(w, http.StatusBadRequest, parts[1]) | |
return | |
} | |
if err := cmd.Wait(); err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, err.Error()) | |
return | |
} | |
// return WebAssembly binary as HTTP response | |
dat, err = ioutil.ReadFile(filepath.Join(workingDir, outputBinary)) | |
if err != nil { | |
api.respondWithError(w, http.StatusInternalServerError, err.Error()) | |
return | |
} | |
w.Write(dat) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment