moonbitstack/moonrpc/client does not have a README file

    Interceptor

    type Interceptor = async (Invocation, async (Invocation) -> CallReply) -> CallReply

    A client interceptor: (invocation, next) -> reply. Change the invocation and hand it to next to let the call go out, look at the reply on the way back, or answer the call itself without calling next.

    Caller

    pub(open) trait Caller {
    async fn invoke(Self, String, Array[Bytes], Array[
    Header
    ], Int?,
    Retry
    ?) -> CallReply
    }

    What a generated client stub calls through: something that sends requests on path with metadata, half-closes, and returns how the call ended, under an optional deadline in milliseconds and retry policy. The native Channel, ManagedChannel and MuxChannel implement it; a test double or an interceptor chain implements it to stand in their place, as tonic's GrpcService does.

    CallReply

    pub(all) struct CallReply {
    status : Bytes
    grpc_status : Int
    grpc_message : String
    headers : Array[
    Header
    ]
    messages : Array[Bytes]
    trailers : Array[
    Header
    ]
    committed : Bool
    unprocessed : Bool
    }

    The completed result of a call: the HTTP :status, the numeric grpc-status (-1 if the peer never sent one), the response initial metadata, the reply messages in order, and the trailing metadata. A Trailers-Only response has no initial metadata: what it carries is trailers.

    committed says Response-Headers arrived before the trailers, so the server had started answering and A6 never retries the call. unprocessed says the server refused the stream or a GOAWAY showed it was never handled, so it is safe to send again.

    CallReply::details

    The google.rpc.Status this call ended with, when the server sent one in grpc-status-details-bin; None when it sent none, or when the trailer does not decode. The status itself is still in grpc_status and grpc_message: a detail a client cannot read is no reason to lose the error it came with.

    CallReply::ok

    The reply messages of a call that ended OK. Any other status is raised as a StatusError with the server's message; a 200 that ended without a grpc-status is INTERNAL, as grpc-go reports it.

    CallReply::one

    The one reply message of a unary or client-streaming call that ended OK. None or more than one is INTERNAL, with grpc-go's cardinality messages.

    CallReply::replies

    ok(), decoded: the replies of a server-streaming or bidirectional call.

    CallReply::reply

    one(), decoded: the reply of a unary or client-streaming call.

    ClientCall

    pub(all) struct ClientCall {
    id : Int
    path : Bytes
    authority : Bytes
    metadata : Array[
    Header
    ]
    timeout : Bytes?
    out : Bytes
    out_off : Int
    req_ended : Bool
    req_headers_sent : Bool
    req_fin_sent : Bool
    send_window : Int
    data :
    Buffer

    data_off : Int
    messages : Array[Bytes]
    recv_window : Int
    status : Bytes
    grpc_status : Int?
    grpc_message : String
    resp_encoding : Bytes
    resp_headers : Array[
    Header
    ]
    resp_trailers : Array[
    Header
    ]
    headers_seen : Bool
    header_block :
    Buffer

    in_headers : Bool
    pending_end_stream : Bool
    decode_failed : Bool
    unprocessed : Bool
    committed : Bool
    done : Bool
    }

    One client-side call: its stream id, the request side (the length-prefixed request body still to send, the send window, and whether the request has been half-closed), and the response side (the accumulating DATA with a cursor over the messages already pulled out, the recv window, the captured :status and grpc-status, and the response initial and trailing metadata).

    H2Client

    pub struct H2Client {
    encoder :
    Encoder

    decoder :
    Decoder

    calls : Map[Int, ClientCall]
    next_id : Int
    conn_send_window : Int
    conn_recv_window : Int
    remote_initial_window : Int
    remote_max_frame : Int
    goaway_received : Bool
    goaway_last_stream_id : Int
    encoding :
    Encoding

    user_agent : Bytes
    max_recv : Int
    max_send : Int
    size_update : Int?
    orphan_blocks : Map[Int,
    Buffer
    ]
    }

    The client side of one HTTP/2 connection: the HPACK codec pair (stateful across every call on the connection), the live calls keyed by stream id, the next odd stream id to allocate (§5.1.1), and the connection-level flow-control state bounded by the peer's SETTINGS.

    H2Client::close_send

    fn H2Client::close_send(self : H2Client, id : Int) -> Array[
    Frame
    ]

    Half-close the request side of a call (no more request messages) and return any frames that completes — the trailing END_STREAM.

    H2Client::feed

    Feed one decoded response frame to the engine, advancing all state and returning the frames to write back (SETTINGS ack, PING pong, WINDOW_UPDATE replenishing a receive window, and — once a WINDOW_UPDATE lifts back-pressure — any remaining request DATA). Captures :status, grpc-status, response metadata, and the reassembled reply messages.

    H2Client::goaway_last_stream_id

    fn H2Client::goaway_last_stream_id(self : H2Client) -> Int

    The peer's last processed stream id from its GOAWAY (0 if none was seen); a call whose stream id is above it was never handled by the server.

    H2Client::goaway_received

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

    Whether the peer has sent GOAWAY; a draining connection opens no new stream, so the driver picks a fresh one for further calls. Mirrors H2Server::goaway_received.

    H2Client::has_messages

    fn H2Client::has_messages(self : H2Client, id : Int) -> Bool

    Whether a call has reply messages buffered but not yet taken — for reading a streaming response incrementally as it arrives, rather than all at once via reply.

    H2Client::is_done

    fn H2Client::is_done(self : H2Client, id : Int) -> Bool

    Whether a call has fully completed (its response ended). An unknown id counts as done so a driver loop terminates.

    H2Client::new

    fn H2Client::new() -> H2Client

    A fresh client engine with no live calls. The first call takes stream id 1.

    H2Client::open

    fn H2Client::open(self : H2Client, path : String, metadata? : Array[
    Header
    ], authority? : String, timeout_millis? : Int) -> Int

    Open a new call on this connection for path (/pkg.Service/Method), returning its freshly allocated stream id. metadata is sent as custom request HEADERS; timeout_millis, when set, becomes the grpc-timeout header. The request body is added with send and half-closed with close_send.

    H2Client::preface

    The client's opening frames (RFC 7540 §3.5): a SETTINGS frame disabling server push. Written right after the 24-octet connection @http2.preface bytes, before any request.

    H2Client::release

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

    Drop everything the engine still holds for a finished call: its buffered body, messages, header block and trailers. 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 made, and every WINDOW_UPDATE and SETTINGS frame would walk that whole history. An unknown or already-released id is a no-op.

    H2Client::reply

    fn H2Client::reply(self : H2Client, id : Int) -> CallReply

    The completed result of a call. Meaningful once is_done is true.

    H2Client::send

    fn H2Client::send(self : H2Client, id : Int, message : Bytes, end? : Bool) -> Array[
    Frame
    ]

    Append one request message to a call and return the frames to write now (the request HEADERS the first time, then as much length-prefixed DATA as the send windows allow). Set end on the last message to half-close the request.

    H2Client::set_encoding

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

    Compress request messages with encoding, and name it in grpc-encoding. Replies are decoded in whatever encoding the server names, whichever this is.

    H2Client::set_max_message_size

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

    Cap the messages this client will accept and send, in octets. A larger incoming message ends its call with RESOURCE_EXHAUSTED rather than pinning the memory it declares; a larger outgoing one raises Refused from send instead of going out.

    H2Client::set_user_agent

    fn H2Client::set_user_agent(self : H2Client, user_agent : String) -> Unit

    What this client calls itself in user-agent — moonrpc/<version> unless a caller has an application name of its own to add.

    H2Client::take_messages

    fn H2Client::take_messages(self : H2Client, id : Int) -> Array[Bytes]

    Take every reply message received so far, clearing the call's buffer — the incremental counterpart to reply, for a server- or bidi-streaming response read message by message.

    H2Client::unary

    fn H2Client::unary(self : H2Client, path : String, request : Bytes, metadata? : Array[
    Header
    ], authority? : String, timeout_millis? : Int) -> (Int, Array[
    Frame
    ])

    Open a unary call and return (stream_id, frames_to_write) in one step: the request HEADERS and the single length-prefixed request message with END_STREAM.

    H2Client::unprocessed

    fn H2Client::unprocessed(self : H2Client, id : Int) -> Bool

    Whether call id never reached the server's application: its stream was refused, or its id is above the last one a GOAWAY says was processed (gRPC A6, RFC 9113 §6.8). Such a call is safe to send again. False for a call that may have been processed.

    Invocation

    pub(all) struct Invocation {
    path : String
    requests : Array[Bytes]
    metadata : Array[
    Header
    ]
    timeout_millis : Int?
    retry :
    Retry
    ?
    }

    One call as an interceptor sees it: the method, the request messages it carries, the metadata it goes out with, its deadline in milliseconds and its retry policy.

    encode_grpc_timeout

    fn encode_grpc_timeout(millis : Int) -> Bytes

    Encode whole millis as a grpc-timeout header value (RFC gRPC HTTP/2 mapping): the m (millisecond) unit when the count fits the 8-digit field, else seconds with the S unit.

    intercepted

    fn intercepted(chain : Array[async (Invocation, async (Invocation) -> CallReply) -> CallReply], base : async (Invocation) -> CallReply) -> (async (Invocation) -> CallReply)

    Fold chain around base so the first interceptor is the outermost. With an empty chain this is base unchanged.

    percent_decode

    fn percent_decode(v : Bytes) -> String

    Percent-decode a received grpc-message value — the inverse of the server's percent_encode (gRPC spec §"Responses"): each %XX escape becomes the byte its two hex digits name, every other byte passes through, and a malformed escape is left literal; the result is read as UTF-8.

    user_agent

    let user_agent : String

    What this client calls itself in user-agent unless told otherwise: the library and the version this source is, which is what a server's access log wants to know.

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io