Documentation
¶
Overview ¶
Package rpc holds the gRPC stream plumbing the proxy's forwarding paths share.
ServiceMethod, Service, and Method split a gRPC full method name into the halves an allowlist check or a descriptor lookup needs. Pump.Forward forwards one call between an inbound server stream and an outbound client stream, and StatusError maps a failure along the way to the status the caller sees.
Index ¶
- func FullMethod(ctx context.Context) (string, error)
- func Method(fullMethod string) string
- func Reject(code codes.Code, clientMsg, detail string) error
- func Service(fullMethod string) string
- func ServiceMethod(fullMethod string) (service, method string, ok bool)
- func StatusError(what string, err error) error
- func WithOutgoing(ctx context.Context, fn func(metadata.MD)) context.Context
- type Frame
- type Pump
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FullMethod ¶
FullMethod returns the full method name of the call ctx belongs to, in the "/pkg.Service/Method" form the other helpers here parse. It fails when ctx carries no server transport stream, which means it is not a server call's context and there is no method to name.
func Method ¶
Method returns the method half of a gRPC full method, or "" when fullMethod carries no method to strip.
func Reject ¶
Reject builds a rejection carrying a client-safe code+message and a server-side detail for logging.
Return the result unwrapped. gRPC reads GRPCStatus verbatim only for an error it can type-assert directly; for a wrapped one it keeps the code but replaces the message with err.Error(), which is the detail. Adding context with %w therefore sends the caller exactly what this type withholds, so put the context in the detail instead.
func Service ¶
Service returns the service half of a gRPC full method, or "" when fullMethod carries no method to strip. Callers must treat "" as "no service" rather than as a name to match on.
func ServiceMethod ¶
ServiceMethod splits a gRPC full method ("/pkg.Service/Method", with or without the leading slash gRPC supplies) into its service and method halves. It reports false when fullMethod carries no method to split off, in which case both halves are empty.
func StatusError ¶
StatusError maps a forwarding error to the gRPC status returned to the caller, naming the step that failed as what. It forwards an error already carrying a status verbatim, maps a raw context error to its status, and otherwise reports Internal. Callers own the whole message, so what carries their own package prefix.
func WithOutgoing ¶
WithOutgoing returns ctx with fn applied to its outgoing gRPC metadata. fn receives a copy, never the metadata already on ctx: that copy is the whole point, because outgoing metadata is shared with whatever else holds the context and mutating it in place corrupts calls in flight. fn is handed empty metadata when ctx carries none, so a caller that only adds keys needs no special case.
Types ¶
type Frame ¶
type Frame func() any
Frame allocates the value one direction receives into, and is called once per message. What that value is decides what the streams' codec does with it: a typed proto message is one client interceptors can read, while an opaque byte frame passes through unparsed. Returning the same value every call reuses one buffer for the direction, which is safe because the direction is sequential.
type Pump ¶
type Pump struct {
// contains filtered or unexported fields
}
Pump copies messages between the inbound server stream and the outbound client stream of one forwarded call, one goroutine per direction.
func NewPump ¶
func NewPump(cs grpc.ClientStream, ss grpc.ServerStream) *Pump
NewPump returns a Pump that reads requests from ss and writes them to cs, and reads responses from cs and writes them to ss.
func (*Pump) Forward ¶
Forward forwards the whole call, relaying the upstream's header, trailer, and status to the caller. A half-close from the caller closes the upstream's send side and the call continues, so the loop runs at most twice: the request direction ending is not the call ending, and only the response direction finishing is. Both directions are started once, up front, because starting them inside the select would spawn a fresh pair per iteration.