Add gated fabric session websocket endpoint
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/authority"
|
||||
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/fabricproto"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
@@ -26,6 +27,7 @@ type ProductionEnvelopeObserver func(context.Context, ProductionEnvelopeObservat
|
||||
type ProductionEnvelopeDelivery func(context.Context, ProductionEnvelope) error
|
||||
type ProductionForwardLogger func(ProductionForwardLogEntry)
|
||||
type FabricServiceChannelAccessLogger func(FabricServiceChannelAccessLogEntry)
|
||||
type FabricSessionEventLogger func(FabricSessionEventLogEntry)
|
||||
type RemoteWorkspaceFrameSink interface {
|
||||
AcceptRemoteWorkspaceFrameBatchProbe(context.Context, RemoteWorkspaceFrameBatchDelivery) (RemoteWorkspaceFrameBatchDeliveryReceipt, error)
|
||||
}
|
||||
@@ -81,6 +83,8 @@ type Server struct {
|
||||
BackendProxyBaseURL string
|
||||
ClusterAuthorityPublicKey string
|
||||
ServiceChannelIntrospection bool
|
||||
FabricSessionEnabled bool
|
||||
FabricSessionLogger FabricSessionEventLogger
|
||||
}
|
||||
|
||||
func (s Server) Handler() http.Handler {
|
||||
@@ -88,6 +92,9 @@ func (s Server) Handler() http.Handler {
|
||||
mux.HandleFunc("/mesh/v1/health", s.handleHealth)
|
||||
mux.HandleFunc("/mesh/v1/forward", s.handleForward)
|
||||
mux.HandleFunc("/mesh/v1/synthetic/probe", s.handleSyntheticProbe)
|
||||
if s.FabricSessionEnabled {
|
||||
mux.HandleFunc("/mesh/v1/fabric/session/ws", s.handleFabricSessionWebSocket)
|
||||
}
|
||||
if s.RemoteWorkspaceFrameSink != nil {
|
||||
mux.HandleFunc("/mesh/v1/remote-workspace/adapter-sessions/", s.handleRemoteWorkspaceAdapterSessionControl)
|
||||
}
|
||||
@@ -187,6 +194,84 @@ func (s Server) handleRemoteWorkspaceAdapterSessionSnapshot(w http.ResponseWrite
|
||||
_ = json.NewEncoder(w).Encode(snapshotter.SnapshotAdapterSessions(includeTerminal, limit, time.Now().UTC()))
|
||||
}
|
||||
|
||||
type FabricSessionEventLogEntry struct {
|
||||
Event string `json:"event"`
|
||||
ClusterID string `json:"cluster_id,omitempty"`
|
||||
NodeID string `json:"node_id,omitempty"`
|
||||
SessionEvent fabricproto.SessionEventType `json:"session_event,omitempty"`
|
||||
StreamID uint64 `json:"stream_id,omitempty"`
|
||||
Sequence uint64 `json:"sequence,omitempty"`
|
||||
TrafficClass fabricproto.TrafficClass `json:"traffic_class,omitempty"`
|
||||
RemoteAddr string `json:"remote_addr,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
ObservedAt time.Time `json:"observed_at"`
|
||||
}
|
||||
|
||||
func (s Server) handleFabricSessionWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
upgrader := websocket.Upgrader{
|
||||
CheckOrigin: func(_ *http.Request) bool { return true },
|
||||
}
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
s.logFabricSession(FabricSessionEventLogEntry{
|
||||
Event: "fabric_session_websocket_opened",
|
||||
ClusterID: s.Local.ClusterID,
|
||||
NodeID: s.Local.NodeID,
|
||||
RemoteAddr: r.RemoteAddr,
|
||||
ObservedAt: time.Now().UTC(),
|
||||
})
|
||||
loop := fabricproto.TransportLoop{
|
||||
Session: fabricproto.NewSession(fabricproto.SessionConfig{}),
|
||||
OnEvent: func(event fabricproto.SessionEvent) ([]fabricproto.Frame, error) {
|
||||
s.logFabricSession(FabricSessionEventLogEntry{
|
||||
Event: "fabric_session_event",
|
||||
ClusterID: s.Local.ClusterID,
|
||||
NodeID: s.Local.NodeID,
|
||||
SessionEvent: event.Type,
|
||||
StreamID: event.StreamID,
|
||||
Sequence: event.Sequence,
|
||||
TrafficClass: event.TrafficClass,
|
||||
RemoteAddr: r.RemoteAddr,
|
||||
ObservedAt: time.Now().UTC(),
|
||||
})
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
err = loop.RunWebSocket(r.Context(), conn, fabricproto.WebSocketTransportConfig{})
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
s.logFabricSession(FabricSessionEventLogEntry{
|
||||
Event: "fabric_session_websocket_closed",
|
||||
ClusterID: s.Local.ClusterID,
|
||||
NodeID: s.Local.NodeID,
|
||||
RemoteAddr: r.RemoteAddr,
|
||||
Reason: err.Error(),
|
||||
ObservedAt: time.Now().UTC(),
|
||||
})
|
||||
return
|
||||
}
|
||||
s.logFabricSession(FabricSessionEventLogEntry{
|
||||
Event: "fabric_session_websocket_closed",
|
||||
ClusterID: s.Local.ClusterID,
|
||||
NodeID: s.Local.NodeID,
|
||||
RemoteAddr: r.RemoteAddr,
|
||||
ObservedAt: time.Now().UTC(),
|
||||
})
|
||||
}
|
||||
|
||||
func (s Server) logFabricSession(entry FabricSessionEventLogEntry) {
|
||||
if s.FabricSessionLogger != nil {
|
||||
s.FabricSessionLogger(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (s Server) handleRemoteWorkspaceAdapterSessionMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
reader, ok := s.RemoteWorkspaceFrameSink.(RemoteWorkspaceFrameSinkSessionMailbox)
|
||||
if !ok {
|
||||
|
||||
Reference in New Issue
Block a user