02 / ROUTING
zrpc
RpcServer::to_h2 exposes the registered handlers as a moonrpc H2Server, and RpcChannel drives real unary, server/client-streaming, and bidirectional calls over that transport: HPACK-coded HEADERS, length-prefixed DATA frames, and the grpc-status trailer read back off the reply. A BidiCall keeps the stream open both ways — send returns the replies produced right then, close_send runs the server's on_end and reports the final grpc-status.
WHERE IT SITS
INTERFACE
fn status_of_code(code : Int32) -> @moonrpc.StatusfnMap a numeric grpc-status code back to a @moonrpc.Status. Anything outside the canonical 0–16 range is reported as Unknown, matching how a gRPC client treats an unrecognised code.
fn RpcServer::to_h2(self : RpcServer) -> @moonrpc.H2ServerfnBuild a @moonrpc.H2Server protocol engine from this zRPC server's registered handlers — the transport-facing view of the same registry dispatch reads. Each handler is bound to its gRPC path, so a request arriving over the h2c transport is dispatched to exactly the handler the group registered.
struct RpcChannelstructAn in-process gRPC channel bound to a server engine — the client half of the h2c transport. A call is carried as the real HTTP/2 frames a socket-backed client would send: an HPACK-coded HEADERS block with the gRPC pseudo-headers, a length-prefixed DATA frame closing the stream, and the grpc-status trailer read back off the engine's reply. The channel's HPACK encoder pairs with the engine's decoder and vice versa, so the dynamic-table state stays in lockstep across every call on the channel.
fn RpcChannel::connect( server : RpcServer, authority~ : String = "localhost") -> RpcChannelfnOpen a channel to server over an in-process h2c transport, exchanging the opening SETTINGS the way a real connection does. Client-initiated streams use odd identifiers (RFC 7540 §5.1.1), starting at 1.
fn RpcChannel::with_interceptors( self : RpcChannel, interceptors : Array[Interceptor]) -> RpcChannelfnA channel with interceptors as its client chain, outermost first.
fn RpcChannel::interceptors(self : RpcChannel) -> Array[Interceptor]fnThe interceptors this channel's unary calls run through, outermost first.
fn RpcChannel::call_through( self : RpcChannel, path : String, request : Bytes, parent? : @trace.TraceContext) -> Result[Bytes, @moonrpc.Status]fnInvoke path through the client interceptor chain. The chain sees every failure the transport reports, including an unknown method, and can refuse a call before it reaches the wire.
fn RpcChannel::call( self : RpcChannel, path : String, request : Bytes) -> Result[Bytes, @moonrpc.Status] raisefnInvoke a unary method at path with request as its message payload, driving the call through the h2c engine and returning the reply payload on grpc-status: 0, or the mapped @moonrpc.Status otherwise. request and the returned reply are bare message bytes; the length-prefix framing is applied and stripped by the transport.
fn RpcChannel::call_server_streaming( self : RpcChannel, path : String, request : Bytes) -> Result[Array[Bytes], @moonrpc.Status] raisefnInvoke a server-streaming method at path: send the single request message and read back the ordered sequence of reply messages the server produced, or the mapped error @moonrpc.Status if the stream closed with a non-zero grpc-status. On Ok the array holds every message in emission order (possibly empty).
fn RpcChannel::call_client_streaming( self : RpcChannel, path : String, requests : Array[Bytes]) -> Result[Bytes, @moonrpc.Status] raisefnInvoke a client-streaming method at path: send every message in requests as its own DATA frame, half-close the stream, and read back the single reply. An empty requests still opens and half-closes the stream, so the handler runs with no messages.
struct BidiCallstructA live client-side bidirectional call over the h2c channel: the request stream stays open while messages flow both ways. send writes one request message and returns whatever replies the server produced right then (bidi interleaving — an echo handler answers each message as it arrives); close_send half-closes the request stream, runs the server's on_end, and reports the final grpc-status. The channel's HPACK decoder is advanced across every reply block, so its dynamic table stays in lockstep with the engine's encoder for the life of the call. pending holds DATA octets not yet split into a whole length-prefixed message (a message may straddle two DATA frames under flow control).
fn RpcChannel::open_bidi( self : RpcChannel, path : String) -> BidiCall raisefnOpen a bidirectional stream to path, sending the request HEADERS without half-closing so the stream stays open for interleaved sends. An unregistered path answers trailers-only UNIMPLEMENTED during this HEADERS feed, which the returned call captures as its status.
fn BidiCall::send(self : BidiCall, msg : Bytes) -> Array[Bytes] raisefnSend one request message on the open stream and return the replies the server emitted in response to it (possibly empty). A no-op once the stream is half-closed.
fn BidiCall::close_send( self : BidiCall) -> Result[Array[Bytes], @moonrpc.Status] raisefnHalf-close the request stream: run the server's on_end, return its final reply messages, and map the grpc-status trailer to Ok/Err. Calling it a second time is an error (Cancelled).
fn RpcChannel::call_bidi_streaming( self : RpcChannel, path : String, requests : Array[Bytes]) -> Result[Array[Bytes], @moonrpc.Status] raisefnDrive a whole bidirectional call at path in one shot: send every message in requests (collecting the interleaved replies in order), then half-close and append the on_end replies. The result is every reply message the server produced, in emission order, or the non-zero grpc-status the stream closed with.
struct RpcMetricsstructThe per-method call metrics of one side of the wire.
let default_latency_buckets : Array[Double] = [letThe latency buckets the reference implementation registers for an RPC method.
fn RpcMetrics::new( kind~ : String = "client") -> RpcMetrics raise @metric.RefusedfnMetrics for the client side (kind="client") or the server side (kind="server").
fn RpcMetrics::registry(self : RpcMetrics) -> @moonp8s.RegistryfnThe registry these families hang off.
fn RpcMetrics::observe( self : RpcMetrics, path : String, status : Int32, duration_ms : Double) -> UnitfnRecord one finished call: its duration in milliseconds and its status code, under the method's full path.
fn RpcMetrics::calls( self : RpcMetrics, path : String, status : Int32) -> DoublefnThe number of calls recorded for path with status.
fn RpcMetrics::observations(self : RpcMetrics, path : String) -> Int64fnThe latency observations recorded for path.
fn RpcMetrics::to_exposition(self : RpcMetrics) -> StringfnThe two families as the Prometheus text exposition a /metrics scrape reads.