源码索引 / CURRENT IMPLEMENTATION
bridge.go
86 行 · 构建时读取的实际文件,不是讲解用伪代码。
package spine
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/tetratelabs/wazero/api"
)
// Tool runs on the Host. args is Go-owned; no borrowed Guest memory escapes.
// Treat args as read-only; the run also retains them for Future matching.
// Tools explicitly registered for early reads must be snapshot reads and honor ctx.
type Tool func(ctx context.Context, args json.RawMessage) (any, error)
type callRequest struct {
Tool string `json:"tool"`
Args json.RawMessage `json:"args"`
}
func readRequest(m api.Module, ptr, size uint32) (callRequest, error) {
var request callRequest
data, ok := m.Memory().Read(ptr, size)
if !ok || size > maxMessage {
return request, errors.New("tool request outside ABI bounds")
}
err := json.Unmarshal(data, &request)
return request, err
}
func encodeResponse(value any, err error) []byte {
response := struct {
Value any `json:"value"`
Error *string `json:"error,omitempty"`
}{Value: value}
if err != nil {
response.Value = nil
message := err.Error()
response.Error = &message
}
encoded, err := json.Marshal(response)
if err != nil {
encoded, _ = json.Marshal(map[string]string{"error": "tool result is not JSON: " + err.Error()})
}
return encoded
}
func (r *Runner) invoke(ctx context.Context, request callRequest) []byte {
fn := r.tools[request.Tool]
if fn == nil {
return encodeResponse(nil, fmt.Errorf("unknown tool: %s", request.Tool))
}
value, err := fn(ctx, request.Args)
return encodeResponse(value, err)
}
func (r *Runner) hostCall(ctx context.Context, m api.Module, ptr, size, out, capacity uint32) uint32 {
request, err := readRequest(m, ptr, size)
var response []byte
if err != nil {
response = encodeResponse(nil, err)
} else {
response = r.invoke(ctx, request)
}
return writeResponse(m, out, capacity, response)
}
func (r *Runner) hostPrepare(ctx context.Context, m api.Module, ptr, size uint32) uint32 {
request, err := readRequest(m, ptr, size)
if err != nil {
return 0
}
return ctx.Value(runKey{}).(*runState).prepare(request)
}
func (r *Runner) hostResolve(ctx context.Context, m api.Module, id, ptr, size, out, capacity uint32) uint32 {
request, err := readRequest(m, ptr, size)
var response []byte
if err != nil {
response = encodeResponse(nil, err)
} else {
response = ctx.Value(runKey{}).(*runState).resolve(id, request)
}
return writeResponse(m, out, capacity, response)
}