Files
rdp-proxy/agents/rap-node-agent/internal/mesh/fabric_overlay_transport.go
T

131 lines
3.7 KiB
Go

package mesh
import (
"context"
"fmt"
"strings"
"sync/atomic"
"time"
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/fabricproto"
)
type FabricOverlayTransportConfig struct {
ClusterID string
LocalNodeID string
RouterConfig FabricChannelRouterConfig
Timeout time.Duration
}
type FabricOverlayTransport struct {
Runtime *FabricChannelRuntime
RouteSets map[string]FabricRouteSet
Config FabricOverlayTransportConfig
sequence atomic.Uint64
}
type FabricOverlayTransportSnapshot struct {
RoutePressure FabricRoutePressureSnapshot `json:"route_pressure"`
RouteHealth FabricRouteHealthSnapshot `json:"route_health,omitempty"`
}
type FabricOverlaySendRequest struct {
ChannelID string
TargetKind FabricChannelTargetKind
TargetID string
TrafficClass fabricproto.TrafficClass
Payloads [][]byte
StickyKey string
}
func NewFabricOverlayTransport(transport FabricTransport, routeSets map[string]FabricRouteSet, cfg FabricOverlayTransportConfig) *FabricOverlayTransport {
if cfg.Timeout <= 0 {
cfg.Timeout = 30 * time.Second
}
runtime := NewFabricChannelRuntime(transport, FabricChannelRuntimeConfig{
RouterConfig: cfg.RouterConfig,
Timeout: cfg.Timeout,
})
normalized := make(map[string]FabricRouteSet, len(routeSets))
for targetID, routeSet := range routeSets {
targetID = strings.TrimSpace(targetID)
if targetID != "" {
normalized[targetID] = routeSet
}
}
return &FabricOverlayTransport{
Runtime: runtime,
RouteSets: normalized,
Config: cfg,
}
}
func (t *FabricOverlayTransport) Send(ctx context.Context, req FabricOverlaySendRequest) (FabricChannelRuntimeResult, error) {
if t == nil || t.Runtime == nil {
return FabricChannelRuntimeResult{}, ErrForwardRuntimeUnavailable
}
targetID := strings.TrimSpace(req.TargetID)
if targetID == "" {
return FabricChannelRuntimeResult{}, ErrFabricChannelInvalid
}
routeSet, ok := t.RouteSets[targetID]
if !ok {
return FabricChannelRuntimeResult{}, ErrFabricRouteNotFound
}
targetKind := req.TargetKind
if targetKind == "" {
targetKind = routeSet.TargetKind
}
if targetKind == "" {
targetKind = FabricChannelTargetNode
}
trafficClass := req.TrafficClass
if trafficClass == 0 {
trafficClass = fabricproto.TrafficClassReliable
}
t.Runtime.Config.TrafficClass = trafficClass
spec := FabricChannelSpec{
ChannelID: firstNonEmpty(strings.TrimSpace(req.ChannelID), fmt.Sprintf("fabric-overlay-%d", t.sequence.Add(1))),
ClusterID: strings.TrimSpace(t.Config.ClusterID),
SourceNodeID: strings.TrimSpace(t.Config.LocalNodeID),
TargetKind: targetKind,
TargetID: targetID,
TrafficClass: loadFabricTrafficClassName(trafficClass),
StickyKey: strings.TrimSpace(req.StickyKey),
CreatedAt: time.Now().UTC(),
}
return t.Runtime.SendReliable(ctx, spec, routeSet, req.Payloads)
}
func (t *FabricOverlayTransport) SnapshotPressure() FabricRoutePressureSnapshot {
if t == nil || t.Runtime == nil || t.Runtime.Pressure == nil {
return FabricRoutePressureSnapshot{}
}
return t.Runtime.Pressure.SnapshotPressure()
}
func (t *FabricOverlayTransport) Snapshot() FabricOverlayTransportSnapshot {
if t == nil || t.Runtime == nil {
return FabricOverlayTransportSnapshot{}
}
return FabricOverlayTransportSnapshot{
RoutePressure: t.Runtime.snapshotRoutePressure(),
RouteHealth: t.Runtime.snapshotRouteHealth(),
}
}
func loadFabricTrafficClassName(trafficClass fabricproto.TrafficClass) string {
switch trafficClass {
case fabricproto.TrafficClassControl:
return "control"
case fabricproto.TrafficClassInteractive:
return "interactive"
case fabricproto.TrafficClassBulk:
return "bulk"
case fabricproto.TrafficClassReliable:
return "reliable"
default:
return fmt.Sprintf("traffic_class_%d", trafficClass)
}
}