Files
Hanzo Dev 54a40e19c1 goa: pure-Go polyglot embedding (Go, Python, TS/JS, Rust/WASM)
One Module/Engine interface with a JSON-in/JSON-out calling convention runs
four pure-Go engines behind a Pool that makes single-threaded interpreters
serve requests as parallel goroutines:

  native               plain Go handlers, zero overhead
  goja + esbuild       JavaScript and TypeScript (TS transpiled to ES2020)
  gpython              Python, no cgo and no GIL -> true goroutine parallelism
  wazero               Rust/WASM via a trivial string ABI

Services mount from a manifest (lang + source + routes), so any Go, Python,
Rust or JS backend collapses into a single static CGO_ENABLED=0 binary served
on the zip/gofiber app. A Go-backed json stdlib shim lets Python backends keep
importing the real module names while running at Go speed.

Examples and tests cover every engine; the Rust guest is a real wasm32 fixture
exercised end to end.
2026-06-28 19:14:19 -07:00

70 lines
2.2 KiB
Go

package goa
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
// Route binds an HTTP method+path to an exported function in the module.
type Route struct {
Method string `json:"method"` // GET, POST, ...
Path string `json:"path"` // e.g. /greet (combined with the service Prefix)
Func string `json:"func"` // exported function name to invoke
}
// Service is a mounted polyglot module: a Pool of interpreters plus the route
// table that maps HTTP requests onto its functions. Handler() returns a plain
// net/http.Handler so any host can serve it — in hanzoai/cloud it is mounted
// onto the zip/gofiber app via zip.AdaptNetHTTP, keeping goa host-agnostic.
type Service struct {
Name string
Prefix string // e.g. /v1/greeter ; routes are mounted under it
Pool *Pool
Routes []Route
}
// Mount registers this service's routes onto an existing mux, so a host can
// serve many services from one mux (the Go 1.22 "METHOD /path" patterns keep
// them non-conflicting). This is the single route-registration path.
func (s *Service) Mount(mux *http.ServeMux) {
for _, r := range s.Routes {
fn := r.Func
pattern := fmt.Sprintf("%s %s%s", r.Method, s.Prefix, r.Path)
mux.HandleFunc(pattern, func(w http.ResponseWriter, req *http.Request) {
body, err := io.ReadAll(io.LimitReader(req.Body, 32<<20))
if err != nil {
writeErr(w, http.StatusBadRequest, err)
return
}
if len(body) == 0 {
body = []byte("{}")
}
out, err := s.Pool.Invoke(req.Context(), fn, body)
if err != nil {
writeErr(w, http.StatusInternalServerError, err)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(out)
})
}
}
// Handler returns a standalone http.Handler serving just this service. In
// hanzoai/cloud it is mounted onto the zip/gofiber app via zip.AdaptNetHTTP,
// keeping goa host-agnostic. To serve many services from one mux, use Mount.
func (s *Service) Handler() http.Handler {
mux := http.NewServeMux()
s.Mount(mux)
return mux
}
func writeErr(w http.ResponseWriter, code int, err error) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
b, _ := json.Marshal(map[string]string{"error": err.Error()})
_, _ = w.Write(b)
}