mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 08:36:57 +00:00
feat: add WebRTC feature management commands and public API endpoints for enabling, disabling, and checking status
This commit is contained in:
parent
e6f828d6f1
commit
e4d51676cc
@ -45,10 +45,59 @@ var repairCmd = &cobra.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var enableCmd = &cobra.Command{
|
||||||
|
Use: "enable <feature>",
|
||||||
|
Short: "Enable a feature for a namespace",
|
||||||
|
Long: "Enable a feature for a namespace. Supported features: webrtc",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
ns, _ := cmd.Flags().GetString("namespace")
|
||||||
|
cliArgs := []string{"enable", args[0]}
|
||||||
|
if ns != "" {
|
||||||
|
cliArgs = append(cliArgs, "--namespace", ns)
|
||||||
|
}
|
||||||
|
cli.HandleNamespaceCommand(cliArgs)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var disableCmd = &cobra.Command{
|
||||||
|
Use: "disable <feature>",
|
||||||
|
Short: "Disable a feature for a namespace",
|
||||||
|
Long: "Disable a feature for a namespace. Supported features: webrtc",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
ns, _ := cmd.Flags().GetString("namespace")
|
||||||
|
cliArgs := []string{"disable", args[0]}
|
||||||
|
if ns != "" {
|
||||||
|
cliArgs = append(cliArgs, "--namespace", ns)
|
||||||
|
}
|
||||||
|
cli.HandleNamespaceCommand(cliArgs)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var webrtcStatusCmd = &cobra.Command{
|
||||||
|
Use: "webrtc-status",
|
||||||
|
Short: "Show WebRTC service status for a namespace",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
ns, _ := cmd.Flags().GetString("namespace")
|
||||||
|
cliArgs := []string{"webrtc-status"}
|
||||||
|
if ns != "" {
|
||||||
|
cliArgs = append(cliArgs, "--namespace", ns)
|
||||||
|
}
|
||||||
|
cli.HandleNamespaceCommand(cliArgs)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
deleteCmd.Flags().Bool("force", false, "Skip confirmation prompt")
|
deleteCmd.Flags().Bool("force", false, "Skip confirmation prompt")
|
||||||
|
enableCmd.Flags().String("namespace", "", "Namespace name")
|
||||||
|
disableCmd.Flags().String("namespace", "", "Namespace name")
|
||||||
|
webrtcStatusCmd.Flags().String("namespace", "", "Namespace name")
|
||||||
|
|
||||||
Cmd.AddCommand(listCmd)
|
Cmd.AddCommand(listCmd)
|
||||||
Cmd.AddCommand(deleteCmd)
|
Cmd.AddCommand(deleteCmd)
|
||||||
Cmd.AddCommand(repairCmd)
|
Cmd.AddCommand(repairCmd)
|
||||||
|
Cmd.AddCommand(enableCmd)
|
||||||
|
Cmd.AddCommand(disableCmd)
|
||||||
|
Cmd.AddCommand(webrtcStatusCmd)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -241,21 +241,27 @@ func handleNamespaceEnable(args []string) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gatewayURL, apiKey := loadAuthForNamespace(ns)
|
||||||
|
|
||||||
fmt.Printf("Enabling WebRTC for namespace '%s'...\n", ns)
|
fmt.Printf("Enabling WebRTC for namespace '%s'...\n", ns)
|
||||||
fmt.Printf("This will provision SFU (3 nodes) and TURN (2 nodes) services.\n")
|
fmt.Printf("This will provision SFU (3 nodes) and TURN (2 nodes) services.\n")
|
||||||
|
|
||||||
url := fmt.Sprintf("http://localhost:%d/v1/internal/namespace/webrtc/enable?namespace=%s", constants.GatewayAPIPort, ns)
|
url := fmt.Sprintf("%s/v1/namespace/webrtc/enable", gatewayURL)
|
||||||
req, err := http.NewRequest(http.MethodPost, url, nil)
|
req, err := http.NewRequest(http.MethodPost, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
req.Header.Set("X-Orama-Internal-Auth", "namespace-coordination")
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Failed to connect to local gateway (is the node running?): %v\n", err)
|
fmt.Fprintf(os.Stderr, "Failed to connect to gateway: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -294,20 +300,26 @@ func handleNamespaceDisable(args []string) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gatewayURL, apiKey := loadAuthForNamespace(ns)
|
||||||
|
|
||||||
fmt.Printf("Disabling WebRTC for namespace '%s'...\n", ns)
|
fmt.Printf("Disabling WebRTC for namespace '%s'...\n", ns)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://localhost:%d/v1/internal/namespace/webrtc/disable?namespace=%s", constants.GatewayAPIPort, ns)
|
url := fmt.Sprintf("%s/v1/namespace/webrtc/disable", gatewayURL)
|
||||||
req, err := http.NewRequest(http.MethodPost, url, nil)
|
req, err := http.NewRequest(http.MethodPost, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
req.Header.Set("X-Orama-Internal-Auth", "namespace-coordination")
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Failed to connect to local gateway (is the node running?): %v\n", err)
|
fmt.Fprintf(os.Stderr, "Failed to connect to gateway: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -329,18 +341,24 @@ func handleNamespaceDisable(args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleNamespaceWebRTCStatus(ns string) {
|
func handleNamespaceWebRTCStatus(ns string) {
|
||||||
url := fmt.Sprintf("http://localhost:%d/v1/internal/namespace/webrtc/status?namespace=%s", constants.GatewayAPIPort, ns)
|
gatewayURL, apiKey := loadAuthForNamespace(ns)
|
||||||
|
|
||||||
|
url := fmt.Sprintf("%s/v1/namespace/webrtc/status", gatewayURL)
|
||||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
req.Header.Set("X-Orama-Internal-Auth", "namespace-coordination")
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Failed to connect to local gateway (is the node running?): %v\n", err)
|
fmt.Fprintf(os.Stderr, "Failed to connect to gateway: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -383,6 +401,26 @@ func handleNamespaceWebRTCStatus(ns string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadAuthForNamespace loads credentials and returns the gateway URL and API key.
|
||||||
|
// Exits with an error message if not authenticated.
|
||||||
|
func loadAuthForNamespace(ns string) (gatewayURL, apiKey string) {
|
||||||
|
store, err := auth.LoadEnhancedCredentials()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to load credentials: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
gatewayURL = getGatewayURL()
|
||||||
|
creds := store.GetDefaultCredential(gatewayURL)
|
||||||
|
|
||||||
|
if creds == nil || !creds.IsValid() {
|
||||||
|
fmt.Fprintf(os.Stderr, "Not authenticated. Run 'orama auth login' first.\n")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return gatewayURL, creds.APIKey
|
||||||
|
}
|
||||||
|
|
||||||
func handleNamespaceList() {
|
func handleNamespaceList() {
|
||||||
// Load credentials
|
// Load credentials
|
||||||
store, err := auth.LoadEnhancedCredentials()
|
store, err := auth.LoadEnhancedCredentials()
|
||||||
|
|||||||
@ -871,6 +871,109 @@ func (g *Gateway) namespaceClusterRepairHandler(w http.ResponseWriter, r *http.R
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// namespaceWebRTCEnablePublicHandler handles POST /v1/namespace/webrtc/enable
|
||||||
|
// Public: authenticated by JWT/API key via auth middleware. Namespace from context.
|
||||||
|
func (g *Gateway) namespaceWebRTCEnablePublicHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaceName, _ := r.Context().Value(CtxKeyNamespaceOverride).(string)
|
||||||
|
if namespaceName == "" {
|
||||||
|
writeError(w, http.StatusForbidden, "namespace not resolved")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.webrtcManager == nil {
|
||||||
|
writeError(w, http.StatusServiceUnavailable, "WebRTC management not enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.webrtcManager.EnableWebRTC(r.Context(), namespaceName, "api"); err != nil {
|
||||||
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"status": "ok",
|
||||||
|
"namespace": namespaceName,
|
||||||
|
"message": "WebRTC enabled successfully",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// namespaceWebRTCDisablePublicHandler handles POST /v1/namespace/webrtc/disable
|
||||||
|
// Public: authenticated by JWT/API key via auth middleware. Namespace from context.
|
||||||
|
func (g *Gateway) namespaceWebRTCDisablePublicHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaceName, _ := r.Context().Value(CtxKeyNamespaceOverride).(string)
|
||||||
|
if namespaceName == "" {
|
||||||
|
writeError(w, http.StatusForbidden, "namespace not resolved")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.webrtcManager == nil {
|
||||||
|
writeError(w, http.StatusServiceUnavailable, "WebRTC management not enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.webrtcManager.DisableWebRTC(r.Context(), namespaceName); err != nil {
|
||||||
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"status": "ok",
|
||||||
|
"namespace": namespaceName,
|
||||||
|
"message": "WebRTC disabled successfully",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// namespaceWebRTCStatusPublicHandler handles GET /v1/namespace/webrtc/status
|
||||||
|
// Public: authenticated by JWT/API key via auth middleware. Namespace from context.
|
||||||
|
func (g *Gateway) namespaceWebRTCStatusPublicHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaceName, _ := r.Context().Value(CtxKeyNamespaceOverride).(string)
|
||||||
|
if namespaceName == "" {
|
||||||
|
writeError(w, http.StatusForbidden, "namespace not resolved")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.webrtcManager == nil {
|
||||||
|
writeError(w, http.StatusServiceUnavailable, "WebRTC management not enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := g.webrtcManager.GetWebRTCStatus(r.Context(), namespaceName)
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
if config == nil {
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"namespace": namespaceName,
|
||||||
|
"enabled": false,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
json.NewEncoder(w).Encode(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// namespaceWebRTCEnableHandler handles POST /v1/internal/namespace/webrtc/enable?namespace={name}
|
// namespaceWebRTCEnableHandler handles POST /v1/internal/namespace/webrtc/enable?namespace={name}
|
||||||
// Internal-only: authenticated by X-Orama-Internal-Auth header + WireGuard subnet.
|
// Internal-only: authenticated by X-Orama-Internal-Auth header + WireGuard subnet.
|
||||||
func (g *Gateway) namespaceWebRTCEnableHandler(w http.ResponseWriter, r *http.Request) {
|
func (g *Gateway) namespaceWebRTCEnableHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@ -52,6 +52,11 @@ func (g *Gateway) Routes() http.Handler {
|
|||||||
mux.HandleFunc("/v1/internal/namespace/webrtc/disable", g.namespaceWebRTCDisableHandler)
|
mux.HandleFunc("/v1/internal/namespace/webrtc/disable", g.namespaceWebRTCDisableHandler)
|
||||||
mux.HandleFunc("/v1/internal/namespace/webrtc/status", g.namespaceWebRTCStatusHandler)
|
mux.HandleFunc("/v1/internal/namespace/webrtc/status", g.namespaceWebRTCStatusHandler)
|
||||||
|
|
||||||
|
// Namespace WebRTC enable/disable/status (public, JWT/API key auth via middleware)
|
||||||
|
mux.HandleFunc("/v1/namespace/webrtc/enable", g.namespaceWebRTCEnablePublicHandler)
|
||||||
|
mux.HandleFunc("/v1/namespace/webrtc/disable", g.namespaceWebRTCDisablePublicHandler)
|
||||||
|
mux.HandleFunc("/v1/namespace/webrtc/status", g.namespaceWebRTCStatusPublicHandler)
|
||||||
|
|
||||||
// auth endpoints
|
// auth endpoints
|
||||||
mux.HandleFunc("/v1/auth/jwks", g.authService.JWKSHandler)
|
mux.HandleFunc("/v1/auth/jwks", g.authService.JWKSHandler)
|
||||||
mux.HandleFunc("/.well-known/jwks.json", g.authService.JWKSHandler)
|
mux.HandleFunc("/.well-known/jwks.json", g.authService.JWKSHandler)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user