304 lines
13 KiB
Go
304 lines
13 KiB
Go
package mesh
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"time"
|
|
)
|
|
|
|
const ProtocolVersion = "mesh-control-v1"
|
|
|
|
var (
|
|
ErrClusterMismatch = errors.New("mesh peer cluster mismatch")
|
|
ErrNodeMismatch = errors.New("mesh peer node mismatch")
|
|
ErrForwardDisabled = errors.New("production payload forwarding is disabled by mesh production gate")
|
|
ErrForwardRuntimeUnavailable = errors.New("production mesh forwarding runtime is unavailable for this route or stage")
|
|
ErrForwardPeerUnavailable = errors.New("production mesh next peer is unavailable")
|
|
ErrForwardEnvelopeInvalid = errors.New("production mesh envelope is invalid")
|
|
ErrForwardObservationFailed = errors.New("production mesh envelope observation failed")
|
|
ErrForwardDeliveryFailed = errors.New("production mesh envelope delivery failed")
|
|
ErrMeshRuntimeDisabled = errors.New("mesh synthetic runtime is disabled")
|
|
ErrUnsupportedSyntheticMessage = errors.New("unsupported synthetic mesh message")
|
|
ErrRouteIDRequired = errors.New("mesh synthetic route id is required")
|
|
ErrRouteNotFound = errors.New("mesh synthetic route not found")
|
|
ErrInvalidRoutePath = errors.New("mesh synthetic route path is invalid")
|
|
ErrRouteExpired = errors.New("mesh synthetic route is expired")
|
|
ErrTTLExhausted = errors.New("mesh synthetic route ttl exhausted")
|
|
ErrLoopDetected = errors.New("mesh synthetic route loop detected")
|
|
ErrUnauthorizedChannel = errors.New("mesh synthetic channel is not authorized")
|
|
ErrSyntheticPeerUnavailable = errors.New("mesh synthetic next peer is unavailable")
|
|
ErrNoHealthySyntheticRoute = errors.New("mesh synthetic no healthy route available")
|
|
ErrSyntheticRelayQueueFull = errors.New("mesh synthetic relay queue is full")
|
|
ErrSyntheticRelayQueueEmpty = errors.New("mesh synthetic relay queue is empty")
|
|
ErrSyntheticPayloadTooLarge = errors.New("mesh synthetic payload is too large")
|
|
ErrSyntheticOrganizationMismatch = errors.New("mesh synthetic organization mismatch")
|
|
ErrUnsupportedSyntheticService = errors.New("unsupported synthetic test service")
|
|
ErrSyntheticRequestInvalid = errors.New("mesh synthetic request is invalid")
|
|
)
|
|
|
|
const (
|
|
SyntheticMessageProbe = "fabric.probe"
|
|
SyntheticMessageProbeAck = "fabric.probe_ack"
|
|
SyntheticMessageRouteHealth = "fabric.route_health"
|
|
SyntheticMessageRouteHealthAck = "fabric.route_health_ack"
|
|
SyntheticMessageTelemetry = "fabric.telemetry"
|
|
SyntheticMessageTestService = "fabric.test_service"
|
|
SyntheticMessageTestServiceAck = "fabric.test_service_ack"
|
|
|
|
SyntheticTestServiceType = "synthetic.echo"
|
|
SyntheticDefaultTestOrganizationID = "org-test"
|
|
SyntheticDefaultMaxTestPayloadBytes = 4096
|
|
|
|
SyntheticChannelFabricControl = "fabric_control"
|
|
SyntheticChannelRouteControl = "route_control"
|
|
SyntheticChannelTelemetry = "telemetry"
|
|
|
|
SyntheticRouteStateUnknown = "unknown"
|
|
SyntheticRouteStateHealthy = "healthy"
|
|
SyntheticRouteStateDegraded = "degraded"
|
|
SyntheticRouteStateFailed = "failed"
|
|
|
|
ProductionChannelFabricControl = "fabric_control"
|
|
ProductionMessageFabricControl = "fabric.control"
|
|
ProductionChannelVPNPacket = "vpn_packet"
|
|
ProductionMessageVPNPacketBatch = "vpn.packet_batch"
|
|
FabricServiceClassVPNPackets = "vpn_packets"
|
|
FabricServiceClassRemoteWorkspace = "remote_workspace"
|
|
FabricServiceChannelBulk = "bulk"
|
|
FabricServiceChannelControl = "control"
|
|
FabricServiceChannelInteractive = "interactive"
|
|
FabricServiceChannelReliable = "reliable"
|
|
FabricServiceChannelDroppable = "droppable"
|
|
MaxProductionEnvelopePayloadBytes = 4096
|
|
MaxProductionVPNPacketPayloadBytes = 256 * 1024
|
|
MaxProductionEnvelopeFutureSkew = time.Minute
|
|
ProductionForwardQUICStreamID = 1
|
|
WebIngressForwardQUICStreamID = 2
|
|
FabricControlForwardQUICStreamID = 3
|
|
SyntheticForwardQUICStreamID = 1001
|
|
)
|
|
|
|
type PeerIdentity struct {
|
|
ClusterID string `json:"cluster_id"`
|
|
NodeID string `json:"node_id"`
|
|
}
|
|
|
|
type SyntheticRoute struct {
|
|
RouteID string `json:"route_id"`
|
|
ClusterID string `json:"cluster_id"`
|
|
SourceNodeID string `json:"source_node_id"`
|
|
DestinationNodeID string `json:"destination_node_id"`
|
|
Hops []string `json:"hops"`
|
|
AllowedChannels []string `json:"allowed_channels"`
|
|
ExpiresAt time.Time `json:"expires_at"`
|
|
MaxTTL int `json:"max_ttl"`
|
|
MaxHops int `json:"max_hops"`
|
|
RouteVersion string `json:"route_version,omitempty"`
|
|
PolicyVersion string `json:"policy_version,omitempty"`
|
|
PeerDirectoryVersion string `json:"peer_directory_version,omitempty"`
|
|
}
|
|
|
|
type SyntheticEnvelope struct {
|
|
ProtocolVersion string `json:"protocol_version"`
|
|
RouteID string `json:"route_id"`
|
|
ClusterID string `json:"cluster_id"`
|
|
From PeerIdentity `json:"from"`
|
|
To PeerIdentity `json:"to"`
|
|
Channel string `json:"channel"`
|
|
MessageType string `json:"message_type"`
|
|
TTL int `json:"ttl"`
|
|
HopCount int `json:"hop_count"`
|
|
Visited []string `json:"visited"`
|
|
Sequence uint64 `json:"sequence"`
|
|
SentAt time.Time `json:"sent_at"`
|
|
Payload json.RawMessage `json:"payload,omitempty"`
|
|
}
|
|
|
|
type SyntheticProbePayload struct {
|
|
ProbeID string `json:"probe_id"`
|
|
SentAt time.Time `json:"sent_at"`
|
|
}
|
|
|
|
type SyntheticProbeAckPayload struct {
|
|
ProbeID string `json:"probe_id"`
|
|
Path []string `json:"path"`
|
|
AcceptedAt time.Time `json:"accepted_at"`
|
|
}
|
|
|
|
type SyntheticRouteObservation struct {
|
|
RouteID string `json:"route_id"`
|
|
State string `json:"state"`
|
|
LastSuccessAt time.Time `json:"last_success_at,omitempty"`
|
|
LastFailureAt time.Time `json:"last_failure_at,omitempty"`
|
|
LastFailureReason string `json:"last_failure_reason,omitempty"`
|
|
SuccessCount uint64 `json:"success_count"`
|
|
FailureCount uint64 `json:"failure_count"`
|
|
LastLatencyMs int64 `json:"last_latency_ms,omitempty"`
|
|
RouteVersion string `json:"route_version,omitempty"`
|
|
PolicyVersion string `json:"policy_version,omitempty"`
|
|
PeerDirectoryVersion string `json:"peer_directory_version,omitempty"`
|
|
}
|
|
|
|
type SyntheticRouteHealthResult struct {
|
|
RequestedRouteID string `json:"requested_route_id"`
|
|
SelectedRouteID string `json:"selected_route_id"`
|
|
FallbackUsed bool `json:"fallback_used"`
|
|
Ack SyntheticEnvelope `json:"ack"`
|
|
Observation SyntheticRouteObservation `json:"observation"`
|
|
}
|
|
|
|
type SyntheticTestServiceRequest struct {
|
|
RequestID string `json:"request_id"`
|
|
OrganizationID string `json:"organization_id"`
|
|
ServiceType string `json:"service_type"`
|
|
Payload string `json:"payload"`
|
|
SentAt time.Time `json:"sent_at"`
|
|
}
|
|
|
|
type SyntheticTestServiceResponse struct {
|
|
RequestID string `json:"request_id"`
|
|
OrganizationID string `json:"organization_id"`
|
|
ServiceType string `json:"service_type"`
|
|
EchoPayload string `json:"echo_payload"`
|
|
Path []string `json:"path"`
|
|
AcceptedAt time.Time `json:"accepted_at"`
|
|
}
|
|
|
|
type SyntheticTestServiceResult struct {
|
|
RequestedRouteID string `json:"requested_route_id"`
|
|
SelectedRouteID string `json:"selected_route_id"`
|
|
FallbackUsed bool `json:"fallback_used"`
|
|
Ack SyntheticEnvelope `json:"ack"`
|
|
Response SyntheticTestServiceResponse `json:"response"`
|
|
Observation SyntheticRouteObservation `json:"observation"`
|
|
}
|
|
|
|
type SyntheticRouteCacheVersion struct {
|
|
RouteVersion string `json:"route_version,omitempty"`
|
|
PolicyVersion string `json:"policy_version,omitempty"`
|
|
PeerDirectoryVersion string `json:"peer_directory_version,omitempty"`
|
|
}
|
|
|
|
type SyntheticRelayQueuePolicy struct {
|
|
Channel string `json:"channel"`
|
|
Capacity int `json:"capacity"`
|
|
Droppable bool `json:"droppable"`
|
|
}
|
|
|
|
type SyntheticRelayEnqueueResult struct {
|
|
Channel string `json:"channel"`
|
|
QueueDepth int `json:"queue_depth"`
|
|
QueueCapacity int `json:"queue_capacity"`
|
|
Dropped bool `json:"dropped"`
|
|
DroppedSequence uint64 `json:"dropped_sequence,omitempty"`
|
|
AcceptedSequence uint64 `json:"accepted_sequence"`
|
|
}
|
|
|
|
type SyntheticRelayQueueMetrics struct {
|
|
Enqueued uint64 `json:"enqueued"`
|
|
Dequeued uint64 `json:"dequeued"`
|
|
Dropped uint64 `json:"dropped"`
|
|
Rejected uint64 `json:"rejected"`
|
|
LastRejectReason string `json:"last_reject_reason,omitempty"`
|
|
QueueDepths map[string]int `json:"queue_depths"`
|
|
}
|
|
|
|
type HealthMessage struct {
|
|
ProtocolVersion string `json:"protocol_version"`
|
|
From PeerIdentity `json:"from"`
|
|
To PeerIdentity `json:"to"`
|
|
ObservedAt time.Time `json:"observed_at"`
|
|
LinkStatus string `json:"link_status"`
|
|
LatencyMs *int `json:"latency_ms,omitempty"`
|
|
QualityScore *int `json:"quality_score,omitempty"`
|
|
}
|
|
|
|
type HealthAck struct {
|
|
ProtocolVersion string `json:"protocol_version"`
|
|
Accepted bool `json:"accepted"`
|
|
By PeerIdentity `json:"by"`
|
|
}
|
|
|
|
type ProductionEnvelope struct {
|
|
FabricProtocolVersion string `json:"fabric_protocol_version"`
|
|
MessageID string `json:"message_id"`
|
|
RouteID string `json:"route_id"`
|
|
ClusterID string `json:"cluster_id"`
|
|
SourceNodeID string `json:"source_node_id"`
|
|
DestinationNodeID string `json:"destination_node_id"`
|
|
CurrentHopNodeID string `json:"current_hop_node_id"`
|
|
NextHopNodeID string `json:"next_hop_node_id"`
|
|
RoutePath []string `json:"route_path,omitempty"`
|
|
VisitedNodeIDs []string `json:"visited_node_ids,omitempty"`
|
|
ChannelClass string `json:"channel_class"`
|
|
MessageType string `json:"message_type"`
|
|
TTL int `json:"ttl"`
|
|
HopCount int `json:"hop_count"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
ExpiresAt time.Time `json:"expires_at"`
|
|
PayloadLength int `json:"payload_length"`
|
|
PayloadHash string `json:"payload_hash"`
|
|
Payload json.RawMessage `json:"payload,omitempty"`
|
|
}
|
|
|
|
type ProductionEnvelopeObservation struct {
|
|
MessageID string `json:"message_id"`
|
|
RouteID string `json:"route_id"`
|
|
ClusterID string `json:"cluster_id"`
|
|
SourceNodeID string `json:"source_node_id"`
|
|
DestinationNodeID string `json:"destination_node_id"`
|
|
CurrentHopNodeID string `json:"current_hop_node_id"`
|
|
NextHopNodeID string `json:"next_hop_node_id"`
|
|
RoutePath []string `json:"route_path,omitempty"`
|
|
VisitedNodeIDs []string `json:"visited_node_ids,omitempty"`
|
|
ChannelClass string `json:"channel_class"`
|
|
MessageType string `json:"message_type"`
|
|
TTL int `json:"ttl"`
|
|
HopCount int `json:"hop_count"`
|
|
PayloadLength int `json:"payload_length"`
|
|
PayloadHash string `json:"payload_hash"`
|
|
ObservedAt time.Time `json:"observed_at"`
|
|
}
|
|
|
|
type ProductionForwardResult struct {
|
|
Accepted bool `json:"accepted"`
|
|
Delivered bool `json:"delivered"`
|
|
Forwarded bool `json:"forwarded"`
|
|
By PeerIdentity `json:"by"`
|
|
MessageID string `json:"message_id"`
|
|
RouteID string `json:"route_id"`
|
|
NextNodeID string `json:"next_node_id,omitempty"`
|
|
}
|
|
|
|
type ProductionForwardLogEntry struct {
|
|
Event string `json:"event"`
|
|
RouteID string `json:"route_id,omitempty"`
|
|
MessageID string `json:"message_id,omitempty"`
|
|
ClusterID string `json:"cluster_id,omitempty"`
|
|
LocalNodeID string `json:"local_node_id,omitempty"`
|
|
SourceNodeID string `json:"source_node_id,omitempty"`
|
|
DestinationNodeID string `json:"destination_node_id,omitempty"`
|
|
CurrentHopNodeID string `json:"current_hop_node_id,omitempty"`
|
|
NextHopNodeID string `json:"next_hop_node_id,omitempty"`
|
|
ChannelClass string `json:"channel_class,omitempty"`
|
|
MessageType string `json:"message_type,omitempty"`
|
|
Reason string `json:"reason,omitempty"`
|
|
StatusCode int `json:"status_code,omitempty"`
|
|
TTL int `json:"ttl,omitempty"`
|
|
HopCount int `json:"hop_count,omitempty"`
|
|
RoutePathLength int `json:"route_path_length,omitempty"`
|
|
VisitedCount int `json:"visited_count,omitempty"`
|
|
PayloadLength int `json:"payload_length,omitempty"`
|
|
OccurredAt time.Time `json:"occurred_at"`
|
|
}
|
|
|
|
func ValidatePeer(local PeerIdentity, remote PeerIdentity) error {
|
|
if local.ClusterID == "" || remote.ClusterID == "" || local.ClusterID != remote.ClusterID {
|
|
return ErrClusterMismatch
|
|
}
|
|
if remote.NodeID == "" {
|
|
return ErrNodeMismatch
|
|
}
|
|
return nil
|
|
}
|