package tenant import ( "fmt" "regexp" ) // CurrentRoute describes a SaaS-owned exact Topic binding. Dispatcher only // consumes/publishes; it never declares, binds, or deletes these resources. type CurrentRoute struct { Exchange string BindingKey string Queue string } var currentTaskID = regexp.MustCompile(`^[A-Za-z0-9_-]{1,128}$`) func CurrentControlRoute(dispatcherID string) (CurrentRoute, error) { if err := ValidateDispatcherID(dispatcherID); err != nil { return CurrentRoute{}, err } return currentRoute("agent-call.dispatchers.v1", "d."+dispatcherID+".control.in", "agent-call.d."+dispatcherID+".control.v1") } func CurrentTaskRoute(dispatcherID, taskID string) (CurrentRoute, error) { if err := ValidateDispatcherID(dispatcherID); err != nil { return CurrentRoute{}, err } if !currentTaskID.MatchString(taskID) { return CurrentRoute{}, fmt.Errorf("invalid task ID for exact MQ route") } return currentRoute("agent-call.dispatchers.v1", "d."+dispatcherID+".task."+taskID+".in", "agent-call.d."+dispatcherID+".task."+taskID+".v1") } func CurrentResultRoute(dispatcherID string) (CurrentRoute, error) { if err := ValidateDispatcherID(dispatcherID); err != nil { return CurrentRoute{}, err } // The shared queue name is only a project-local Mock fixture. SaaS owns // the actual receiving queue and exact bindings for each Dispatcher. return currentRoute("agent-call.saas.v1", "d."+dispatcherID+".out", "agent-call.saas.events.v1") } func currentRoute(exchange, key, queue string) (CurrentRoute, error) { if len(key) > 255 || len(queue) > 255 { return CurrentRoute{}, fmt.Errorf("AMQP route exceeds 255 bytes") } return CurrentRoute{Exchange: exchange, BindingKey: key, Queue: queue}, nil }