mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 03:13:00 +00:00
feat: add WebRTC configuration support for gateway instances
This commit is contained in:
parent
552fde428e
commit
3597c61cfc
1
.gitignore
vendored
1
.gitignore
vendored
@ -93,3 +93,4 @@ terms-agreement
|
||||
./cli
|
||||
./inspector
|
||||
docs/later_todos/
|
||||
sim/
|
||||
@ -48,6 +48,11 @@ type SpawnRequest struct {
|
||||
IPFSAPIURL string `json:"ipfs_api_url,omitempty"`
|
||||
IPFSTimeout string `json:"ipfs_timeout,omitempty"`
|
||||
IPFSReplicationFactor int `json:"ipfs_replication_factor,omitempty"`
|
||||
// Gateway WebRTC config (when action = "spawn-gateway" and WebRTC is enabled)
|
||||
GatewayWebRTCEnabled bool `json:"gateway_webrtc_enabled,omitempty"`
|
||||
GatewaySFUPort int `json:"gateway_sfu_port,omitempty"`
|
||||
GatewayTURNDomain string `json:"gateway_turn_domain,omitempty"`
|
||||
GatewayTURNSecret string `json:"gateway_turn_secret,omitempty"`
|
||||
|
||||
// SFU config (when action = "spawn-sfu")
|
||||
SFUListenAddr string `json:"sfu_listen_addr,omitempty"`
|
||||
@ -225,6 +230,10 @@ func (h *SpawnHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
IPFSAPIURL: req.IPFSAPIURL,
|
||||
IPFSTimeout: ipfsTimeout,
|
||||
IPFSReplicationFactor: req.IPFSReplicationFactor,
|
||||
WebRTCEnabled: req.GatewayWebRTCEnabled,
|
||||
SFUPort: req.GatewaySFUPort,
|
||||
TURNDomain: req.GatewayTURNDomain,
|
||||
TURNSecret: req.GatewayTURNSecret,
|
||||
}
|
||||
if err := h.systemdSpawner.SpawnGateway(ctx, req.Namespace, req.NodeID, cfg); err != nil {
|
||||
h.logger.Error("Failed to spawn Gateway instance", zap.Error(err))
|
||||
@ -241,6 +250,51 @@ func (h *SpawnHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
writeSpawnResponse(w, http.StatusOK, SpawnResponse{Success: true})
|
||||
|
||||
case "restart-gateway":
|
||||
// Restart gateway with updated config (used by EnableWebRTC/DisableWebRTC)
|
||||
var ipfsTimeout time.Duration
|
||||
if req.IPFSTimeout != "" {
|
||||
var err error
|
||||
ipfsTimeout, err = time.ParseDuration(req.IPFSTimeout)
|
||||
if err != nil {
|
||||
ipfsTimeout = 60 * time.Second
|
||||
}
|
||||
}
|
||||
var olricTimeout time.Duration
|
||||
if req.GatewayOlricTimeout != "" {
|
||||
var err error
|
||||
olricTimeout, err = time.ParseDuration(req.GatewayOlricTimeout)
|
||||
if err != nil {
|
||||
olricTimeout = 30 * time.Second
|
||||
}
|
||||
} else {
|
||||
olricTimeout = 30 * time.Second
|
||||
}
|
||||
cfg := gateway.InstanceConfig{
|
||||
Namespace: req.Namespace,
|
||||
NodeID: req.NodeID,
|
||||
HTTPPort: req.GatewayHTTPPort,
|
||||
BaseDomain: req.GatewayBaseDomain,
|
||||
RQLiteDSN: req.GatewayRQLiteDSN,
|
||||
GlobalRQLiteDSN: req.GatewayGlobalRQLiteDSN,
|
||||
OlricServers: req.GatewayOlricServers,
|
||||
OlricTimeout: olricTimeout,
|
||||
IPFSClusterAPIURL: req.IPFSClusterAPIURL,
|
||||
IPFSAPIURL: req.IPFSAPIURL,
|
||||
IPFSTimeout: ipfsTimeout,
|
||||
IPFSReplicationFactor: req.IPFSReplicationFactor,
|
||||
WebRTCEnabled: req.GatewayWebRTCEnabled,
|
||||
SFUPort: req.GatewaySFUPort,
|
||||
TURNDomain: req.GatewayTURNDomain,
|
||||
TURNSecret: req.GatewayTURNSecret,
|
||||
}
|
||||
if err := h.systemdSpawner.RestartGateway(ctx, req.Namespace, req.NodeID, cfg); err != nil {
|
||||
h.logger.Error("Failed to restart Gateway instance", zap.Error(err))
|
||||
writeSpawnResponse(w, http.StatusInternalServerError, SpawnResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
writeSpawnResponse(w, http.StatusOK, SpawnResponse{Success: true})
|
||||
|
||||
case "save-cluster-state":
|
||||
if len(req.ClusterState) == 0 {
|
||||
writeSpawnResponse(w, http.StatusBadRequest, SpawnResponse{Error: "cluster_state is required"})
|
||||
|
||||
@ -90,26 +90,41 @@ type InstanceConfig struct {
|
||||
IPFSAPIURL string // IPFS API URL (e.g., "http://localhost:5001")
|
||||
IPFSTimeout time.Duration // Timeout for IPFS operations
|
||||
IPFSReplicationFactor int // IPFS replication factor
|
||||
// WebRTC configuration (populated when WebRTC is enabled for the namespace)
|
||||
WebRTCEnabled bool // Enable WebRTC (SFU/TURN) routes on this gateway
|
||||
SFUPort int // SFU signaling port on this node
|
||||
TURNDomain string // TURN server domain (e.g., "turn.ns-alice.orama-devnet.network")
|
||||
TURNSecret string // TURN shared secret for credential generation
|
||||
}
|
||||
|
||||
// GatewayYAMLWebRTC represents the webrtc section of the gateway YAML config.
|
||||
// Must match yamlWebRTCCfg in cmd/gateway/config.go.
|
||||
type GatewayYAMLWebRTC struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
SFUPort int `yaml:"sfu_port,omitempty"`
|
||||
TURNDomain string `yaml:"turn_domain,omitempty"`
|
||||
TURNSecret string `yaml:"turn_secret,omitempty"`
|
||||
}
|
||||
|
||||
// GatewayYAMLConfig represents the gateway YAML configuration structure
|
||||
// This must match the yamlCfg struct in cmd/gateway/config.go exactly
|
||||
// because the gateway uses strict YAML decoding that rejects unknown fields
|
||||
type GatewayYAMLConfig struct {
|
||||
ListenAddr string `yaml:"listen_addr"`
|
||||
ClientNamespace string `yaml:"client_namespace"`
|
||||
RQLiteDSN string `yaml:"rqlite_dsn"`
|
||||
GlobalRQLiteDSN string `yaml:"global_rqlite_dsn,omitempty"`
|
||||
BootstrapPeers []string `yaml:"bootstrap_peers,omitempty"`
|
||||
EnableHTTPS bool `yaml:"enable_https,omitempty"`
|
||||
DomainName string `yaml:"domain_name,omitempty"`
|
||||
TLSCacheDir string `yaml:"tls_cache_dir,omitempty"`
|
||||
OlricServers []string `yaml:"olric_servers"`
|
||||
OlricTimeout string `yaml:"olric_timeout,omitempty"`
|
||||
IPFSClusterAPIURL string `yaml:"ipfs_cluster_api_url,omitempty"`
|
||||
IPFSAPIURL string `yaml:"ipfs_api_url,omitempty"`
|
||||
IPFSTimeout string `yaml:"ipfs_timeout,omitempty"`
|
||||
IPFSReplicationFactor int `yaml:"ipfs_replication_factor,omitempty"`
|
||||
ListenAddr string `yaml:"listen_addr"`
|
||||
ClientNamespace string `yaml:"client_namespace"`
|
||||
RQLiteDSN string `yaml:"rqlite_dsn"`
|
||||
GlobalRQLiteDSN string `yaml:"global_rqlite_dsn,omitempty"`
|
||||
BootstrapPeers []string `yaml:"bootstrap_peers,omitempty"`
|
||||
EnableHTTPS bool `yaml:"enable_https,omitempty"`
|
||||
DomainName string `yaml:"domain_name,omitempty"`
|
||||
TLSCacheDir string `yaml:"tls_cache_dir,omitempty"`
|
||||
OlricServers []string `yaml:"olric_servers"`
|
||||
OlricTimeout string `yaml:"olric_timeout,omitempty"`
|
||||
IPFSClusterAPIURL string `yaml:"ipfs_cluster_api_url,omitempty"`
|
||||
IPFSAPIURL string `yaml:"ipfs_api_url,omitempty"`
|
||||
IPFSTimeout string `yaml:"ipfs_timeout,omitempty"`
|
||||
IPFSReplicationFactor int `yaml:"ipfs_replication_factor,omitempty"`
|
||||
WebRTC GatewayYAMLWebRTC `yaml:"webrtc,omitempty"`
|
||||
}
|
||||
|
||||
// NewInstanceSpawner creates a new Gateway instance spawner
|
||||
@ -294,6 +309,12 @@ func (is *InstanceSpawner) generateConfig(configPath string, cfg InstanceConfig,
|
||||
IPFSClusterAPIURL: cfg.IPFSClusterAPIURL,
|
||||
IPFSAPIURL: cfg.IPFSAPIURL,
|
||||
IPFSReplicationFactor: cfg.IPFSReplicationFactor,
|
||||
WebRTC: GatewayYAMLWebRTC{
|
||||
Enabled: cfg.WebRTCEnabled,
|
||||
SFUPort: cfg.SFUPort,
|
||||
TURNDomain: cfg.TURNDomain,
|
||||
TURNSecret: cfg.TURNSecret,
|
||||
},
|
||||
}
|
||||
// Set Olric timeout if provided
|
||||
if cfg.OlricTimeout > 0 {
|
||||
|
||||
@ -661,6 +661,10 @@ func (cm *ClusterManager) spawnGatewayRemote(ctx context.Context, nodeIP string,
|
||||
"ipfs_api_url": cfg.IPFSAPIURL,
|
||||
"ipfs_timeout": ipfsTimeout,
|
||||
"ipfs_replication_factor": cfg.IPFSReplicationFactor,
|
||||
"gateway_webrtc_enabled": cfg.WebRTCEnabled,
|
||||
"gateway_sfu_port": cfg.SFUPort,
|
||||
"gateway_turn_domain": cfg.TURNDomain,
|
||||
"gateway_turn_secret": cfg.TURNSecret,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1555,6 +1559,16 @@ func (cm *ClusterManager) restoreClusterOnNode(ctx context.Context, clusterID, n
|
||||
IPFSReplicationFactor: cm.ipfsReplicationFactor,
|
||||
}
|
||||
|
||||
// Add WebRTC config if enabled for this namespace
|
||||
if webrtcCfg, err := cm.GetWebRTCConfig(ctx, namespaceName); err == nil && webrtcCfg != nil {
|
||||
if sfuBlock, err := cm.webrtcPortAllocator.GetSFUPorts(ctx, clusterID, cm.localNodeID); err == nil && sfuBlock != nil {
|
||||
gwCfg.WebRTCEnabled = true
|
||||
gwCfg.SFUPort = sfuBlock.SFUSignalingPort
|
||||
gwCfg.TURNDomain = fmt.Sprintf("turn.ns-%s.%s", namespaceName, cm.baseDomain)
|
||||
gwCfg.TURNSecret = webrtcCfg.TURNSharedSecret
|
||||
}
|
||||
}
|
||||
|
||||
if err := cm.spawnGatewayWithSystemd(ctx, gwCfg); err != nil {
|
||||
cm.logger.Error("Failed to restore Gateway", zap.String("namespace", namespaceName), zap.Error(err))
|
||||
} else {
|
||||
@ -1617,7 +1631,8 @@ type ClusterLocalState struct {
|
||||
// WebRTC fields (zero values when WebRTC not enabled — backward compatible)
|
||||
HasSFU bool `json:"has_sfu,omitempty"`
|
||||
HasTURN bool `json:"has_turn,omitempty"`
|
||||
TURNSharedSecret string `json:"-"` // Never persisted to disk state file
|
||||
TURNSharedSecret string `json:"turn_shared_secret,omitempty"` // Needed for gateway to generate TURN credentials on cold start
|
||||
TURNDomain string `json:"turn_domain,omitempty"` // TURN server domain for gateway config
|
||||
TURNCredentialTTL int `json:"turn_credential_ttl,omitempty"`
|
||||
SFUSignalingPort int `json:"sfu_signaling_port,omitempty"`
|
||||
SFUMediaPortStart int `json:"sfu_media_port_start,omitempty"`
|
||||
@ -1915,6 +1930,15 @@ func (cm *ClusterManager) restoreClusterFromState(ctx context.Context, state *Cl
|
||||
IPFSTimeout: cm.ipfsTimeout,
|
||||
IPFSReplicationFactor: cm.ipfsReplicationFactor,
|
||||
}
|
||||
|
||||
// Add WebRTC config from persisted local state
|
||||
if state.HasSFU && state.SFUSignalingPort > 0 && state.TURNSharedSecret != "" {
|
||||
gwCfg.WebRTCEnabled = true
|
||||
gwCfg.SFUPort = state.SFUSignalingPort
|
||||
gwCfg.TURNDomain = state.TURNDomain
|
||||
gwCfg.TURNSecret = state.TURNSharedSecret
|
||||
}
|
||||
|
||||
if err := cm.spawnGatewayWithSystemd(ctx, gwCfg); err != nil {
|
||||
cm.logger.Error("Failed to restore Gateway from state", zap.String("namespace", state.NamespaceName), zap.Error(err))
|
||||
} else {
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/DeBrosOfficial/network/pkg/client"
|
||||
"github.com/DeBrosOfficial/network/pkg/gateway"
|
||||
"github.com/DeBrosOfficial/network/pkg/sfu"
|
||||
"github.com/google/uuid"
|
||||
"go.uber.org/zap"
|
||||
@ -189,7 +190,10 @@ func (cm *ClusterManager) EnableWebRTC(ctx context.Context, namespaceName, enabl
|
||||
}
|
||||
|
||||
// 14. Update cluster-state.json on all nodes with WebRTC info
|
||||
cm.updateClusterStateWithWebRTC(ctx, cluster, clusterNodes, sfuBlocks, turnBlocks)
|
||||
cm.updateClusterStateWithWebRTC(ctx, cluster, clusterNodes, sfuBlocks, turnBlocks, turnDomain, turnSecret)
|
||||
|
||||
// 15. Restart namespace gateways with WebRTC config so they register WebRTC routes
|
||||
cm.restartGatewaysWithWebRTC(ctx, cluster, clusterNodes, nodePortBlocks, sfuBlocks, turnDomain, turnSecret)
|
||||
|
||||
cm.logEvent(ctx, cluster.ID, EventWebRTCEnabled, "",
|
||||
fmt.Sprintf("WebRTC enabled: SFU on %d nodes, TURN on %d nodes", len(clusterNodes), len(turnNodes)), nil)
|
||||
@ -265,7 +269,19 @@ func (cm *ClusterManager) DisableWebRTC(ctx context.Context, namespaceName strin
|
||||
cm.db.Exec(internalCtx, `DELETE FROM namespace_webrtc_config WHERE namespace_cluster_id = ?`, cluster.ID)
|
||||
|
||||
// 9. Update cluster-state.json to remove WebRTC info
|
||||
cm.updateClusterStateWithWebRTC(ctx, cluster, clusterNodes, nil, nil)
|
||||
cm.updateClusterStateWithWebRTC(ctx, cluster, clusterNodes, nil, nil, "", "")
|
||||
|
||||
// 10. Restart namespace gateways without WebRTC config so they unregister WebRTC routes
|
||||
portBlocks, err := cm.portAllocator.GetAllPortBlocks(ctx, cluster.ID)
|
||||
if err == nil {
|
||||
nodePortBlocks := make(map[string]*PortBlock)
|
||||
for i := range portBlocks {
|
||||
nodePortBlocks[portBlocks[i].NodeID] = &portBlocks[i]
|
||||
}
|
||||
cm.restartGatewaysWithWebRTC(ctx, cluster, clusterNodes, nodePortBlocks, nil, "", "")
|
||||
} else {
|
||||
cm.logger.Warn("Failed to get port blocks for gateway restart after WebRTC disable", zap.Error(err))
|
||||
}
|
||||
|
||||
cm.logEvent(ctx, cluster.ID, EventWebRTCDisabled, "", "WebRTC disabled", nil)
|
||||
|
||||
@ -508,13 +524,14 @@ func (cm *ClusterManager) cleanupWebRTCOnError(ctx context.Context, clusterID, n
|
||||
|
||||
// updateClusterStateWithWebRTC updates the cluster-state.json on all nodes
|
||||
// to include (or remove) WebRTC port information.
|
||||
// Pass nil maps to clear WebRTC state (when disabling).
|
||||
// Pass nil maps and empty strings to clear WebRTC state (when disabling).
|
||||
func (cm *ClusterManager) updateClusterStateWithWebRTC(
|
||||
ctx context.Context,
|
||||
cluster *NamespaceCluster,
|
||||
nodes []clusterNodeInfo,
|
||||
sfuBlocks map[string]*WebRTCPortBlock,
|
||||
turnBlocks map[string]*WebRTCPortBlock,
|
||||
turnDomain, turnSecret string,
|
||||
) {
|
||||
// Get existing port blocks for base state
|
||||
portBlocks, err := cm.portAllocator.GetAllPortBlocks(ctx, cluster.ID)
|
||||
@ -589,6 +606,9 @@ func (cm *ClusterManager) updateClusterStateWithWebRTC(
|
||||
state.TURNRelayPortEnd = turnBlock.TURNRelayPortEnd
|
||||
}
|
||||
}
|
||||
// Persist TURN domain and secret so gateways can be restored on cold start
|
||||
state.TURNDomain = turnDomain
|
||||
state.TURNSharedSecret = turnSecret
|
||||
|
||||
if node.NodeID == cm.localNodeID {
|
||||
if err := cm.saveLocalState(state); err != nil {
|
||||
@ -615,3 +635,118 @@ func (cm *ClusterManager) saveRemoteState(ctx context.Context, nodeIP, namespace
|
||||
zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// restartGatewaysWithWebRTC restarts namespace gateways on all nodes with updated WebRTC config.
|
||||
// Pass nil sfuBlocks and empty turnDomain/turnSecret to disable WebRTC on gateways.
|
||||
func (cm *ClusterManager) restartGatewaysWithWebRTC(
|
||||
ctx context.Context,
|
||||
cluster *NamespaceCluster,
|
||||
nodes []clusterNodeInfo,
|
||||
portBlocks map[string]*PortBlock,
|
||||
sfuBlocks map[string]*WebRTCPortBlock,
|
||||
turnDomain, turnSecret string,
|
||||
) {
|
||||
// Build Olric server addresses from port blocks + node IPs
|
||||
var olricServers []string
|
||||
for _, node := range nodes {
|
||||
if pb, ok := portBlocks[node.NodeID]; ok {
|
||||
olricServers = append(olricServers, fmt.Sprintf("%s:%d", node.InternalIP, pb.OlricHTTPPort))
|
||||
}
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
pb, ok := portBlocks[node.NodeID]
|
||||
if !ok {
|
||||
cm.logger.Warn("No port block for node, skipping gateway restart",
|
||||
zap.String("node_id", node.NodeID))
|
||||
continue
|
||||
}
|
||||
|
||||
// Build gateway config with WebRTC fields
|
||||
webrtcEnabled := false
|
||||
sfuPort := 0
|
||||
if sfuBlocks != nil {
|
||||
if sfuBlock, ok := sfuBlocks[node.NodeID]; ok {
|
||||
webrtcEnabled = true
|
||||
sfuPort = sfuBlock.SFUSignalingPort
|
||||
}
|
||||
}
|
||||
|
||||
cfg := gateway.InstanceConfig{
|
||||
Namespace: cluster.NamespaceName,
|
||||
NodeID: node.NodeID,
|
||||
HTTPPort: pb.GatewayHTTPPort,
|
||||
BaseDomain: cm.baseDomain,
|
||||
RQLiteDSN: fmt.Sprintf("http://localhost:%d", pb.RQLiteHTTPPort),
|
||||
GlobalRQLiteDSN: cm.globalRQLiteDSN,
|
||||
OlricServers: olricServers,
|
||||
OlricTimeout: 30 * time.Second,
|
||||
IPFSClusterAPIURL: cm.ipfsClusterAPIURL,
|
||||
IPFSAPIURL: cm.ipfsAPIURL,
|
||||
IPFSTimeout: cm.ipfsTimeout,
|
||||
IPFSReplicationFactor: cm.ipfsReplicationFactor,
|
||||
WebRTCEnabled: webrtcEnabled,
|
||||
SFUPort: sfuPort,
|
||||
TURNDomain: turnDomain,
|
||||
TURNSecret: turnSecret,
|
||||
}
|
||||
|
||||
if node.NodeID == cm.localNodeID {
|
||||
if err := cm.systemdSpawner.RestartGateway(ctx, cluster.NamespaceName, node.NodeID, cfg); err != nil {
|
||||
cm.logger.Error("Failed to restart local gateway with WebRTC config",
|
||||
zap.String("namespace", cluster.NamespaceName),
|
||||
zap.String("node_id", node.NodeID),
|
||||
zap.Error(err))
|
||||
} else {
|
||||
cm.logger.Info("Restarted local gateway with WebRTC config",
|
||||
zap.String("namespace", cluster.NamespaceName),
|
||||
zap.Bool("webrtc_enabled", webrtcEnabled))
|
||||
}
|
||||
} else {
|
||||
cm.restartGatewayRemote(ctx, node.InternalIP, cfg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restartGatewayRemote sends a restart-gateway request to a remote node.
|
||||
func (cm *ClusterManager) restartGatewayRemote(ctx context.Context, nodeIP string, cfg gateway.InstanceConfig) {
|
||||
ipfsTimeout := ""
|
||||
if cfg.IPFSTimeout > 0 {
|
||||
ipfsTimeout = cfg.IPFSTimeout.String()
|
||||
}
|
||||
olricTimeout := ""
|
||||
if cfg.OlricTimeout > 0 {
|
||||
olricTimeout = cfg.OlricTimeout.String()
|
||||
}
|
||||
|
||||
_, err := cm.sendSpawnRequest(ctx, nodeIP, map[string]interface{}{
|
||||
"action": "restart-gateway",
|
||||
"namespace": cfg.Namespace,
|
||||
"node_id": cfg.NodeID,
|
||||
"gateway_http_port": cfg.HTTPPort,
|
||||
"gateway_base_domain": cfg.BaseDomain,
|
||||
"gateway_rqlite_dsn": cfg.RQLiteDSN,
|
||||
"gateway_global_rqlite_dsn": cfg.GlobalRQLiteDSN,
|
||||
"gateway_olric_servers": cfg.OlricServers,
|
||||
"gateway_olric_timeout": olricTimeout,
|
||||
"ipfs_cluster_api_url": cfg.IPFSClusterAPIURL,
|
||||
"ipfs_api_url": cfg.IPFSAPIURL,
|
||||
"ipfs_timeout": ipfsTimeout,
|
||||
"ipfs_replication_factor": cfg.IPFSReplicationFactor,
|
||||
"gateway_webrtc_enabled": cfg.WebRTCEnabled,
|
||||
"gateway_sfu_port": cfg.SFUPort,
|
||||
"gateway_turn_domain": cfg.TURNDomain,
|
||||
"gateway_turn_secret": cfg.TURNSecret,
|
||||
})
|
||||
if err != nil {
|
||||
cm.logger.Error("Failed to restart remote gateway with WebRTC config",
|
||||
zap.String("node_ip", nodeIP),
|
||||
zap.String("namespace", cfg.Namespace),
|
||||
zap.Error(err))
|
||||
} else {
|
||||
cm.logger.Info("Restarted remote gateway with WebRTC config",
|
||||
zap.String("node_ip", nodeIP),
|
||||
zap.String("namespace", cfg.Namespace),
|
||||
zap.Bool("webrtc_enabled", cfg.WebRTCEnabled))
|
||||
}
|
||||
}
|
||||
|
||||
@ -529,6 +529,16 @@ func (cm *ClusterManager) ReplaceClusterNode(ctx context.Context, cluster *Names
|
||||
IPFSReplicationFactor: cm.ipfsReplicationFactor,
|
||||
}
|
||||
|
||||
// Add WebRTC config if enabled for this namespace
|
||||
if webrtcCfg, err := cm.GetWebRTCConfig(ctx, cluster.NamespaceName); err == nil && webrtcCfg != nil {
|
||||
if sfuBlock, err := cm.webrtcPortAllocator.GetSFUPorts(ctx, cluster.ID, replacement.NodeID); err == nil && sfuBlock != nil {
|
||||
gwCfg.WebRTCEnabled = true
|
||||
gwCfg.SFUPort = sfuBlock.SFUSignalingPort
|
||||
gwCfg.TURNDomain = fmt.Sprintf("turn.ns-%s.%s", cluster.NamespaceName, cm.baseDomain)
|
||||
gwCfg.TURNSecret = webrtcCfg.TURNSharedSecret
|
||||
}
|
||||
}
|
||||
|
||||
var spawnErr error
|
||||
if replacement.NodeID == cm.localNodeID {
|
||||
spawnErr = cm.spawnGatewayWithSystemd(ctx, gwCfg)
|
||||
@ -1061,6 +1071,16 @@ func (cm *ClusterManager) addNodeToCluster(
|
||||
IPFSReplicationFactor: cm.ipfsReplicationFactor,
|
||||
}
|
||||
|
||||
// Add WebRTC config if enabled for this namespace
|
||||
if webrtcCfg, err := cm.GetWebRTCConfig(ctx, cluster.NamespaceName); err == nil && webrtcCfg != nil {
|
||||
if sfuBlock, err := cm.webrtcPortAllocator.GetSFUPorts(ctx, cluster.ID, replacement.NodeID); err == nil && sfuBlock != nil {
|
||||
gwCfg.WebRTCEnabled = true
|
||||
gwCfg.SFUPort = sfuBlock.SFUSignalingPort
|
||||
gwCfg.TURNDomain = fmt.Sprintf("turn.ns-%s.%s", cluster.NamespaceName, cm.baseDomain)
|
||||
gwCfg.TURNSecret = webrtcCfg.TURNSharedSecret
|
||||
}
|
||||
}
|
||||
|
||||
if replacement.NodeID == cm.localNodeID {
|
||||
spawnErr = cm.spawnGatewayWithSystemd(ctx, gwCfg)
|
||||
} else {
|
||||
|
||||
@ -195,22 +195,8 @@ func (s *SystemdSpawner) SpawnGateway(ctx context.Context, namespace, nodeID str
|
||||
|
||||
configPath := filepath.Join(configDir, fmt.Sprintf("gateway-%s.yaml", nodeID))
|
||||
|
||||
// Build Gateway YAML config
|
||||
type gatewayYAMLConfig struct {
|
||||
ListenAddr string `yaml:"listen_addr"`
|
||||
ClientNamespace string `yaml:"client_namespace"`
|
||||
RQLiteDSN string `yaml:"rqlite_dsn"`
|
||||
GlobalRQLiteDSN string `yaml:"global_rqlite_dsn,omitempty"`
|
||||
DomainName string `yaml:"domain_name"`
|
||||
OlricServers []string `yaml:"olric_servers"`
|
||||
OlricTimeout string `yaml:"olric_timeout"`
|
||||
IPFSClusterAPIURL string `yaml:"ipfs_cluster_api_url"`
|
||||
IPFSAPIURL string `yaml:"ipfs_api_url"`
|
||||
IPFSTimeout string `yaml:"ipfs_timeout"`
|
||||
IPFSReplicationFactor int `yaml:"ipfs_replication_factor"`
|
||||
}
|
||||
|
||||
gatewayConfig := gatewayYAMLConfig{
|
||||
// Build Gateway YAML config using the shared type from gateway package
|
||||
gatewayConfig := gateway.GatewayYAMLConfig{
|
||||
ListenAddr: fmt.Sprintf(":%d", cfg.HTTPPort),
|
||||
ClientNamespace: cfg.Namespace,
|
||||
RQLiteDSN: cfg.RQLiteDSN,
|
||||
@ -222,6 +208,12 @@ func (s *SystemdSpawner) SpawnGateway(ctx context.Context, namespace, nodeID str
|
||||
IPFSAPIURL: cfg.IPFSAPIURL,
|
||||
IPFSTimeout: cfg.IPFSTimeout.String(),
|
||||
IPFSReplicationFactor: cfg.IPFSReplicationFactor,
|
||||
WebRTC: gateway.GatewayYAMLWebRTC{
|
||||
Enabled: cfg.WebRTCEnabled,
|
||||
SFUPort: cfg.SFUPort,
|
||||
TURNDomain: cfg.TURNDomain,
|
||||
TURNSecret: cfg.TURNSecret,
|
||||
},
|
||||
}
|
||||
|
||||
configBytes, err := yaml.Marshal(gatewayConfig)
|
||||
@ -291,6 +283,24 @@ func (s *SystemdSpawner) StopGateway(ctx context.Context, namespace, nodeID stri
|
||||
return s.systemdMgr.StopService(namespace, systemd.ServiceTypeGateway)
|
||||
}
|
||||
|
||||
// RestartGateway stops and re-spawns a Gateway instance with updated config.
|
||||
// Used when gateway config changes at runtime (e.g., WebRTC enable/disable).
|
||||
func (s *SystemdSpawner) RestartGateway(ctx context.Context, namespace, nodeID string, cfg gateway.InstanceConfig) error {
|
||||
s.logger.Info("Restarting Gateway via systemd",
|
||||
zap.String("namespace", namespace),
|
||||
zap.String("node_id", nodeID))
|
||||
|
||||
// Stop existing service (ignore error if already stopped)
|
||||
if err := s.systemdMgr.StopService(namespace, systemd.ServiceTypeGateway); err != nil {
|
||||
s.logger.Warn("Failed to stop Gateway before restart (may not be running)",
|
||||
zap.String("namespace", namespace),
|
||||
zap.Error(err))
|
||||
}
|
||||
|
||||
// Re-spawn with updated config
|
||||
return s.SpawnGateway(ctx, namespace, nodeID, cfg)
|
||||
}
|
||||
|
||||
// SFUInstanceConfig holds configuration for spawning an SFU instance
|
||||
type SFUInstanceConfig struct {
|
||||
Namespace string
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user