Files
go-sip/internal/tenant/routing.go
T

50 lines
1.6 KiB
Go

package tenant
import (
"fmt"
"regexp"
)
// Route describes a SaaS-owned exact Topic binding. Dispatcher only
// consumes/publishes; it never declares, binds, or deletes these resources.
type Route struct {
Exchange string
BindingKey string
Queue string
}
var taskIDPattern = regexp.MustCompile(`^[A-Za-z0-9_-]{1,128}$`)
func ControlRoute(dispatcherID string) (Route, error) {
if err := ValidateDispatcherID(dispatcherID); err != nil {
return Route{}, err
}
return exactRoute("agent-call.dispatchers.v1", "d."+dispatcherID+".control.in", "agent-call.d."+dispatcherID+".control.v1")
}
func TaskRoute(dispatcherID, taskID string) (Route, error) {
if err := ValidateDispatcherID(dispatcherID); err != nil {
return Route{}, err
}
if !taskIDPattern.MatchString(taskID) {
return Route{}, fmt.Errorf("invalid task ID for exact MQ route")
}
return exactRoute("agent-call.dispatchers.v1", "d."+dispatcherID+".task."+taskID+".in", "agent-call.d."+dispatcherID+".task."+taskID+".v1")
}
func ResultRoute(dispatcherID string) (Route, error) {
if err := ValidateDispatcherID(dispatcherID); err != nil {
return Route{}, 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 exactRoute("agent-call.saas.v1", "d."+dispatcherID+".out", "agent-call.saas.events.v1")
}
func exactRoute(exchange, key, queue string) (Route, error) {
if len(key) > 255 || len(queue) > 255 {
return Route{}, fmt.Errorf("AMQP route exceeds 255 bytes")
}
return Route{Exchange: exchange, BindingKey: key, Queue: queue}, nil
}