mirror of
https://github.com/LukeHagar/wasm-overhead-research.git
synced 2025-12-06 04:22:06 +00:00
146 lines
4.2 KiB
Go
146 lines
4.2 KiB
Go
//go:build js && wasm
|
|
// +build js,wasm
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"syscall/js"
|
|
|
|
"github.com/dop251/goja"
|
|
)
|
|
|
|
// promisify wraps a Go function to return a JavaScript Promise
|
|
func promisify(fn func([]js.Value) (string, error)) js.Func {
|
|
return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
|
// Create a new Promise
|
|
handler := js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
|
resolve := promiseArgs[0]
|
|
reject := promiseArgs[1]
|
|
|
|
// Run the function in a goroutine
|
|
go func() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
errorConstructor := js.Global().Get("Error")
|
|
errorObj := errorConstructor.New(fmt.Sprintf("panic occurred: %v", r))
|
|
reject.Invoke(errorObj)
|
|
}
|
|
}()
|
|
|
|
// Pass the original args to the function, not the promise args
|
|
result, err := fn(args)
|
|
if err != nil {
|
|
errorConstructor := js.Global().Get("Error")
|
|
errorObj := errorConstructor.New(err.Error())
|
|
reject.Invoke(errorObj)
|
|
} else {
|
|
resolve.Invoke(result)
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
})
|
|
|
|
promiseConstructor := js.Global().Get("Promise")
|
|
return promiseConstructor.New(handler)
|
|
})
|
|
}
|
|
|
|
// transformData takes a JSON string, processes it using Goja JavaScript engine with a default transform, and returns a JSON string
|
|
func transformData(args []js.Value) (string, error) {
|
|
js.Global().Get("console").Call("log", "🔄 transformData called with", len(args), "arguments")
|
|
|
|
if len(args) < 1 {
|
|
return "", fmt.Errorf("expected at least one argument (JSON string)")
|
|
}
|
|
|
|
// Get the input JSON string
|
|
inputJSON := args[0].String()
|
|
js.Global().Get("console").Call("log", "📥 Input JSON:", inputJSON)
|
|
|
|
// Use a default transformation if no JavaScript code is provided
|
|
var transformJS string
|
|
if len(args) >= 2 {
|
|
transformJS = args[1].String()
|
|
js.Global().Get("console").Call("log", "📜 JavaScript code length:", len(transformJS), "characters")
|
|
} else {
|
|
// Default transformation that matches the test expectations
|
|
transformJS = `
|
|
function transform(data) {
|
|
return {
|
|
original: data,
|
|
transformed: true,
|
|
timestamp: new Date().toISOString(),
|
|
message: "Data has been processed by Go WASM"
|
|
};
|
|
}
|
|
`
|
|
}
|
|
|
|
// Parse the input JSON
|
|
var inputData interface{}
|
|
if err := json.Unmarshal([]byte(inputJSON), &inputData); err != nil {
|
|
return "", fmt.Errorf("failed to parse input JSON: %v", err)
|
|
}
|
|
|
|
// Create a new Goja runtime
|
|
vm := goja.New()
|
|
|
|
// Execute the JavaScript code to define the transform function
|
|
_, err := vm.RunString(transformJS)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute JavaScript transformation code: %v", err)
|
|
}
|
|
|
|
// Get the transform function
|
|
transformFunc, ok := goja.AssertFunction(vm.Get("transform"))
|
|
if !ok {
|
|
return "", fmt.Errorf("transform function not found in JavaScript code")
|
|
}
|
|
|
|
// Convert Go data to Goja value
|
|
gojaInput := vm.ToValue(inputData)
|
|
|
|
// Call the JavaScript transform function
|
|
result, err := transformFunc(goja.Undefined(), gojaInput)
|
|
if err != nil {
|
|
return "", fmt.Errorf("JavaScript transformation failed: %v", err)
|
|
}
|
|
|
|
// Export the result back to Go
|
|
transformedData := result.Export()
|
|
|
|
// Convert back to JSON
|
|
outputJSON, err := json.Marshal(transformedData)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to marshal output JSON: %v", err)
|
|
}
|
|
|
|
resultStr := string(outputJSON)
|
|
js.Global().Get("console").Call("log", "📤 Output JSON:", resultStr)
|
|
|
|
return resultStr, nil
|
|
}
|
|
|
|
func main() {
|
|
js.Global().Get("console").Call("log", "🚀 Go WASM module loaded (Goja implementation)")
|
|
|
|
// Expose the transformData function to JavaScript
|
|
js.Global().Set("transformData", promisify(transformData))
|
|
|
|
// Add a simple health check function
|
|
js.Global().Set("healthCheck", promisify(func(args []js.Value) (string, error) {
|
|
js.Global().Get("console").Call("log", "💓 Health check called")
|
|
return `{"status": "healthy", "message": "Go WASM module is running"}`, nil
|
|
}))
|
|
|
|
js.Global().Get("console").Call("log", "✅ Functions exposed to JavaScript:")
|
|
js.Global().Get("console").Call("log", " - transformData(jsonString, jsCode)")
|
|
js.Global().Get("console").Call("log", " - healthCheck()")
|
|
|
|
// Keep the program running
|
|
<-make(chan bool)
|
|
}
|