Files
story/internal/httpapi/router.go
T

295 lines
24 KiB
Go

package httpapi
import (
"log/slog"
"net/http"
"time"
"data-terminal-cloud/internal/alerts"
"data-terminal-cloud/internal/billing"
"data-terminal-cloud/internal/buildinfo"
"data-terminal-cloud/internal/device"
"data-terminal-cloud/internal/diagnostics"
"data-terminal-cloud/internal/health"
"data-terminal-cloud/internal/identity"
"data-terminal-cloud/internal/media"
"data-terminal-cloud/internal/opsaccess"
"data-terminal-cloud/internal/opsconfig"
"data-terminal-cloud/internal/saas"
"data-terminal-cloud/internal/sharing"
"data-terminal-cloud/internal/webevents"
)
type RouterOptions struct {
ServiceName string
Logger *slog.Logger
RateLimiter RateLimiter
Readiness *health.Checker
TokenVerifier *identity.OIDCVerifier
IdentityRepository *identity.Repository
SaaSService *saas.Service
DeviceVerifier DeviceRequestVerifier
DeviceService *device.Repository
DeviceTelemetrySubmitter DeviceTelemetrySubmitter
MediaService *media.Service
WebEventService *webevents.Service
SharingService *sharing.Service
OpsConfigService *opsconfig.Service
BillingService *billing.Service
AlertService *alerts.Service
DiagnosticService *diagnostics.Service
OpsAccessService *opsaccess.Service
ConversationCreator ConversationCreator
ConversationActivator ConversationActivator
DeviceConversationStateReader DeviceConversationStateReader
ConversationHeartbeater ConversationHeartbeater
ConversationStopper ConversationStopper
ConversationTranscriptSubmitter ConversationTranscriptSubmitter
ProviderCallbackSecret []byte
ProviderCallbackSkew time.Duration
ProviderCallbackProcessor ProviderCallbackProcessor
PlatformHealthCallbackSecret []byte
PlatformHealthCallbackSkew time.Duration
PlatformHealthProcessor PlatformHealthProcessor
}
func NewRouter(options RouterOptions) http.Handler {
logger := options.Logger
if logger == nil {
logger = slog.Default()
}
mux := http.NewServeMux()
mux.Handle("GET /metrics", MetricsHandler())
mux.HandleFunc("GET /health/live", func(writer http.ResponseWriter, request *http.Request) {
WriteJSON(writer, request, http.StatusOK, map[string]string{
"status": "alive",
"service": options.ServiceName,
})
})
mux.HandleFunc("GET /health/ready", func(writer http.ResponseWriter, request *http.Request) {
result := options.Readiness.Ready(request.Context())
status := http.StatusOK
if result.Status != "ready" {
status = http.StatusServiceUnavailable
}
WriteJSON(writer, request, status, result)
})
mux.HandleFunc("GET /api/v1/version", func(writer http.ResponseWriter, request *http.Request) {
WriteJSON(writer, request, http.StatusOK, buildinfo.Current())
})
if options.ServiceName == "api" && options.TokenVerifier != nil && options.IdentityRepository != nil {
mux.Handle("GET /api/v1/me", BearerAuth(options.TokenVerifier, UserRateLimit(logger, options.RateLimiter, CurrentUserHandler(options.IdentityRepository))))
}
if options.ServiceName == "api" && options.TokenVerifier != nil && options.SaaSService != nil {
authenticated := func(handler http.Handler) http.Handler {
return BearerAuth(options.TokenVerifier, UserRateLimit(logger, options.RateLimiter, handler))
}
if options.WebEventService != nil {
mux.Handle("GET /api/v1/events", authenticated(StreamWebEventsHandler(options.WebEventService)))
}
if options.SharingService != nil {
mux.Handle("GET /api/v1/sharing-grants", authenticated(ListSharingGrantsHandler(options.SharingService)))
mux.Handle("POST /api/v1/sharing-grants", authenticated(CreateSharingGrantHandler(options.SharingService)))
mux.Handle("DELETE /api/v1/sharing-grants/{id}", authenticated(RevokeSharingGrantHandler(options.SharingService)))
mux.Handle("GET /api/v1/sharing-grants/{id}/resource", authenticated(AccessSharedResourceHandler(options.SharingService)))
mux.Handle("PATCH /api/v1/sharing-grants/{id}/resource", authenticated(EditSharedStoryHandler(options.SharingService)))
}
if options.OpsConfigService != nil {
mux.Handle("GET /api/v1/ops/resource-references", authenticated(ListOpsResourceReferencesHandler(options.OpsConfigService)))
mux.Handle("POST /api/v1/ops/resource-references", authenticated(CreateOpsResourceReferenceHandler(options.OpsConfigService)))
mux.Handle("PATCH /api/v1/ops/resource-references/{id}/revoke", authenticated(RevokeOpsResourceReferenceHandler(options.OpsConfigService)))
mux.Handle("GET /api/v1/ops/device-groups", authenticated(ListOpsDeviceGroupsHandler(options.OpsConfigService)))
mux.Handle("POST /api/v1/ops/device-groups", authenticated(CreateOpsDeviceGroupHandler(options.OpsConfigService)))
mux.Handle("GET /api/v1/ops/config-rollouts", authenticated(ListOpsConfigRolloutsHandler(options.OpsConfigService)))
mux.Handle("PATCH /api/v1/ops/config-rollouts/{id}/pause", authenticated(PauseOpsConfigRolloutHandler(options.OpsConfigService)))
mux.Handle("PATCH /api/v1/ops/config-rollouts/{id}/resume", authenticated(ResumeOpsConfigRolloutHandler(options.OpsConfigService)))
mux.Handle("GET /api/v1/ops/config-versions", authenticated(ListOpsConfigVersionsHandler(options.OpsConfigService)))
mux.Handle("POST /api/v1/ops/config-versions", authenticated(CreateOpsConfigVersionHandler(options.OpsConfigService)))
mux.Handle("GET /api/v1/ops/config-versions/{id}/evaluations", authenticated(ListOpsConfigEvaluationsHandler(options.OpsConfigService)))
mux.Handle("POST /api/v1/ops/config-versions/{id}/evaluations", authenticated(CreateOpsConfigEvaluationHandler(options.OpsConfigService)))
mux.Handle("PATCH /api/v1/ops/config-versions/{id}/submit", authenticated(SubmitOpsConfigVersionHandler(options.OpsConfigService)))
mux.Handle("PATCH /api/v1/ops/config-versions/{id}/publish", authenticated(PublishOpsConfigVersionHandler(options.OpsConfigService)))
mux.Handle("POST /api/v1/ops/config-versions/{id}/rollback", authenticated(RollbackOpsConfigVersionHandler(options.OpsConfigService)))
}
if options.BillingService != nil {
mux.Handle("GET /api/v1/ops/price-books", authenticated(ListOpsPriceBooksHandler(options.BillingService)))
mux.Handle("POST /api/v1/ops/price-books", authenticated(CreateOpsPriceBookHandler(options.BillingService)))
mux.Handle("PATCH /api/v1/ops/price-books/{id}/publish", authenticated(PublishOpsPriceBookHandler(options.BillingService)))
mux.Handle("GET /api/v1/ops/quota-policies", authenticated(ListOpsQuotaPoliciesHandler(options.BillingService)))
mux.Handle("POST /api/v1/ops/quota-policies", authenticated(CreateOpsQuotaPolicyHandler(options.BillingService)))
mux.Handle("GET /api/v1/ops/cost-summary", authenticated(GetOpsCostSummaryHandler(options.BillingService)))
}
if options.DiagnosticService != nil {
mux.Handle("GET /api/v1/ops/diagnostics/platform-health", authenticated(GetOpsPlatformHealthHandler(options.DiagnosticService)))
mux.Handle("GET /api/v1/ops/integration-issues", authenticated(ListOpsIntegrationIssuesHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/integration-issues", authenticated(CreateOpsIntegrationIssueHandler(options.DiagnosticService)))
mux.Handle("PATCH /api/v1/ops/integration-issues/{id}", authenticated(UpdateOpsIntegrationIssueHandler(options.DiagnosticService)))
mux.Handle("GET /api/v1/ops/diagnostics/search", authenticated(SearchOpsDiagnosticsHandler(options.DiagnosticService)))
mux.Handle("GET /api/v1/ops/diagnostics/external-dependencies", authenticated(ListOpsExternalDependenciesHandler(options.DiagnosticService)))
mux.Handle("GET /api/v1/ops/diagnostics/jobs", authenticated(ListOpsDiagnosticJobsHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/jobs/{id}/retry", authenticated(RetryOpsDiagnosticJobHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/bundles", authenticated(ExportOpsDiagnosticBundleHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/acceptance-snapshots", authenticated(ExportOpsAcceptanceSnapshotHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/pilot-daily-snapshots", authenticated(ExportOpsPilotDailySnapshotHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/pilot-weekly-snapshots", authenticated(ExportOpsPilotWeeklySnapshotHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/conversations/{id}/stop", authenticated(StopOpsDiagnosticConversationHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/conversations/{id}/reconcile", authenticated(ReconcileOpsDiagnosticConversationHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/devices/{id}/config-refresh", authenticated(RefreshOpsDiagnosticDeviceConfigHandler(options.DiagnosticService)))
mux.Handle("POST /api/v1/ops/diagnostics/devices/{id}/revoke", authenticated(RevokeOpsDiagnosticDeviceHandler(options.DiagnosticService)))
}
if options.OpsAccessService != nil {
mux.Handle("GET /api/v1/ops/sensitive-access-requests", authenticated(ListOpsSensitiveAccessRequestsHandler(options.OpsAccessService)))
mux.Handle("POST /api/v1/ops/sensitive-access-requests", authenticated(CreateOpsSensitiveAccessRequestHandler(options.OpsAccessService)))
mux.Handle("POST /api/v1/ops/sensitive-access-requests/{id}/review", authenticated(ReviewOpsSensitiveAccessRequestHandler(options.OpsAccessService)))
mux.Handle("GET /api/v1/ops/sensitive-conversations/{id}", authenticated(GetOpsSensitiveConversationHandler(options.OpsAccessService)))
mux.Handle("POST /api/v1/ops/sensitive-media/{id}/play", authenticated(CreateOpsSensitiveRecordingAccessHandler(options.OpsAccessService)))
}
mux.Handle("GET /api/v1/households", authenticated(ListHouseholdsHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households", authenticated(CreateHouseholdHandler(options.SaaSService)))
mux.Handle("GET /api/v1/households/{id}", authenticated(GetHouseholdHandler(options.SaaSService)))
mux.Handle("PATCH /api/v1/households/{id}", authenticated(PatchHouseholdHandler(options.SaaSService)))
mux.Handle("GET /api/v1/households/{id}/members", authenticated(ListHouseholdMembersHandler(options.SaaSService)))
mux.Handle("PATCH /api/v1/households/{id}/members/{member_id}", authenticated(PatchHouseholdMemberHandler(options.SaaSService)))
mux.Handle("DELETE /api/v1/households/{id}/members/{member_id}", authenticated(RemoveHouseholdMemberHandler(options.SaaSService)))
mux.Handle("GET /api/v1/households/{id}/invitations", authenticated(ListMemberInvitationsHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households/{id}/invitations", authenticated(CreateMemberInvitationHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households/{id}/invitations/{invitation_id}/revoke", authenticated(RevokeMemberInvitationHandler(options.SaaSService)))
mux.Handle("POST /api/v1/member-invitations/preview", authenticated(PreviewMemberInvitationHandler(options.SaaSService)))
mux.Handle("POST /api/v1/member-invitations/accept", authenticated(AcceptMemberInvitationHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households/{id}/ownership", authenticated(TransferHouseholdOwnershipHandler(options.SaaSService)))
mux.Handle("GET /api/v1/households/{id}/subjects", authenticated(ListSubjectsHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households/{id}/subjects", authenticated(CreateSubjectHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}", authenticated(GetSubjectHandler(options.SaaSService)))
mux.Handle("PATCH /api/v1/subjects/{id}", authenticated(PatchSubjectHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}/conversation-readiness", authenticated(GetConversationReadinessHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}/facts", authenticated(ListSubjectFactsHandler(options.SaaSService)))
mux.Handle("POST /api/v1/subjects/{id}/facts", authenticated(CreateSubjectFactHandler(options.SaaSService)))
mux.Handle("PATCH /api/v1/subjects/{id}/facts/{fact_id}", authenticated(PatchSubjectFactHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}/consents", authenticated(ListConsentsHandler(options.SaaSService)))
mux.Handle("POST /api/v1/subjects/{id}/consents", authenticated(GrantConsentHandler(options.SaaSService)))
mux.Handle("POST /api/v1/subjects/{id}/consents/{consent_id}/withdraw", authenticated(WithdrawConsentHandler(options.SaaSService)))
mux.Handle("POST /api/v1/device-claims", authenticated(ClaimDeviceHandler(options.SaaSService)))
mux.Handle("GET /api/v1/devices", authenticated(ListManagedDevicesHandler(options.SaaSService)))
mux.Handle("GET /api/v1/devices/{id}", authenticated(GetManagedDeviceHandler(options.SaaSService)))
mux.Handle("GET /api/v1/devices/{id}/presence", authenticated(GetDevicePresenceHandler(options.SaaSService)))
mux.Handle("GET /api/v1/devices/{id}/twin", authenticated(GetDeviceTwinHandler(options.SaaSService)))
mux.Handle("PATCH /api/v1/devices/{id}/twin", authenticated(PatchDeviceTwinHandler(options.SaaSService)))
mux.Handle("GET /api/v1/devices/{id}/commands", authenticated(ListDeviceCommandsHandler(options.SaaSService)))
mux.Handle("POST /api/v1/devices/{id}/commands", authenticated(CreateDeviceCommandHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households/{id}/firmware-releases", authenticated(PrepareFirmwareReleaseHandler(options.SaaSService)))
mux.Handle("GET /api/v1/households/{id}/firmware-releases", authenticated(ListFirmwareReleasesHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households/{id}/firmware-signing-keys", authenticated(RegisterFirmwareSigningKeyHandler(options.SaaSService)))
mux.Handle("GET /api/v1/households/{id}/firmware-signing-keys", authenticated(ListFirmwareSigningKeysHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households/{id}/firmware-signing-keys/revoke", authenticated(RevokeFirmwareSigningKeyHandler(options.SaaSService)))
mux.Handle("GET /api/v1/firmware-releases/{id}/impact", authenticated(GetFirmwareReleaseImpactHandler(options.SaaSService)))
mux.Handle("POST /api/v1/firmware-releases/{id}/finalize", authenticated(FinalizeFirmwareReleaseHandler(options.SaaSService)))
mux.Handle("POST /api/v1/firmware-releases/{id}/upload-session", authenticated(RenewFirmwareUploadHandler(options.SaaSService)))
mux.Handle("POST /api/v1/firmware-releases/{id}/pause", authenticated(PauseFirmwareReleaseHandler(options.SaaSService)))
mux.Handle("POST /api/v1/firmware-releases/{id}/resume", authenticated(ResumeFirmwareReleaseHandler(options.SaaSService)))
mux.Handle("POST /api/v1/firmware-releases/{id}/retire", authenticated(RetireFirmwareReleaseHandler(options.SaaSService)))
mux.Handle("POST /api/v1/households/{id}/firmware-rollouts", authenticated(StartFirmwareRolloutHandler(options.SaaSService)))
mux.Handle("GET /api/v1/households/{id}/firmware-rollouts", authenticated(ListFirmwareRolloutsHandler(options.SaaSService)))
mux.Handle("GET /api/v1/firmware-rollouts/{id}", authenticated(GetFirmwareRolloutHandler(options.SaaSService)))
mux.Handle("POST /api/v1/firmware-rollouts/{id}/pause", authenticated(PauseFirmwareRolloutHandler(options.SaaSService)))
mux.Handle("POST /api/v1/firmware-rollouts/{id}/rollback", authenticated(RollbackFirmwareRolloutHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}/conversations", authenticated(ListSubjectConversationsHandler(options.SaaSService)))
mux.Handle("GET /api/v1/conversations/{id}", authenticated(GetConversationHandler(options.SaaSService)))
mux.Handle("GET /api/v1/conversations/{id}/usage", authenticated(GetConversationUsageHandler(options.SaaSService)))
if options.MediaService != nil {
mux.Handle("GET /api/v1/subjects/{id}/recording-access-grants", authenticated(ListRecordingAccessGrantsHandler(options.MediaService)))
mux.Handle("POST /api/v1/subjects/{id}/recording-access-grants", authenticated(GrantRecordingAccessHandler(options.MediaService)))
mux.Handle("POST /api/v1/recording-access-grants/{id}/revoke", authenticated(RevokeRecordingAccessHandler(options.MediaService)))
mux.Handle("GET /api/v1/conversations/{id}/media", authenticated(GetConversationMediaHandler(options.MediaService)))
mux.Handle("POST /api/v1/media-segments/{id}/access", authenticated(CreateMediaAccessHandler(options.MediaService)))
}
mux.Handle("GET /api/v1/conversations/{id}/turns", authenticated(ListConversationTurnsHandler(options.SaaSService)))
mux.Handle("GET /api/v1/conversations/{id}/summaries", authenticated(ListConversationSummariesHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}/stories", authenticated(ListSubjectStoriesHandler(options.SaaSService)))
mux.Handle("GET /api/v1/stories/{id}", authenticated(GetStoryHandler(options.SaaSService)))
mux.Handle("PATCH /api/v1/stories/{id}", authenticated(PatchStoryHandler(options.SaaSService)))
mux.Handle("POST /api/v1/stories/{id}/confirm", authenticated(ConfirmStoryHandler(options.SaaSService)))
mux.Handle("POST /api/v1/stories/{id}/reject", authenticated(RejectStoryHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}/memories", authenticated(ListSubjectMemoriesHandler(options.SaaSService)))
mux.Handle("GET /api/v1/memories/{id}", authenticated(GetMemoryHandler(options.SaaSService)))
mux.Handle("PATCH /api/v1/memories/{id}", authenticated(PatchMemoryHandler(options.SaaSService)))
mux.Handle("DELETE /api/v1/memories/{id}", authenticated(DeleteMemoryHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}/privacy-requests", authenticated(ListPrivacyRequestsHandler(options.SaaSService)))
mux.Handle("POST /api/v1/subjects/{id}/privacy-requests", authenticated(CreatePrivacyRequestHandler(options.SaaSService)))
mux.Handle("GET /api/v1/privacy-requests/{id}", authenticated(GetPrivacyRequestHandler(options.SaaSService)))
mux.Handle("GET /api/v1/subjects/{id}/exports", authenticated(ListExportTasksHandler(options.SaaSService)))
mux.Handle("POST /api/v1/subjects/{id}/exports", authenticated(CreateExportTaskHandler(options.SaaSService)))
mux.Handle("GET /api/v1/exports/{id}", authenticated(GetExportTaskHandler(options.SaaSService)))
}
if options.ServiceName == "api" && options.TokenVerifier != nil && options.AlertService != nil {
authenticated := func(handler http.Handler) http.Handler {
return BearerAuth(options.TokenVerifier, UserRateLimit(logger, options.RateLimiter, handler))
}
mux.Handle("GET /api/v1/ops/alert-routing-policies", authenticated(ListOpsAlertRoutingPoliciesHandler(options.AlertService)))
mux.Handle("POST /api/v1/ops/alert-routing-policies", authenticated(CreateOpsAlertRoutingPolicyHandler(options.AlertService)))
mux.Handle("GET /api/v1/ops/alert-delivery-tests", authenticated(ListOpsAlertDeliveryTestsHandler(options.AlertService)))
mux.Handle("POST /api/v1/ops/alert-routing-policies/{id}/delivery-tests", authenticated(CreateOpsAlertDeliveryTestHandler(options.AlertService)))
mux.Handle("GET /api/v1/ops/alerts", authenticated(ListOpsAlertsHandler(options.AlertService)))
mux.Handle("GET /api/v1/ops/alerts/{id}", authenticated(GetOpsAlertHandler(options.AlertService)))
mux.Handle("POST /api/v1/ops/alerts/{id}/acknowledge", authenticated(TransitionOpsAlertHandler(options.AlertService, "ACKNOWLEDGE")))
mux.Handle("POST /api/v1/ops/alerts/{id}/mitigate", authenticated(TransitionOpsAlertHandler(options.AlertService, "MITIGATE")))
mux.Handle("POST /api/v1/ops/alerts/{id}/resolve", authenticated(TransitionOpsAlertHandler(options.AlertService, "RESOLVE")))
mux.Handle("GET /api/v1/ops/alert-silences", authenticated(ListOpsAlertSilencesHandler(options.AlertService)))
mux.Handle("POST /api/v1/ops/alert-silences", authenticated(CreateOpsAlertSilenceHandler(options.AlertService)))
mux.Handle("POST /api/v1/ops/alert-silences/{id}/revoke", authenticated(RevokeOpsAlertSilenceHandler(options.AlertService)))
}
if options.ServiceName == "api" && options.SharingService != nil {
mux.Handle("GET /api/v1/public/shares/{id}", AccessPublicSharedResourceHandler(options.SharingService))
}
if options.ServiceName == "api" && options.DeviceVerifier != nil && options.DeviceService != nil {
deviceAuthenticated := func(handler http.Handler) http.Handler {
return DeviceAuth(options.DeviceVerifier, DeviceRateLimit(logger, options.RateLimiter, handler))
}
mux.Handle("GET /device/v2/bootstrap", deviceAuthenticated(DeviceBootstrapHandler(options.DeviceService)))
mux.Handle("GET /device/v2/config", deviceAuthenticated(DeviceConfigHandler(options.DeviceService)))
mux.Handle("GET /device/v2/commands", deviceAuthenticated(PullDeviceCommandsHandler(options.DeviceService)))
mux.Handle("POST /device/v2/commands/{id}/ack", deviceAuthenticated(AcknowledgeDeviceCommandHandler(options.DeviceService)))
if options.DeviceTelemetrySubmitter != nil {
mux.Handle("POST /device/v2/telemetry:batch", deviceAuthenticated(SubmitDeviceTelemetryHandler(options.DeviceTelemetrySubmitter)))
}
mux.Handle("GET /device/v2/firmware-releases/{id}/download", deviceAuthenticated(DeviceFirmwareDownloadHandler(options.SaaSService)))
if options.MediaService != nil {
mux.Handle("POST /device/v2/conversations/{id}/upload-batches", deviceAuthenticated(PrepareMediaUploadBatchHandler(options.MediaService)))
mux.Handle("POST /device/v2/upload-batches/{id}/complete", deviceAuthenticated(CompleteMediaUploadBatchHandler(options.MediaService)))
mux.Handle("GET /device/v2/upload-batches/{id}", deviceAuthenticated(GetDeviceMediaUploadBatchHandler(options.MediaService)))
mux.Handle("POST /device/v2/media-segments/{id}/local-delete-ack", deviceAuthenticated(AcknowledgeLocalMediaDeleteHandler(options.MediaService)))
}
if options.ConversationCreator != nil {
mux.Handle("POST /device/v2/conversations", deviceAuthenticated(CreateConversationHandler(options.ConversationCreator)))
}
if options.ConversationActivator != nil {
mux.Handle("POST /device/v2/conversations/{id}/activate", deviceAuthenticated(ActivateConversationHandler(options.ConversationActivator)))
}
if options.DeviceConversationStateReader != nil {
mux.Handle("GET /device/v2/conversations/{id}", deviceAuthenticated(GetDeviceConversationStateHandler(options.DeviceConversationStateReader)))
}
if options.ConversationHeartbeater != nil {
mux.Handle("POST /device/v2/conversations/{id}/heartbeat", deviceAuthenticated(HeartbeatConversationHandler(options.ConversationHeartbeater)))
}
if options.ConversationStopper != nil {
mux.Handle("POST /device/v2/conversations/{id}/stop", deviceAuthenticated(StopConversationHandler(options.ConversationStopper)))
}
if options.ConversationTranscriptSubmitter != nil {
mux.Handle("POST /device/v2/conversations/{id}/turns:batch", deviceAuthenticated(SubmitConversationTurnsHandler(options.ConversationTranscriptSubmitter)))
}
}
if options.ServiceName == "callbacks" && len(options.ProviderCallbackSecret) > 0 && options.ProviderCallbackProcessor != nil {
mux.Handle("POST /callbacks/v1/vertc/voice-chat", VoiceProviderCallbackHandler(
options.ProviderCallbackSecret, options.ProviderCallbackSkew, options.ProviderCallbackProcessor,
))
}
if options.ServiceName == "callbacks" && len(options.PlatformHealthCallbackSecret) > 0 && options.PlatformHealthProcessor != nil {
mux.Handle("POST /callbacks/v1/platform-health", PlatformHealthCallbackHandler(
options.PlatformHealthCallbackSecret, options.PlatformHealthCallbackSkew, options.PlatformHealthProcessor,
))
}
mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
WriteError(writer, request, http.StatusNotFound, "RESOURCE_NOT_FOUND", "请求的资源不存在")
})
return mux
}