Files
go-sip/deploys/test/saas-mock/main.go
T

83 lines
3.9 KiB
Go

// 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))
}