// saas-mock serves approved, static SaaS test snapshots through the formal // Dispatcher configuration API. One-shot publishing is an explicit separate mode. package main import ( "context" "errors" "flag" "log" "net/http" "os" "time" ) func main() { dataDir := flag.String("data", "", "private directory with sip.json, providers.json, quota.json and tasks/*.json") dispatcherID := flag.String("dispatcher-id", "", "approved test Dispatcher UUID") listen := flag.String("listen", "", "explicit HTTPS listen address") cert := flag.String("tls-cert", "", "HTTPS certificate file") key := flag.String("tls-key", "", "HTTPS private key file") validateOnly := flag.Bool("validate-only", false, "validate private snapshots offline without MQ or HTTPS") publishID := flag.String("publish-event-id", "", "one-shot MQ event ID matching capture --call-id") publishTask := flag.String("publish-task-id", "", "one approved single-trunk task") publishCallee := flag.String("publish-callee", "", "one original allowlisted callee") awaitResultFile := flag.String("await-result-file", "", "absolute private path for durable final result; blocks until the exact call ends") flag.Parse() secret := os.Getenv("SAAS_MOCK_DISPATCHER_SECRET") brokerURL := os.Getenv("SAAS_MOCK_RABBITMQ_URL") if *validateOnly { if *dataDir == "" || *dispatcherID == "" || *publishID != "" || *publishTask != "" || *publishCallee != "" || *awaitResultFile != "" || flag.NArg() != 0 { log.Fatal("offline validation requires only a private data directory and bound Dispatcher ID") } data, err := loadDataset(*dataDir, *dispatcherID) if err != nil { log.Fatal(err) } log.Printf("private SaaS snapshots validated: task_count=%d", len(data.tasks)) return } if *publishID != "" || *publishTask != "" || *publishCallee != "" || *awaitResultFile != "" { if *dataDir == "" || *dispatcherID == "" || brokerURL == "" || *publishID == "" || *publishTask == "" || *publishCallee == "" || flag.NArg() != 0 { log.Fatal("one-shot publish requires private data, dispatcher ID, MQ environment and explicit event/task/callee") } data, err := loadDataset(*dataDir, *dispatcherID) if err != nil { log.Fatal(err) } if *awaitResultFile != "" { ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute) defer cancel() result, err := publishAndAwait(ctx, brokerURL, data, *publishID, *publishTask, *publishCallee, *awaitResultFile, time.Now()) if err != nil { log.Fatal(err) } log.Printf("one-shot SaaS result saved and acknowledged: event_id=%q outcome=%q recording_status=%q final_user_turns=%d result_sha256=%s", *publishID, result.Outcome, result.RecordingStatus, result.Transcripts, result.BodySHA256) if result.Outcome != "answered" || result.RecordingStatus != "uploaded" { log.Fatal("real call did not produce the required answered, uploaded-recording result; stop further attempts") } return } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := publishExecute(ctx, brokerURL, data, *publishID, *publishTask, *publishCallee); err != nil { log.Fatal(err) } log.Printf("one-shot command broker-confirmed: event_id=%q task_id=%q (not SaaS result receipt)", *publishID, *publishTask) return } if *dataDir == "" || *dispatcherID == "" || *listen == "" || *cert == "" || *key == "" || secret == "" || brokerURL == "" || flag.NArg() != 0 { log.Fatal(errors.New("data, dispatcher-id, listen, tls-cert, tls-key, SAAS_MOCK_DISPATCHER_SECRET and SAAS_MOCK_RABBITMQ_URL are required")) } data, err := loadDataset(*dataDir, *dispatcherID) if err != nil { log.Fatal(err) } if err := provisionMQ(brokerURL, data); err != nil { log.Fatal(err) } log.Printf("SaaS test configuration and MQ topology ready: tasks=%d dispatcher=%s", len(data.tasks), *dispatcherID) server := http.Server{Addr: *listen, Handler: data.handler(secret), ReadHeaderTimeout: 5 * time.Second} log.Fatal(server.ListenAndServeTLS(*cert, *key)) }