Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

rpc.transport

import rpc

Everything here is re-exported by rpc, so import rpc is enough and the names are called as rpc.*. Importing rpc.transport on its own works too and reaches the same definitions.

Where an endpoint’s bytes come from and go to. A transport is any object with three methods:

  • read(max) returns the next bytes that arrive, at most max of them, waiting until at least one does. It returns empty bytes once the stream has ended.
  • write(data) sends all of data, a bytes.
  • close() ends the stream in the direction it writes.

A transport may also have can_listen(), true when another isolate can read it while the one that made it writes to it, which Endpoint.listen() relies on. Without the method, it is false. And a transport that keeps messages apart itself has framing(), returning the framing an endpoint over it uses unless told otherwise.

StdioTransport talks over the program’s own standard input and output, SocketTransport over a connected socket, ProcessTransport over the standard input and output of a child process, WebSocketTransport over a WebSocket, and ChannelTransport over isolate channels, two of which pipe() joins into a connection between isolates. Any other object with the three methods works the same.

Re-exported by rpc.

Functions

pipe()

rpc.pipe() -> list[ChannelTransport]:

Two ChannelTransports joined to each other: what one writes, the other reads. Hand one end to another isolate and the two can talk JSON-RPC across the isolate boundary.

import rpc

var ends = rpc.pipe()

ends[0].write('ping'.to_bytes())
echo ends[1].read(4096).to_string()  # ping

Returns list[ChannelTransport]: — The two ends.

Classes

StdioTransport

class rpc.StdioTransport

Talks over the program’s own standard input and output: what it reads arrives on stdin, and what it writes goes to stdout. This is the transport of a program that another one starts and talks to.

Every write is flushed at once. Anything else the program prints to stdout lands in the middle of the stream, so a program serving over stdio writes everything else to stderr.

  • printable — has a @to_string(), so echo and print() show something useful

Constructor

rpc.StdioTransport()

Returns a new StdioTransport.

StdioTransport.read()

rpc.StdioTransport.read(max: int) -> bytes

The next bytes on stdin, at most max of them, or empty bytes once stdin has ended.

Parameters

  • max (int)

Returns bytes

StdioTransport.write()

rpc.StdioTransport.write(data: bytes)

Writes data to stdout and flushes it.

Parameters

  • data (bytes)

StdioTransport.close()

rpc.StdioTransport.close()

Flushes stdout. The program’s standard streams stay open.

StdioTransport.can_listen()

rpc.StdioTransport.can_listen() -> bool

True: every isolate reads the same stdin, so one can read it while another writes.

Returns bool

StdioTransport.to_string()

rpc.StdioTransport.to_string() -> string

This transport as StdioTransport().

Returns string

SocketTransport

class rpc.SocketTransport

Talks over a connected stream from net: a TcpStream, a UnixStream or a TlsStream, or anything else with read(), write_all() and close().

A socket is held by one isolate at a time, so an endpoint serving one reads it with serve() rather than listen().

  • printable — has a @to_string(), so echo and print() show something useful

Constructor

rpc.SocketTransport(socket)

Returns a new SocketTransport over socket.

Parameters

  • socket (any) — A connected socket.

SocketTransport.read()

rpc.SocketTransport.read(max: int) -> bytes

The next bytes from the socket, at most max of them, or empty bytes once the other side has closed its end.

Parameters

  • max (int)

Returns bytes

Raises Error when the socket fails, or its read timeout runs out.

SocketTransport.write()

rpc.SocketTransport.write(data: bytes)

Writes all of data to the socket.

Parameters

  • data (bytes)

Raises Error when the socket fails.

SocketTransport.close()

rpc.SocketTransport.close()

Closes the socket.

SocketTransport.can_listen()

rpc.SocketTransport.can_listen() -> bool

False: a socket is held by one isolate at a time.

Returns bool

SocketTransport.to_string()

rpc.SocketTransport.to_string() -> string

This transport as SocketTransport().

Returns string

ProcessTransport

class rpc.ProcessTransport

Talks to a child process over its standard input and output, from os.spawn() with stdin and stdout both 'pipe': what the child prints is read, and what is written goes to its stdin.

import os
import rpc

var child = os.spawn('zuri', ['run', 'calculator.zu'], {
  stdin: 'pipe',
  stdout: 'pipe'
})
var calculator = rpc.endpoint(rpc.process(child))

echo calculator.request('add', [2, 3])

The child’s streams are held by the isolate that spawned it, so an endpoint talking to it reads with serve() and request() rather than listen().

  • printable — has a @to_string(), so echo and print() show something useful

Constructor

rpc.ProcessTransport(process)

Returns a new ProcessTransport over process.

Parameters

  • process (os.Process) — A child whose stdin and stdout are pipes.

ProcessTransport.read()

rpc.ProcessTransport.read(max: int) -> bytes

The next bytes the child printed, at most max of them, or empty bytes once its stdout has ended.

Parameters

  • max (int)

Returns bytes

ProcessTransport.write()

rpc.ProcessTransport.write(data: bytes)

Writes all of data to the child’s stdin.

Parameters

  • data (bytes)

ProcessTransport.close()

rpc.ProcessTransport.close()

Closes the child’s stdin, so it reads the end of its input. The child itself keeps running until it exits.

ProcessTransport.can_listen()

rpc.ProcessTransport.can_listen() -> bool

False: a child process is read by the isolate that spawned it.

Returns bool

ProcessTransport.to_string()

rpc.ProcessTransport.to_string() -> string

This transport as ProcessTransport().

Returns string

WebSocketTransport

class rpc.WebSocketTransport

Talks over a WebSocket from http.websocket, on either end of it: one websocket.accept() returned in a route handler, or one websocket.connect() opened. Each message is one WebSocket message, sent as text, so an endpoint over it uses a MessageFraming.

import http.websocket
import rpc

var node = rpc.endpoint(rpc.websocket(websocket.connect('ws://127.0.0.1:8546')))

echo node.request('eth_blockNumber', [])

A WebSocket is held by one isolate at a time, so an endpoint over one reads with serve() and request() rather than listen().

  • printable — has a @to_string(), so echo and print() show something useful

Constructor

rpc.WebSocketTransport(socket)

Returns a new WebSocketTransport over socket.

Parameters

  • socket (http.websocket.WebSocket) — An open WebSocket.

WebSocketTransport.read()

rpc.WebSocketTransport.read(max: int) -> bytes

The next message that arrives, as its bytes, or empty bytes once the connection has closed. An empty message is skipped, since it holds no JSON-RPC message.

Parameters

  • max (int) — Ignored; each read returns one message whole.

Returns bytes

WebSocketTransport.write()

rpc.WebSocketTransport.write(data: bytes)

Sends data as one text message.

Parameters

  • data (bytes) — One message’s UTF-8 text.

WebSocketTransport.close()

rpc.WebSocketTransport.close()

Closes the WebSocket, with the closing handshake.

WebSocketTransport.can_listen()

rpc.WebSocketTransport.can_listen() -> bool

False: a WebSocket is held by one isolate at a time.

Returns bool

WebSocketTransport.framing()

rpc.WebSocketTransport.framing() -> MessageFraming

A MessageFraming: a WebSocket keeps messages apart itself.

Returns MessageFraming

WebSocketTransport.to_string()

rpc.WebSocketTransport.to_string() -> string

This transport as WebSocketTransport().

Returns string

ChannelTransport

class rpc.ChannelTransport

Talks over two isolate channels: what it reads arrives on inbox and what it writes goes to outbox. Channels cross isolates, so a ChannelTransport can be handed to another isolate and talk to it from there; pipe() makes the two ends of such a connection.

  • printable — has a @to_string(), so echo and print() show something useful

Constructor

rpc.ChannelTransport(inbox, outbox)

Returns a new ChannelTransport.

Parameters

  • inbox (isolate.Channel) — Where the bytes it reads arrive.
  • outbox (isolate.Channel) — Where the bytes it writes go.

ChannelTransport.read()

rpc.ChannelTransport.read(max: int) -> bytes

The next bytes sent to this end, whatever their length, or empty bytes once the other end has closed.

Parameters

  • max (int) — Ignored; each read returns one write from the other end whole.

Returns bytes

ChannelTransport.write()

rpc.ChannelTransport.write(data: bytes)

Sends data to the other end.

Parameters

  • data (bytes)

Raises RpcClosedError when this end has been closed.

ChannelTransport.close()

rpc.ChannelTransport.close()

Closes this end, so the other end reads the end of its input.

ChannelTransport.can_listen()

rpc.ChannelTransport.can_listen() -> bool

True: channels are shared between isolates, so one can read this end while another writes to it.

Returns bool

ChannelTransport.to_string()

rpc.ChannelTransport.to_string() -> string

This transport as ChannelTransport().

Returns string


2026, Richard Ore and Zuri contributors