moonbitstack/moonrpc/server does not have a README file

    Interceptor

    type Interceptor = (CallInfo,
    RpcContext
    , Array[Bytes], (Array[Bytes]) -> Array[Bytes]) -> Array[Bytes]

    A server interceptor: (info, ctx, requests, next) -> replies. Call next(requests) to run the rest of the chain, with the messages possibly changed; return without calling it to answer the call itself.

    StreamInterceptor

    A server-streaming interceptor: (ctx, request, next) -> replies. It applies to server-streaming methods only.

    UnaryInterceptor

    A unary server interceptor: (ctx, request, next) -> reply, the shape gRPC-go calls a unary interceptor. It applies to unary methods only; [Interceptor] covers every kind.

    Call

    A call a concurrent server hands to its driver: the stream it belongs to, the context the handler will see, the request messages it carries, and the way to run it. The driver runs run on a task of its own and answers through the Responder, which comes back into the engine as push and end.

    CallInfo

    pub(all) struct CallInfo {
    path : String
    client_streaming : Bool
    server_streaming : Bool
    }

    What a call is, apart from the messages in it: the path, and which of gRPC's two streaming sides it has. An interceptor that only wants unary calls reads this and passes anything else straight on.

    H2Server

    pub struct H2Server {
    handlers : Map[String,
    Handler
    ]
    encoder :
    Encoder

    decoder :
    Decoder

    streams : Map[Int, SrvStream]
    interceptors : Array[(CallInfo,
    RpcContext
    , Array[Bytes], (Array[Bytes]) -> Array[Bytes]) -> Array[Bytes]]
    encoding :
    Encoding

    concurrent : Bool
    calls : Array[Call]
    ended : Array[Int]
    keepalive :
    ServerKeepalive
    ?
    pings :
    PingGuard
    ?
    settings_sent_at : Int64?
    max_recv : Int
    max_send : Int
    size_update : Int?
    conn_recv_window : Int
    conn_send_window : Int
    remote_initial_window : Int
    remote_max_frame : Int
    max_streams : Int
    clock : () -> Int64
    continuing : Int?
    goaway_received : Bool
    last_client_stream : Int
    closing : Bool
    drained : Int?
    }

    The server side of one HTTP/2 connection: the HPACK codec pair, the live streams, the connection-level flow-control windows, and the peer's settings that bound what we may send. Persistent across the whole connection because HPACK and flow control are stateful.

    H2Server::active_streams

    fn H2Server::active_streams(self : H2Server) -> Int

    How many streams are still running: the ones RFC 9113 §5.1.2 counts against SETTINGS_MAX_CONCURRENT_STREAMS, which is open and both half-closed states. A graceful shutdown waits for this to reach zero before closing the connection. Finished streams stay in the map with their state but are not counted, and neither is one the engine only knows of because a WINDOW_UPDATE named it — that stream was never opened, so it holds nothing and occupies no slot.

    H2Server::add_interceptor

    fn H2Server::add_interceptor(self : H2Server, interceptor : (CallInfo,
    RpcContext
    , Array[Bytes], (Array[Bytes]) -> Array[Bytes]) -> Array[Bytes]) -> Unit

    Add an interceptor to the server's chain. It runs on every method the server serves, whichever of the four call kinds it is; interceptors run in registration order, outermost first.

    H2Server::add_stream_interceptor

    fn H2Server::add_stream_interceptor(self : H2Server, interceptor : (
    RpcContext
    , Bytes, (
    RpcContext
    , Bytes) -> Array[Bytes]) -> Array[Bytes]) -> Unit

    Add a server-streaming interceptor: one request, an ordered run of replies.

    H2Server::add_unary_interceptor

    fn H2Server::add_unary_interceptor(self : H2Server, interceptor : (
    RpcContext
    , Bytes, (
    RpcContext
    , Bytes) -> Bytes) -> Bytes) -> Unit

    Add a unary interceptor. It is an [Interceptor] that only answers unary calls, the one-request-one-reply shape; every other kind passes through untouched.

    H2Server::announce

    fn H2Server::announce(self : H2Server, params : Array[(Int, Int)]) -> Array[
    Frame
    ]

    Announce a settings change of our own: a SETTINGS frame the peer must acknowledge. A setting the server enforces on arrival is applied now as well, since a peer cannot be held to a limit it has not been told about either way.

    H2Server::closing

    fn H2Server::closing(self : H2Server) -> Bool

    Whether a connection error has been reported. The GOAWAY carrying it came back from the feed that found it, so the driver writes that and then closes; the engine processes nothing more (RFC 9113 §5.4.1).

    H2Server::concurrent

    fn H2Server::concurrent(self : H2Server, on? : Bool) -> Unit

    Dispatch finished calls to the driver instead of running them inside feed. A concurrent server hands every unary, server- and client-streaming call to the driver as a [Call], which runs it on a task of its own, so one slow handler no longer holds up the other streams on the connection; a pushed handler needs this to run at all. A bidirectional call stays on the engine's thread, since its handler is answered message by message as they arrive.

    H2Server::end

    Close a call the driver was running: its context says how it ended (a handler that called ctx.fail ends it with that status), the body is complete, and the trailers follow. Nothing is sent for a call the engine has already ended.

    H2Server::ended_streams

    fn H2Server::ended_streams(self : H2Server) -> Array[Int]

    The streams the engine has ended since the last call — a deadline that passed, a reset from the peer — so the driver can stop the tasks behind them. Taking the list clears it.

    H2Server::fail

    fn H2Server::fail(self : H2Server, code : Int, why : String) -> Array[
    Frame
    ]

    End the connection with code and why, as a fault of the server's own finding: the frames that report it, after which closing is set. A driver uses this for a fault it detects while reading — a frame over the size the server advertised never becomes a Frame at all, so the engine cannot be the one to notice.

    H2Server::feed

    Feed one decoded incoming frame to the engine, advancing all state and returning the frames to write back (SETTINGS ack, PING pong, WINDOW_UPDATE, and — as the request stream progresses — the framed gRPC response messages and trailers). A protocol fault comes back as the frames that report it rather than as a raise the driver can only discard: RST_STREAM for a stream error, and for a connection error a GOAWAY, after which closing is set and every later frame is ignored (RFC 9113 §5.4).

    H2Server::goaway

    fn H2Server::goaway(self : H2Server, last_stream_id : Int) -> Array[
    Frame
    ]

    Frames for a graceful shutdown: a GOAWAY announcing last_stream_id — the highest client stream the server will still process (RFC 7540 §6.8) — with NO_ERROR, so the peer opens no new streams while in-flight ones finish. The driver writes these before closing the connection. A stream opened above last_stream_id afterwards is declined with RST_STREAM(REFUSED_STREAM), which tells the client it was never processed and can be re-issued elsewhere.

    H2Server::goaway_received

    fn H2Server::goaway_received(self : H2Server) -> Bool

    Whether the peer has sent GOAWAY; the driver stops accepting new streams once this is set.

    H2Server::highest_stream

    fn H2Server::highest_stream(self : H2Server) -> Int

    The highest client stream id this connection has opened, which is what a GOAWAY has to name so the peer knows which of its streams were accepted.

    H2Server::new

    fn H2Server::new() -> H2Server

    A fresh server engine with no registered handlers. Flow-control windows start at the HTTP/2 defaults until the peer's SETTINGS adjust them.

    H2Server::preface

    The server's opening frames (RFC 7540 §3.5): a SETTINGS frame disabling server push and naming how many streams this connection will run at once. Sent immediately after the client connection @http2.preface is validated, before any request frame is read.

    H2Server::push

    fn H2Server::push(self : H2Server, id : Int, messages : Array[Bytes]) -> Array[
    Frame
    ]

    Append reply messages to a call the driver is running, and frame what the windows now allow. A call the engine has already ended — its deadline passed, the peer reset it — takes nothing more.

    H2Server::register

    fn H2Server::register(self : H2Server, path : String, handler : (Bytes) -> Bytes) -> Unit

    Register a unary handler for a fully-qualified gRPC path (/pkg.Service/Method): one request message in, one reply message out. An unmatched path gets a trailers-only grpc-status: 12 (UNIMPLEMENTED) response.

    H2Server::register_bidi

    Register a bidirectional-streaming handler. The factory runs once per call and returns a BidiHandler whose on_message fires per request message (its replies stream out immediately) and whose on_end fires at half-close.

    H2Server::register_client_streaming

    fn H2Server::register_client_streaming(self : H2Server, path : String, handler : (
    RpcContext
    , Array[Bytes]) -> Bytes) -> Unit

    Register a client-streaming handler: every request message the client sends is collected, and after the client half-closes the handler returns one reply.

    H2Server::register_handler

    fn H2Server::register_handler(self : H2Server, path : String, handler :
    Handler
    ) -> Unit

    Register a handler of any of the four gRPC call kinds.

    H2Server::register_server_streaming

    fn H2Server::register_server_streaming(self : H2Server, path : String, handler : (
    RpcContext
    , Bytes) -> Array[Bytes]) -> Unit

    Register a server-streaming handler: one request message, an ordered sequence of reply messages, each framed as its own gRPC message.

    H2Server::register_unary

    fn H2Server::register_unary(self : H2Server, path : String, handler : (
    RpcContext
    , Bytes) -> Bytes) -> Unit

    Register a unary handler that also sees the call context (metadata, deadline, and the response metadata slots).

    H2Server::release

    fn H2Server::release(self : H2Server, id : Int) -> Unit

    Drop everything the engine still holds for a finished stream. The map is only ever inserted into otherwise, so a long-lived connection would keep one full request and response per RPC it has ever served. An unknown id is a no-op.

    H2Server::set_clock

    fn H2Server::set_clock(self : H2Server, clock : () -> Int64) -> Unit

    Install the clock the engine measures grpc-timeout deadlines against: a function returning the current time in milliseconds on any monotonic scale. The engine is a pure state machine with no clock of its own, so until one is installed every deadline is inert; the native driver installs @async.now.

    H2Server::set_encoding

    fn H2Server::set_encoding(self : H2Server, encoding :
    Encoding
    ) -> Unit

    Compress replies with encoding whenever the caller's grpc-accept-encoding lists it; a caller that did not ask for it gets identity, as gRPC requires. A server left alone sends identity, since compressing costs both ends CPU.

    H2Server::set_keepalive

    Hold peers to policy: PINGs closer together than its min_ping_interval are strikes, and a peer that runs out of them is answered GOAWAY(ENHANCE_YOUR_CALM). The driver uses the same policy's time and timeout to ping an idle connection and to declare it dead. Off by default: a server that sets no policy accepts any PING rate.

    H2Server::set_max_message_size

    fn H2Server::set_max_message_size(self : H2Server, recv? : Int, send? : Int) -> Unit

    Cap the messages this server will accept and send, in octets. A larger incoming message ends its call with RESOURCE_EXHAUSTED rather than pinning the memory the length prefix declares; a larger reply ends its call the same way instead of going out.

    H2Server::set_max_streams

    fn H2Server::set_max_streams(self : H2Server, n : Int) -> Unit

    Set how many streams this connection may run at once. The value is both advertised as SETTINGS_MAX_CONCURRENT_STREAMS and enforced on arrival, so set it before @http2.preface and the peer is told exactly what it will be held to.

    H2Server::stream_state

    The lifecycle state of stream id, or Idle if the engine has never seen it.

    H2Server::take_calls

    fn H2Server::take_calls(self : H2Server) -> Array[Call]

    Take the calls waiting to be run, emptying the queue. A driver calls this after every feed and starts a task for each.

    H2Server::tick

    Expire every call whose deadline has passed, returning the frames that end them. The driver calls this on whatever schedule it keeps time on; the engine also checks the deadline whenever a stream advances, so a call that is making progress never needs a tick to be cut off.

    SrvStream

    pub(all) struct SrvStream {
    id : Int
    state :
    StreamState

    header_block :
    Buffer

    data :
    Buffer

    req_off : Int
    req_msgs : Array[Bytes]
    bidi_processed : Int
    headers_complete : Bool
    in_headers : Bool
    end_stream_recv : Bool
    path : String
    ctx :
    RpcContext

    deadline_at : Int64?
    recv_window : Int
    send_window : Int
    out : Bytes
    out_off : Int
    started : Bool
    started_response : Bool
    response_ended : Bool
    finalized : Bool
    trailers_only : Bool
    http_status : Int
    status_code : Int
    status_message : String
    req_encoding : Bytes
    accept_encodings : Bytes
    resp_encoding :
    Encoding

    compressed_unsupported : Bool
    oversize : Bool
    headers_sent : Bool
    trailers_sent : Bool
    bidi :
    BidiHandler
    ?
    }

    One server-side stream: its lifecycle state, the accumulating request header block and DATA (with a cursor over the length-prefixed messages already pulled out of it), the per-stream flow-control windows, and the response side — the bytes still to send, whether the initial HEADERS and the trailers have gone out, and any live bidi call state.

    default_max_streams

    let default_max_streams : Int

    The SETTINGS_MAX_CONCURRENT_STREAMS the server advertises and enforces unless a caller says otherwise: 100, the value gRPC and nghttp2 both settle on. RFC 9113 §5.1.2 leaves the setting unset by default, which means unbounded — and every live stream holds a request buffer, so a peer that opens streams and never finishes them pins memory for as long as the connection lasts.

    settings_ack_timeout

    let settings_ack_timeout : Int64

    How long a peer has to acknowledge a SETTINGS frame before the connection is given up on: ten seconds, the value gRPC core uses for SETTINGS timeouts.

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io