源码索引 / CURRENT IMPLEMENTATION
cmd/walkthrough/main.go
171 行 · 点击行号可定位;函数链接随声明位置更新,不手填行号。
跳到函数 / 声明
package main
import (
"context"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"os"
"strings"
"time"
spine "pysolate-spine"
)
type scenario string
const (
normal scenario = "normal"
denied scenario = "denied"
unknown scenario = "unknown"
)
type report struct {
Title string `json:"title"`
Items int `json:"items"`
}
type notice struct {
Status string `json:"status"`
}
type notificationHost struct {
scenario scenario
events []string
calls map[string]int
args map[string][]json.RawMessage
serviceDelivered bool // Independent evaluation state; never returned to Guest.
}
func newNotificationHost(s scenario) *notificationHost {
return ¬ificationHost{scenario: s, calls: make(map[string]int), args: make(map[string][]json.RawMessage)}
}
func (h *notificationHost) record(name string, args json.RawMessage) {
h.calls[name]++
h.args[name] = append(h.args[name], append(json.RawMessage(nil), args...))
}
func (h *notificationHost) manifest() spine.Manifest {
return spine.Manifest{
"get_report": {Call: func(_ context.Context, args json.RawMessage) (any, error) {
h.record("get_report", args)
var empty map[string]any
if err := json.Unmarshal(args, &empty); err != nil || len(empty) != 0 {
return nil, errors.New("get_report expects no arguments")
}
h.events = append(h.events, "get_report({}) -> report")
return report{Title: "Daily summary", Items: 3}, nil
}},
"send_notification": {Call: func(_ context.Context, args json.RawMessage) (any, error) {
h.record("send_notification", args)
var request struct {
Message string `json:"message"`
}
if err := json.Unmarshal(args, &request); err != nil || request.Message != "Daily summary: 3 items" {
return nil, errors.New("send_notification received an unexpected message")
}
status := "sent"
switch h.scenario {
case normal:
h.serviceDelivered = true
case denied:
status = "denied" // Rejected before any simulated dispatch.
case unknown:
status = "unknown"
h.serviceDelivered = true // Dispatch happened; confirmation was lost.
default:
return nil, fmt.Errorf("unsupported scenario: %s", h.scenario)
}
h.events = append(h.events, fmt.Sprintf("send_notification(message=%q) -> %s", request.Message, status))
return notice{Status: status}, nil
}},
}
}
func validScenario(value string) (scenario, error) {
switch scenario(value) {
case normal, denied, unknown:
return scenario(value), nil
default:
return "", fmt.Errorf("invalid scenario %q (choose normal, denied, unknown, or all)", value)
}
}
func main() {
if err := runCLI(os.Args[1:], os.Stdout, os.Stderr); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func runCLI(args []string, stdout, stderr io.Writer) error {
flags := flag.NewFlagSet("walkthrough", flag.ContinueOnError)
flags.SetOutput(stderr)
artifact := flags.String("wasm", "dist/spine.wasm", "path to an existing CPython Wasm artifact (does not build or download it)")
selected := flags.String("scenario", "all", "notification case: normal, denied, unknown, or all")
if err := flags.Parse(args); err != nil {
if errors.Is(err, flag.ErrHelp) {
return nil
}
return err
}
if flags.NArg() != 0 {
return fmt.Errorf("unexpected positional arguments: %s", strings.Join(flags.Args(), " "))
}
code, err := os.ReadFile("examples/notification.py")
if err != nil {
return err
}
cases := []scenario{normal, denied, unknown}
if *selected != "all" {
one, err := validScenario(*selected)
if err != nil {
return err
}
cases = []scenario{one}
}
wasm, err := os.ReadFile(*artifact)
if err != nil {
return fmt.Errorf("read existing Wasm artifact %q (build it separately; walkthrough never downloads or builds it): %w", *artifact, err)
}
fmt.Fprintln(stdout, "Python source (examples/notification.py):")
fmt.Fprintln(stdout, strings.TrimSpace(string(code)))
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
for _, current := range cases {
if err := runScenario(ctx, wasm, string(code), current, stdout); err != nil {
return err
}
}
return nil
}
func runScenario(ctx context.Context, wasm []byte, source string, current scenario, stdout io.Writer) error {
host := newNotificationHost(current)
runner, err := spine.New(ctx, wasm, host.manifest())
if err != nil {
return err
}
defer runner.Close(context.Background())
out, runErr := runner.Run(ctx, source, map[string]any{})
fmt.Fprintf(stdout, "\nScenario: %s\n", current)
for _, event := range host.events {
fmt.Fprintf(stdout, "Host: %s\n", event)
}
if out.Stdout != "" {
fmt.Fprintf(stdout, "Guest output: %s", out.Stdout)
if !strings.HasSuffix(out.Stdout, "\n") {
fmt.Fprintln(stdout)
}
}
if runErr != nil {
return fmt.Errorf("Guest run failed in scenario %s: %w", current, runErr)
}
fmt.Fprintf(stdout, "Result: %s\n", out.Value)
fmt.Fprintf(stdout, "Evaluation only (not Guest-visible): simulated service delivered=%t\n", host.serviceDelivered)
return nil
}