feat: edge gateway service

This commit is contained in:
Ilia Denisov
2026-04-02 19:18:42 +02:00
committed by GitHub
parent 8cde99936c
commit 436c97a38b
95 changed files with 20504 additions and 57 deletions
+102
View File
@@ -0,0 +1,102 @@
// Package telemetry provides shared edge observability helpers used by the
// gateway transports and internal event consumers.
package telemetry
import (
"net/http"
"strings"
"google.golang.org/grpc/codes"
)
// EdgeOutcome is the stable low-cardinality outcome vocabulary shared by REST,
// gRPC, push shutdown, and observability backends.
type EdgeOutcome string
const (
EdgeOutcomeSuccess EdgeOutcome = "success"
EdgeOutcomeMalformedRequest EdgeOutcome = "malformed_request"
EdgeOutcomeRequestTooLarge EdgeOutcome = "request_too_large"
EdgeOutcomeUnsupportedProtocol EdgeOutcome = "unsupported_protocol"
EdgeOutcomeUnknownSession EdgeOutcome = "unknown_session"
EdgeOutcomeRevokedSession EdgeOutcome = "revoked_session"
EdgeOutcomeInvalidSignature EdgeOutcome = "invalid_signature"
EdgeOutcomeStaleRequest EdgeOutcome = "stale_request"
EdgeOutcomeReplayDetected EdgeOutcome = "replay_detected"
EdgeOutcomeRateLimited EdgeOutcome = "rate_limited"
EdgeOutcomePolicyDenied EdgeOutcome = "policy_denied"
EdgeOutcomeDownstreamUnavailable EdgeOutcome = "downstream_unavailable"
EdgeOutcomeBackendUnavailable EdgeOutcome = "backend_unavailable"
EdgeOutcomeInternalError EdgeOutcome = "internal_error"
EdgeOutcomeGatewayShuttingDown EdgeOutcome = "gateway_shutting_down"
)
// RejectReason returns the stable reject reason for outcome. Success does not
// produce a reject reason.
func RejectReason(outcome EdgeOutcome) string {
if outcome == EdgeOutcomeSuccess {
return ""
}
return string(outcome)
}
// OutcomeFromPublicErrorCode maps the stable public REST error envelope into
// the shared edge-outcome vocabulary.
func OutcomeFromPublicErrorCode(statusCode int, code string) EdgeOutcome {
switch strings.TrimSpace(code) {
case "":
if statusCode < http.StatusBadRequest {
return EdgeOutcomeSuccess
}
return EdgeOutcomeInternalError
case "invalid_request", "method_not_allowed", "not_found":
return EdgeOutcomeMalformedRequest
case "request_too_large":
return EdgeOutcomeRequestTooLarge
case "rate_limited":
return EdgeOutcomeRateLimited
case "service_unavailable":
return EdgeOutcomeBackendUnavailable
default:
if statusCode >= http.StatusInternalServerError {
return EdgeOutcomeInternalError
}
return EdgeOutcomeMalformedRequest
}
}
// OutcomeFromGRPCStatus maps the stable authenticated gRPC reject contract
// into the shared edge-outcome vocabulary.
func OutcomeFromGRPCStatus(code codes.Code, message string) EdgeOutcome {
switch {
case code == codes.OK:
return EdgeOutcomeSuccess
case code == codes.InvalidArgument:
return EdgeOutcomeMalformedRequest
case code == codes.FailedPrecondition && strings.Contains(message, "unsupported protocol_version"):
return EdgeOutcomeUnsupportedProtocol
case code == codes.Unauthenticated && message == "unknown device session":
return EdgeOutcomeUnknownSession
case code == codes.FailedPrecondition && message == "device session is revoked":
return EdgeOutcomeRevokedSession
case code == codes.Unauthenticated && message == "invalid request signature":
return EdgeOutcomeInvalidSignature
case code == codes.FailedPrecondition && message == "request timestamp is outside the freshness window":
return EdgeOutcomeStaleRequest
case code == codes.FailedPrecondition && message == "request replay detected":
return EdgeOutcomeReplayDetected
case code == codes.ResourceExhausted && message == "authenticated request rate limit exceeded":
return EdgeOutcomeRateLimited
case code == codes.PermissionDenied && message == "authenticated request rejected by edge policy":
return EdgeOutcomePolicyDenied
case code == codes.Unavailable && message == "downstream service is unavailable":
return EdgeOutcomeDownstreamUnavailable
case code == codes.Unavailable && message == "gateway is shutting down":
return EdgeOutcomeGatewayShuttingDown
case code == codes.Unavailable:
return EdgeOutcomeBackendUnavailable
default:
return EdgeOutcomeInternalError
}
}