NURLNURL registrynurl-lang.org →

← grpc

grpc 0.2.1 API

metadata.nu

Metadata uses Vec[Header]. Application -bin values are raw, binary-safe Strings; wire conversion performs Base64 and preserves duplicate order.

API

@ grpc_metadata_new → ( Vec Header )

@ grpc_metadata_free sink ( Vec Header ) metadata → v

Let go of metadata now rather than at the end of its owner's scope.

@ grpc_header_clone Header header → Header

@ grpc_metadata_clone ( Vec Header ) headers → ( Vec Header )

@ grpc_metadata_key String key → b

@ grpc_metadata_reserved String key → b

@ grpc_metadata_ascii String value → b

@ grpc_metadata_add ( Vec Header ) metadata s key s value → !v GrpcError

@ grpc_metadata_add_binary ( Vec Header ) metadata s key ( Vec u ) value → !v GrpcError

@ grpc_request_headers_check_size ( Vec Header ) headers s scheme s authority s path i limit → !v GrpcError

The HTTP/2 client adds these four pseudoheaders when opening a POST stream. Include their decoded sizes in the same budget as application metadata.

@ grpc_message_encode String message → String

@ grpc_message_decode String message → String

Malformed percent escapes are preserved as required by the wire protocol.

: GrpcStatus { i code String message ( Vec u ) details }

@ grpc_status i code s message → GrpcStatus

@ grpc_status_free sink GrpcStatus status → v

Let go of status now rather than at the end of its owner's scope.

@ grpc_status_parse ( Vec Header ) headers → !GrpcStatus GrpcError

headers must be the final trailer block, or END_STREAM initial headers for a trailers-only response. The transport decides which block is final.

@ grpc_status_headers GrpcStatus status ( Vec Header ) metadata i limit → !( Vec Header ) GrpcError


grpc.nu

Public facade. Import client.nu or server.nu separately for a smaller API.


server.nu

Incremental gRPC server. A GrpcServer owns protocol state, never its TcpConn. Its owner's drop releases it (a final best-effort flush of the HTTP/2 connection, then every call); nothing here is released by hand — grpc_server_free and the *_free functions are optional early releases. Unary, client streaming, server streaming, and bidirectional calls share this event API. send accepts one complete message into a bounded queue; flush writes only available HTTP/2 credit and next services the peer.

API

: GrpcServerLimits

: GrpcServerLimits {
    i max_message
    i max_buffer
    i max_metadata
    i max_calls
    i max_connection_buffer
    i idle_timeout_ns
}

@ grpc_server_limits → GrpcServerLimits

: GrpcServerCall

: GrpcServerCall {
    i stream_id
    String method
    GrpcDecoder decoder
    i deadline_ns
    b input_ended
    b end_notified
    b headers_sent
    b output_finished
    b cancelled
    b accepts_gzip
    i output_encoding
    ( Vec u ) outgoing
    i outgoing_pos
    ( Vec Header ) trailers
    b finish_requested
    ( Vec Header ) request_trailers
}

: GrpcServer

: GrpcServer {
    H2Connection transport
    GrpcServerLimits limits
    ( Vec GrpcServerCall ) calls
    i cursor
    b closed
}

: GrpcServerEvent

: GrpcServerEvent {
    i kind
    i stream_id
    String method
    ( Vec Header ) metadata
    ( Vec u ) message
    i code
}

@ grpc_server_event_control → i

@ grpc_server_event_open → i

@ grpc_server_event_message → i

@ grpc_server_event_half_close → i

@ grpc_server_event_cancelled → i

@ grpc_server_event_closed → i

@ grpc_server_event_free sink GrpcServerEvent event → v

Let go of event now rather than at the end of its owner's scope.

% Drop GrpcServer { @ drop GrpcServer server → v { ( h2_conn_free . server transport ) } }

The connection's last frames are flushed (best effort) and its state released; the calls go with the drop glue.

@ grpc_server_free sink GrpcServer server → v

Let go of server now rather than at the end of its owner's scope.

@ grpc_server_deadline GrpcServer server i sid → !i GrpcError

@ grpc_server_is_cancelled GrpcServer server i sid → b

@ grpc_server_new TcpConn conn GrpcServerLimits limits → !GrpcServer GrpcError

@ grpc_server_send_metadata inout GrpcServer server i sid ( Vec Header ) metadata i encoding → !v GrpcError

@ grpc_server_send inout GrpcServer server i sid ( Vec u ) message → !v GrpcError

Success means the message was accepted. The caller keeps its input; the server owns the encoded frame until all bytes have reached the peer.

@ grpc_server_finish inout GrpcServer server i sid GrpcStatus status ( Vec Header ) metadata → !v GrpcError

@ grpc_server_next inout GrpcServer server → !GrpcServerEvent GrpcError

@ grpc_server_next_until inout GrpcServer server i poll_deadline_ns → !GrpcServerEvent GrpcError

Application timers can wake an idle connection without cancelling its RPCs. An expired poll deadline returns control; RPC deadlines still produce cancelled events and terminal status. Zero uses the ordinary idle bound.


wire.nu

gRPC message framing and protocol values. Inputs are borrowed; returned buffers and GrpcError messages are owned. No protobuf schema is assumed.

API

: i GRPC_OK 0

: i GRPC_CANCELLED 1

: i GRPC_UNKNOWN 2

: i GRPC_INVALID_ARGUMENT 3

: i GRPC_DEADLINE_EXCEEDED 4

: i GRPC_NOT_FOUND 5

: i GRPC_ALREADY_EXISTS 6

: i GRPC_PERMISSION_DENIED 7

: i GRPC_RESOURCE_EXHAUSTED 8

: i GRPC_FAILED_PRECONDITION 9

: i GRPC_ABORTED 10

: i GRPC_OUT_OF_RANGE 11

: i GRPC_UNIMPLEMENTED 12

: i GRPC_INTERNAL 13

: i GRPC_UNAVAILABLE 14

: i GRPC_DATA_LOSS 15

: i GRPC_UNAUTHENTICATED 16

: i GRPC_IDENTITY 0

: i GRPC_GZIP 1

: i GRPC_DEFAULT_MAX_MESSAGE 4194304

: i GRPC_DEFAULT_MAX_METADATA 8192

: GrpcError { i code String message }

@ grpc_error i code s message → GrpcError

@ grpc_error_free sink GrpcError e → v

Let go of e now rather than at the end of its owner's scope.

@ grpc_code_name i code → s

@ grpc_http_status i status → i

@ grpc_reset_status i code → i

@ grpc_encoding_name i encoding → s

@ grpc_encoding s name → !i GrpcError

@ grpc_content_type String value → b

@ grpc_timeout_ns String value → !i GrpcError

Timeout parsing is strict, uses every defined unit, and saturates instead of overflowing for the protocol's largest (99,999,999 hour) duration.

@ grpc_timeout_value i duration_ns → String

Round up so the wire timeout never expires before the caller's duration.

@ grpc_deadline_after i now_ns i duration_ns → i

@ grpc_frame ( Vec u ) message i encoding i max_message → !( Vec u ) GrpcError

Both compressed and uncompressed sizes are bounded. Each message gets its own compression context, including the empty protobuf message.

: GrpcMessage { b present ( Vec u ) data }

: GrpcDecoder { ( Vec u ) pending i pos i max_message i max_buffer i encoding }

@ grpc_message_free sink GrpcMessage message → v

Let go of message now rather than at the end of its owner's scope.

@ grpc_decoder i max_message i max_buffer i encoding → !GrpcDecoder GrpcError

@ grpc_decoder_free sink GrpcDecoder d → v

Let go of d now rather than at the end of its owner's scope.

@ grpc_decoder_feed inout GrpcDecoder d ( Vec u ) bytes → !v GrpcError

Atomic on error. Call next repeatedly after each feed until present=false.

@ grpc_decoder_finish GrpcDecoder d → !v GrpcError

Called after draining messages when the HTTP/2 receive side ends.


client.nu

HTTP/2-backed gRPC calls. A client and all its calls have one owner/driver. A GrpcClient is a handle: every copy is the same client, and each call holds one, so the transport outlives every call on it. The last owner disconnects a transport the client opened (grpc_client_connect_); one it was lent (grpc_client_from_h2) stays its owner's. A GrpcCall is released by its owner's drop, which cancels an unfinished call. Nothing here is released by hand: grpc_client_close / grpc_call_free / the _free functions are optional early releases. Sending borrows protobuf bytes. Receiving transfers an owned GrpcMessage.

API

: GrpcClientImpl { H2Client transport String scheme String authority b owns_transport }

% Drop GrpcClientImpl

% Drop GrpcClientImpl {
    @ drop GrpcClientImpl c → v { ? . c owns_transport { ( h2_client_disconnect . c transport ) } {} }
}

A transport the client opened is disconnected with it; a lent one stays connected for whoever lent it. The fields (the transport handle, the strings) go with the value.

: GrpcClient { s ctl }

@ GrpcClient_drop sink GrpcClient h → v

: GrpcCallOptions { i timeout_ns i max_send_message i max_recv_message i max_metadata i encoding }

: GrpcCall

: GrpcCall {
    GrpcClient client  // a share: the transport stays up while the call lives
    i stream_id
    GrpcDecoder decoder
    i max_send_message
    i max_metadata
    i encoding
    b response_checked
    b status_checked
    GrpcStatus status
    ( Vec Header ) headers
    ( Vec Header ) trailers
}

: GrpcUnaryResponse { ( Vec u ) data ( Vec Header ) headers ( Vec Header ) trailers GrpcStatus status }

@ grpc_call_options → GrpcCallOptions

@ grpc_client_connect_h2c s host i port → !GrpcClient GrpcError

@ grpc_client_connect_tls s host i port b verify → !GrpcClient GrpcError

@ grpc_client_close sink GrpcClient client → v

Let go of client now rather than at the end of its owner's scope (the transport closes when the last call on it is gone too).

@ grpc_call_free sink GrpcCall call → v

Let go of call now rather than at the end of its owner's scope.

% Drop GrpcCall

% Drop GrpcCall {
    unsafe @ drop GrpcCall call → v {
        : *GrpcClientImpl cl ( __GrpcClient_ptr . call client )
        ?? ( h2_client_cancel . cl transport . call stream_id ( h2_err_cancel ) ) { T _ → {} F _ → {} }
        ?? ( h2_client_release_stream . cl transport . call stream_id ) { T _ → {} F _ → {} }
    }
}

Always cancels unfinished calls so application early-return releases the peer's stream resources; the decoder, the metadata and the call's share of its client go with the drop glue.

@ grpc_unary_response_free sink GrpcUnaryResponse response → v

Let go of response now rather than at the end of its owner's scope.

@ grpc_unary GrpcClient client s path ( Vec u ) request ( Vec Header ) metadata GrpcCallOptions opts → !GrpcUnaryResponse GrpcError