fix(gateway): close Phase 3C audit gaps

This commit is contained in:
sechmachine
2026-07-30 01:46:00 +07:00
parent 040ca73ce9
commit d3852d15f3
23 changed files with 1619 additions and 219 deletions
+74 -1
View File
@@ -90,6 +90,8 @@ func heartbeatLoop(ctx context.Context, client *gateway.ControlPlaneClient, serv
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
var sequence int64
var sampler heartbeatSampler
_, _ = sampler.sample(time.Now(), server.Metrics())
for {
select {
case <-ctx.Done():
@@ -104,11 +106,82 @@ func heartbeatLoop(ctx context.Context, client *gateway.ControlPlaneClient, serv
state = "draining"
}
metrics := server.Metrics()
_ = client.Heartbeat(ctx, protocol.GatewayHeartbeat{Version: "1", GatewayID: registration.GatewayID, Sequence: sequence, ObservedAt: time.Now().UTC().Format(time.RFC3339Nano), ActiveConnections: metrics.ActiveSessions, EgressKbps: registration.BandwidthCapacityKbps, State: state})
observedAt := time.Now()
egressKbps, telemetry := sampler.sample(observedAt, metrics)
_ = client.Heartbeat(ctx, protocol.GatewayHeartbeat{
Version: "1", GatewayID: registration.GatewayID, Sequence: sequence,
ObservedAt: observedAt.UTC().Format(time.RFC3339Nano), ActiveConnections: metrics.ActiveSessions,
EgressKbps: egressKbps, State: state, Telemetry: telemetry,
})
}
}
}
type heartbeatSampler struct {
observedAt time.Time
mediaBytes uint64
}
func (s *heartbeatSampler) sample(observedAt time.Time, metrics gateway.MetricsSnapshot) (int64, protocol.GatewayTelemetry) {
egressKbps := int64(0)
elapsedMillis := observedAt.Sub(s.observedAt).Milliseconds()
if !s.observedAt.IsZero() && elapsedMillis > 0 && metrics.MediaBytes >= s.mediaBytes {
delta := metrics.MediaBytes - s.mediaBytes
milliseconds := uint64(elapsedMillis)
whole, remainder := delta/milliseconds, delta%milliseconds
if whole > 125_000_000 {
egressKbps = 1_000_000_000
} else {
rate := whole*8 + remainder*8/milliseconds
if rate > 1_000_000_000 {
rate = 1_000_000_000
}
egressKbps = int64(rate)
}
}
s.observedAt, s.mediaBytes = observedAt, metrics.MediaBytes
return egressKbps, protocol.GatewayTelemetry{
AdmittedSessions: boundedMetric(metrics.AdmittedSessions), AdmissionRejects: boundedMetric(metrics.AdmissionRejects),
Reconnects: boundedMetric(metrics.Reconnects), DrainTransitions: boundedMetric(metrics.DrainTransitions),
MediaDrops: boundedMetric(metrics.MediaDrops), MediaPackets: boundedMetric(metrics.MediaPackets),
MediaBytes: boundedMetric(metrics.MediaBytes), QueueDelayMicros: boundedMetric(metrics.QueueDelayNanos / 1000),
ProcessingDelayMicros: boundedMetric(metrics.ProcessingDelayNanos / 1000), ProcessingSamples: boundedMetric(metrics.ProcessingSamples),
PacingDelayMicros: boundedMetric(metrics.PacingDelayNanos / 1000), ProviderErrors: boundedMetric(metrics.ProviderErrors),
InputRejected: boundedMetric(metrics.InputRejected), ControlRttMicros: boundedMetric(metrics.ControlRTTNanos / 1000),
ControlJitterMicros: boundedMetric(metrics.ControlJitterNanos / 1000), ControlLossPpm: boundedMetric(metrics.ControlLossPPM),
PendingReliable: boundedMetric(metrics.PendingReliable), ProviderState: providerStateName(metrics.ProviderState),
}
}
func boundedMetric(value uint64) int64 {
const maximum = uint64(^uint64(0) >> 1)
if value > maximum {
return int64(maximum)
}
return int64(value)
}
func providerStateName(value uint64) string {
switch value {
case 1:
return gateway.ProviderStateStarting
case 2:
return gateway.ProviderStateReady
case 3:
return gateway.ProviderStateDisconnected
case 4:
return gateway.ProviderStateTerminating
case 5:
return gateway.ProviderStateTerminated
case 6:
return gateway.ProviderStateCleanup
case 7:
return gateway.ProviderStateFailed
default:
return "unknown"
}
}
func loadTLS(certFile, keyFile, clientCAFile string) (*tls.Config, *tls.Config, error) {
certificate, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {