Standard library · Network

rpc

JSON-RPC 2.0 and MessagePack-RPC: a server, a client and registering methods.

import rpc

With a remote procedure call one program calls another program's methods as if they were its own routines. On the server side you tie each method to a routine with Register; that routine takes the call's number, reads the parameters with CallParamInt and the like, and answers with Reply... or Fail.

The messages are exchanged with the JSON codec (JSON-RPC 2.0) or MessagePack, and over TCP they are separated by one of three framings, line, header (like LSP) or length prefixed; the client and the server must have the same framing. HandleText does the same thing without a network, so you can put RPC behind an net/http route.

Types

Server

struct Server
An RPC server.
NameTypeDescription
portint = 0The port; zero means a free port.
codecint = 0The codec.
framingint = 0The framing.
listen_fdi64 = -1The listening socket.
runningbool = falseIt is running.
servedint = 0The number of connections answered.
rpc-Serve.salam
import rpc
import net.tcp
import compress

func echo(c: i64):
    rpc.Reply(c, rpc.CallParams(c))
end

func main:
    rpc.Register("echo", echo)
    if rpc.HandleText("").len() == 0:
        _ := rpc.ServeStdio(rpc.RPC_FRAME_HEADER)
        ret
    end

    mut s := rpc.NewServer(4000, rpc.RPC_CODEC_MSGPACK)
    rpc.SetFraming(s, rpc.RPC_FRAME_LENGTH)
    if rpc.Listen(s):
        println "on port", rpc.Port(s), s.running
        rpc.Serve(s)
    end

    conn := tcp.Dial("127.0.0.1", 4001)
    _ := rpc.ServeConn(conn.fd, rpc.RPC_CODEC_JSON, rpc.RPC_FRAME_LINE)

    c := tcp.Dial("127.0.0.1", 4002)
    mut client := rpc.ClientFromFd(c.fd, rpc.RPC_CODEC_JSON)
    println rpc.ResultStr(rpc.CallNoParams(client, "version"))

    mut stream := rpc.NewStream(c.fd)
    _ := rpc.WriteFrameStr(c.fd, rpc.RPC_FRAME_LINE, `{"jsonrpc":"2.0","method":"echo","params":[1],"id":1}`)
    _ := rpc.WriteFrame(c.fd, rpc.RPC_FRAME_LINE, compress.BufFromStr(`{"jsonrpc":"2.0","method":"echo","id":2}`))
    mut ok := false
    println rpc.ReadFrameStr(stream, rpc.RPC_FRAME_LINE, ok)
    answer := rpc.HandlePayload(rpc.RPC_CODEC_JSON, compress.BufFromStr(`{"jsonrpc":"2.0","method":"echo","params":[3],"id":3}`))
    println compress.BufToStrUnsafe(answer)
    rpc.FreeStream(stream)
    rpc.StopServer(s)
end

Stream

struct Stream
The input stream that separates the frames from a socket or from memory.
NameTypeDescription
fdi64 = -1The socket.
datacompress.ByteBufThe data read.
posint = 0The read position.
closedbool = falseThe input is finished.
has_fdbool = falseIt is over a socket.
rpc-Frames.salam
import rpc
import compress

func main:
    line := rpc.FrameEncodeStr(rpc.RPC_FRAME_LINE, `{"a":1}`)
    headed := rpc.FrameEncodeStr(rpc.RPC_FRAME_HEADER, `{"b":2}`)
    sized := rpc.FrameEncode(rpc.RPC_FRAME_LENGTH, compress.BufFromStr(`{"c":3}`))
    println line.len, headed.len, sized.len
    println compress.BufToStrUnsafe(headed).len() > 0

    mut s := rpc.NewMemStream()
    rpc.FeedStr(s, `{"x":1}` + "\n" + `{"x":2}` + "\n")
    mut ok := false
    println rpc.ReadFrameStr(s, rpc.RPC_FRAME_LINE, ok), ok
    println rpc.StreamPending(s)
    println rpc.ReadFrameStr(s, rpc.RPC_FRAME_LINE, ok)
    _ := rpc.ReadFrameStr(s, rpc.RPC_FRAME_LINE, ok)
    println ok, rpc.StreamClosed(s)

    mut s2 := rpc.NewMemStream()
    rpc.FeedBuf(s2, headed)
    rpc.FeedBuf(s2, sized)
    println rpc.ReadFrameStr(s2, rpc.RPC_FRAME_HEADER, ok)
    b := rpc.ReadFrame(s2, rpc.RPC_FRAME_LENGTH, ok)
    println compress.BufToStrUnsafe(b), ok
    println rpc.RPC_READ_CHUNK, rpc.RPC_MAX_FRAME
    rpc.FreeStream(s)
    rpc.FreeStream(s2)
end
Output8 28 11 true {"x":1} true 8 {"x":2} false false {"b":2} {"c":3} true 4096 33554432

Client

struct Client
An RPC client over a TCP connection.
NameTypeDescription
conntcp.ConnThe connection.
streamStreamThe reading stream.
codecint = 0The codec.
framingint = 0The framing.
next_idi64 = 1The next request id.
okbool = falseIt is healthy.
last_errorstr = ""The last error.
rpc-Client.salam
import rpc
import encoding.value
import net.http
import net.router
import sync

mut server := rpc.NewServer(0, rpc.RPC_CODEC_JSON)
mut ready := sync.NewWaitGroup()

func add(c: i64):
    rpc.ReplyInt(c, rpc.CallParamInt(c, "a", 0) + rpc.CallParamInt(c, "b", 1))
end

func clock(c: i64):
    rpc.ReplyStr(c, "12:00")
end

func note(c: i64):
    rpc.ReplyNull(c)
end

func run_server():
    _ := rpc.Listen(server)
    sync.Done(ready)
    _ := rpc.ServeCount(server, 1)
end

func endpoint(ctx: i64):
    http.Ctx_json(ctx, rpc.HandleText(http.Ctx_body(ctx)))
end

func main:
    rpc.Register("add", add)
    rpc.Register("time", clock)
    rpc.Register("note", note)
    rpc.SetFraming(server, rpc.RPC_FRAME_LINE)
    sync.Add(ready, 1)
    t := spawn(run_server)
    sync.Wait(ready)
    println rpc.Port(server) > 0

    mut client := rpc.DialClient("127.0.0.1", rpc.Port(server), rpc.RPC_CODEC_JSON)
    rpc.ClientSetFraming(client, rpc.RPC_FRAME_LINE)
    println rpc.ClientOk(client)
    mut params := value.NewValueArray()
    value.ArrayPush(params, value.ValueInt(2))
    value.ArrayPush(params, value.ValueInt(40))
    println rpc.ResultInt(rpc.Call(client, "add", params))
    println rpc.ResultStr(rpc.CallNoParams(client, "time"))
    mut args := Vector {} as Vector<value.Value>
    args.push(value.ValueInt(1))
    args.push(value.ValueInt(2))
    println rpc.ResultInt(rpc.CallArgs(client, "add", args))
    println rpc.Notify(client, "note", value.NewValueArray())
    mut batch := Vector {} as Vector<rpc.Request>
    batch.push(rpc.NewRequest("add", params, 10))
    batch.push(rpc.NewRequest("missing", value.NewValueArray(), 11))
    answers := rpc.CallBatch(client, batch)
    println answers.items.len(), rpc.ResultInt(answers.items[0])
    println rpc.IsErrorResponse(answers.items[1]), rpc.ErrorCode(answers.items[1]), rpc.ErrorMessage(answers.items[1])
    rpc.CloseClient(client)
    println rpc.ClientOk(client), rpc.ClientError(client).len() >= 0
    join(t)
    rpc.StopServer(server)

    mut r := router.NewRouter()
    router.Post(r, "/rpc", endpoint)
    mut s := http.NewServer(19631)
    http.Use(s, r)
    _ := http.RunBackground(s)
    answer := rpc.CallHTTP("http://127.0.0.1:19631/rpc", "add", params, 7)
    println rpc.ResultInt(answer)
end
Outputtrue true 42 12:00 3 true 2 42 true -32601 Method not found false true 42

Error

struct Error
A JSON-RPC error.
NameTypeDescription
codeint = 0The code.
messagestr = ""The message.
datavalue.ValueThe extra data.
has_databool = falseIt has data.
rpc-Messages.salam
import rpc
import encoding.value
import compress

func main:
    mut params := value.NewValueArray()
    value.ArrayPush(params, value.ValueInt(2))
    value.ArrayPush(params, value.ValueString("hello"))
    value.ArrayPush(params, value.ValueFloat(1.5))
    value.ArrayPush(params, value.ValueBool(true))
    req := rpc.NewRequest("calc", params, 1)
    println rpc.JsonEncodeRequest(req)
    println rpc.ParamCount(req), rpc.ParamInt(req, "a", 0), rpc.ParamStr(req, "b", 1)
    println rpc.ParamFloat(req, "c", 2), rpc.ParamBool(req, "d", 3), rpc.HasParam(req, "e", 4)
    println value.AsInt(rpc.ParamAt(req, 0)), value.AsInt(rpc.Param(req, "a", 0))
    mut obj := value.NewValueObject()
    value.ObjectSet(obj, "name", value.ValueString("Ali"))
    req2 := rpc.NewRequestStrId("greet", obj, "req-1")
    println rpc.JsonEncodeRequest(req2)
    println value.AsString(rpc.ParamNamed(req2, "name"))
    note := rpc.NewNotification("tick", value.NewValueArray())
    println rpc.IsNotification(note), rpc.JsonEncodeRequest(note)

    mut ok := false
    read := rpc.JsonDecodeRequest(`{"jsonrpc":"2.0","method":"add","params":{"a":1,"b":2},"id":9}`, ok)
    println ok, read.method, read.msgid, rpc.ParamInt(read, "b", 1)

    answer := rpc.NewResponse(value.ValueInt(1), value.ValueString("ok"))
    println rpc.JsonEncodeResponse(answer)
    err := rpc.StdError(rpc.RPC_METHOD_NOT_FOUND)
    println err.code, err.message
    println rpc.JsonEncodeResponse(rpc.NewErrorResponse(value.ValueInt(2), rpc.NewError(-32000, "the server is busy")))
    with_data := rpc.ErrorWithData(rpc.RPC_INVALID_PARAMS, "bad", value.ValueString("x"))
    println with_data.has_data, rpc.JsonTopLevelError(rpc.StdError(rpc.RPC_PARSE_ERROR))

    one := rpc.JsonDecodeResponse(`{"jsonrpc":"2.0","result":3.5,"id":1}`, ok)
    println ok, rpc.ResultFloat(one), rpc.IsErrorResponse(one)
    two := rpc.JsonDecodeResponse(`{"jsonrpc":"2.0","error":{"code":-32601,"message":"nope"},"id":2}`, ok)
    println rpc.IsErrorResponse(two), rpc.ErrorCode(two), rpc.ErrorMessage(two)
    all := rpc.JsonDecodeResponses(`[{"jsonrpc":"2.0","result":true,"id":1},{"jsonrpc":"2.0","result":"x","id":2}]`, ok)
    println all.is_batch, all.items.len(), rpc.ResultBool(all.items[0]), rpc.ResultStr(all.items[1])
    println rpc.JsonEncodeResponses(all)

    println rpc.CodecName(rpc.RPC_CODEC_JSON), rpc.CodecName(rpc.RPC_CODEC_MSGPACK)
    println rpc.CodecDefaultFraming(rpc.RPC_CODEC_JSON) == rpc.RPC_FRAME_LINE, rpc.CodecDefaultFraming(rpc.RPC_CODEC_MSGPACK) == rpc.RPC_FRAME_LENGTH
    packed := rpc.EncodeRequest(rpc.RPC_CODEC_MSGPACK, req)
    println packed.len, compress.BufGet(packed, 0)
    batch := rpc.DecodeBatch(rpc.RPC_CODEC_MSGPACK, packed)
    println batch.ok, batch.items[0].method, batch.items[0].msgid
    println rpc.MsgpackDecodeBatch(rpc.MsgpackEncodeRequest(req)).items[0].method
    mp := rpc.MsgpackEncodeResponse(rpc.NewResponse(value.ValueInt(1), value.ValueInt(42)))
    println rpc.ResultInt(rpc.MsgpackDecodeResponse(mp, ok)), ok
    js := rpc.EncodeRequest(rpc.RPC_CODEC_JSON, req)
    println rpc.ResultInt(rpc.DecodeResponse(rpc.RPC_CODEC_MSGPACK, mp, ok)), js.len > 0
    println compress.BufToStrUnsafe(rpc.EncodeResponses(rpc.RPC_CODEC_JSON, all)).len() > 0
    println compress.BufToStrUnsafe(rpc.EncodeTopLevelError(rpc.RPC_CODEC_JSON, err))
    println rpc.RPC_MP_REQUEST, rpc.RPC_MP_RESPONSE, rpc.RPC_MP_NOTIFY
    println rpc.RPC_INVALID_REQUEST, rpc.RPC_INTERNAL_ERROR, rpc.RPC_SERVER_ERROR
    println rpc.RPC_KIND_REQUEST, rpc.RPC_KIND_NOTIFICATION, rpc.RPC_KIND_RESPONSE
    println compress.BufToStrUnsafe(compress.BufFromStr(rpc.JsonEncodeRequest(req))).len() > 0
end
Output{"jsonrpc": "2.0", "id": 1, "method": "calc", "params": [2, "hello", 1.5, true]} 4 2 hello 1.5 true false 2 2 {"jsonrpc": "2.0", "id": "req-1", "method": "greet", "params": {"name": "Ali"}} Ali true {"jsonrpc": "2.0", "method": "tick", "params": []} true add 9 2 {"jsonrpc": "2.0", "id": 1, "result": "ok"} -32601 Method not found {"jsonrpc": "2.0", "error": {"message": "the server is busy", "code": -32000}, "id": 2} true {"jsonrpc": "2.0", "error": {"message": "Parse error", "code": -32700}, "id": null} true 3.5 false true -32601 nope true 2 true x [{"jsonrpc": "2.0", "id": 1, "result": true}, {"jsonrpc": "2.0", "id": 2, "result": "x"}] json-rpc-2.0 msgpack-rpc true true 26 148 true calc 1 calc 42 true 42 true true {"jsonrpc": "2.0", "error": {"message": "Method not found", "code": -32601}, "id": null} 0 1 2 -32600 -32603 -32000 1 2 3 true

Request

struct Request
One request.
NameTypeDescription
methodstr = ""The method name.
paramsvalue.ValueThe parameters: an array or an object.
has_paramsbool = falseIt has parameters.
idvalue.ValueThe id; a number or a string.
has_idbool = falseIt has an id; without one it is a notification.
msgidi64 = 0The numeric id.
err_codeint = 0If the request could not be read, the error code.
err_messagestr = ""That error's message.
rpc-Methods.salam
import rpc
import encoding.value

func add(c: i64):
    a := rpc.CallParamInt(c, "a", 0)
    b := rpc.CallParamInt(c, "b", 1)
    rpc.ReplyInt(c, a + b)
end

func divide(c: i64):
    divisor := rpc.CallParamFloat(c, "b", 1)
    if divisor == 0.0:
        rpc.FailInvalidParams(c, "division by zero")
        ret
    end
    rpc.ReplyFloat(c, rpc.CallParamFloat(c, "a", 0) / divisor)
end

func hello(c: i64):
    name := rpc.CallParamStr(c, "name", 0)
    if name.len() == 0:
        rpc.Fail(c, -32001, "a name is needed")
        ret
    end
    rpc.ReplyStr(c, "hello " + name)
end

func status(c: i64):
    mut info := value.NewValueArray()
    value.ArrayPush(info, value.ValueString(rpc.CallMethodName(c)))
    value.ArrayPush(info, value.ValueInt(rpc.CallParamCount(c)))
    value.ArrayPush(info, value.ValueBool(rpc.CallParamBool(c, "verbose", 0)))
    rpc.Reply(c, info)
end

func log_event(c: i64):
    println "event:", value.AsString(rpc.CallParam(c, "event", 0)), rpc.CallIsNotification(c)
    _ := rpc.CallParams(c)
    _ := rpc.CallRequest(c)
    rpc.ReplyNull(c)
end

func forbidden(c: i64):
    rpc.FailWithData(c, -32003, "you are not allowed", value.ValueString("admin"))
end

func always(c: i64):
    rpc.ReplyBool(c, true)
end

func main:
    rpc.RegisterDoc("add", add, "adds two numbers")
    rpc.Register("divide", divide)
    rpc.Register("hello", hello)
    rpc.Register("status", status)
    rpc.Register("log", log_event)
    rpc.Register("admin", forbidden)
    rpc.Register("ping", always)
    println rpc.MethodCount(), rpc.HasMethod("add"), rpc.MethodDoc("add")
    println rpc.ListMethods().len()

    println rpc.HandleText(`{"jsonrpc":"2.0","method":"add","params":[2,40],"id":1}`)
    println rpc.HandleText(`{"jsonrpc":"2.0","method":"add","params":{"a":5,"b":6},"id":2}`)
    println rpc.HandleText(`{"jsonrpc":"2.0","method":"divide","params":[1,0],"id":3}`)
    println rpc.HandleText(`{"jsonrpc":"2.0","method":"hello","params":["Maryam"],"id":"x"}`)
    println rpc.HandleText(`{"jsonrpc":"2.0","method":"hello","params":[],"id":4}`)
    println rpc.HandleText(`{"jsonrpc":"2.0","method":"status","params":{"verbose":true},"id":5}`)
    println rpc.HandleText(`{"jsonrpc":"2.0","method":"admin","id":6}`)
    println rpc.HandleText(`{"jsonrpc":"2.0","method":"nope","id":7}`)
    println rpc.HandleText(`{"jsonrpc":"2.0","method":"log","params":{"event":"start"}}`).len()
    println rpc.HandleText(`[{"jsonrpc":"2.0","method":"ping","id":8},{"jsonrpc":"2.0","method":"add","params":[1,1],"id":9}]`)
    println rpc.HandleText(`{"jsonrpc":`)

    mut ok := false
    req := rpc.JsonDecodeRequest(`{"jsonrpc":"2.0","method":"add","params":[20,22],"id":10}`, ok)
    answer := rpc.Invoke(req)
    println rpc.ResultInt(answer)
    batch := rpc.JsonDecodeBatch(`[{"jsonrpc":"2.0","method":"ping","id":1}]`)
    println rpc.InvokeBatch(batch).items.len()

    println rpc.Unregister("ping"), rpc.HasMethod("ping")
    rpc.ResetRegistry()
    println rpc.MethodCount()
end
Output7 true adds two numbers 7 {"jsonrpc": "2.0", "id": 1, "result": 42} {"jsonrpc": "2.0", "id": 2, "result": 11} {"jsonrpc": "2.0", "error": {"message": "division by zero", "code": -32602}, "id": 3} {"jsonrpc": "2.0", "id": "x", "result": "hello Maryam"} {"jsonrpc": "2.0", "error": {"message": "a name is needed", "code": -32001}, "id": 4} {"jsonrpc": "2.0", "id": 5, "result": ["status", 1, true]} {"jsonrpc": "2.0", "error": {"message": "you are not allowed", "code": -32003, "data": "admin"}, "id": 6} {"jsonrpc": "2.0", "error": {"message": "Method not found", "code": -32601}, "id": 7} event: start true 0 [{"jsonrpc": "2.0", "id": 8, "result": true}, {"jsonrpc": "2.0", "id": 9, "result": 2}] {"jsonrpc": "2.0", "error": {"message": "Parse error", "code": -32700}, "id": null} 42 1 true false 0

Response

struct Response
One response.
NameTypeDescription
idvalue.ValueThe request's id.
has_idbool = falseIt has an id.
resultvalue.ValueThe result.
is_errorbool = falseIt is an error.
errErrorThe error.
msgidi64 = 0The numeric id.

The example for this item is shown with the ones above: rpc-Methods.salam

Batch

struct Batch
A batch of requests.
NameTypeDescription
itemsVectorThe requests.
is_batchbool = falseIt came in as an array.
okbool = trueIt was read correctly.
errErrorIf it was not, the error.

The example for this item is shown with the ones above: rpc-Methods.salam

Responses

struct Responses
The responses of a batch.
NameTypeDescription
itemsVectorThe responses.
is_batchbool = falseSend it as an array.

The example for this item is shown with the ones above: rpc-Messages.salam

Method

struct Method
One registered method.
NameTypeDescription
namestr = ""The name.
fni64 = 0The routine.
docstr = ""The description.

The example for this item is shown with the ones above: rpc-Methods.salam

MethodTable

struct MethodTable
The table of methods.
NameTypeDescription
itemsVectorThe methods.

The example for this item is shown with the ones above: rpc-Methods.salam

CallSlot

struct CallSlot
The state of a call that is running.
NameTypeDescription
reqRequestThe request.
resultvalue.ValueThe result.
errErrorThe error.
is_errorbool = falseIt is an error.
repliedbool = falseIt has been answered.
busybool = falseIt is in use.

The example for this item is shown with the ones above: rpc-Methods.salam

SlotTable

struct SlotTable
The table of calls.
NameTypeDescription
itemsVectorThe calls.

The example for this item is shown with the ones above: rpc-Methods.salam

Constants and variables

RPC_MP_REQUEST

const RPC_MP_REQUEST: i32 = 0
MessagePack-RPC message type: a request.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_MP_RESPONSE

const RPC_MP_RESPONSE: i32 = 1
Message type: a response.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_MP_NOTIFY

const RPC_MP_NOTIFY: i32 = 2
Message type: a notification.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_READ_CHUNK

const RPC_READ_CHUNK: i32 = 4096
The size of each read from the socket.

The example for this item is shown with the ones above: rpc-Frames.salam

RPC_MAX_FRAME

const RPC_MAX_FRAME: i32 = 33554432
The largest size of one frame: 32 megabytes.

The example for this item is shown with the ones above: rpc-Frames.salam

RPC_PARSE_ERROR

const RPC_PARSE_ERROR: i32 = -32700
Error code: the JSON text could not be read.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_INVALID_REQUEST

const RPC_INVALID_REQUEST: i32 = -32600
Error code: the request is not in the right shape.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_METHOD_NOT_FOUND

const RPC_METHOD_NOT_FOUND: i32 = -32601
Error code: the method is not registered.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_INVALID_PARAMS

const RPC_INVALID_PARAMS: i32 = -32602
Error code: the parameters are wrong.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_INTERNAL_ERROR

const RPC_INTERNAL_ERROR: i32 = -32603
Error code: an internal error.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_SERVER_ERROR

const RPC_SERVER_ERROR: i32 = -32000
The start of the range of the server's own error codes: -32000 down to -32099.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_KIND_REQUEST

const RPC_KIND_REQUEST: i32 = 1
Message type: a request.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_KIND_NOTIFICATION

const RPC_KIND_NOTIFICATION: i32 = 2
Message type: a notification.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_KIND_RESPONSE

const RPC_KIND_RESPONSE: i32 = 3
Message type: a response.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_CODEC_JSON

const RPC_CODEC_JSON: i32 = 0
The JSON-RPC 2.0 codec.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_CODEC_MSGPACK

const RPC_CODEC_MSGPACK: i32 = 1
The MessagePack-RPC codec.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_FRAME_LINE

const RPC_FRAME_LINE: i32 = 0
Framing: each message on one line.

The example for this item is shown with the ones above: rpc-Messages.salam

RPC_FRAME_HEADER

const RPC_FRAME_HEADER: i32 = 1
Framing: a Content-Length header, like LSP.

The example for this item is shown with the ones above: rpc-Frames.salam

RPC_FRAME_LENGTH

const RPC_FRAME_LENGTH: i32 = 2
Framing: a 4 byte length before each message.

The example for this item is shown with the ones above: rpc-Messages.salam

Functions

JsonEncodeRequest

func JsonEncodeRequest(r: Request): str
A request as JSON-RPC text.

The example for this item is shown with the ones above: rpc-Messages.salam

JsonEncodeResponse

func JsonEncodeResponse(r: Response): str
A response as JSON-RPC text.

The example for this item is shown with the ones above: rpc-Messages.salam

JsonEncodeResponses

func JsonEncodeResponses(rs: Responses): str
The responses, one or an array.

The example for this item is shown with the ones above: rpc-Messages.salam

JsonDecodeBatch

func JsonDecodeBatch(text: str): Batch
Turns a text back into a batch of requests.

The example for this item is shown with the ones above: rpc-Methods.salam

JsonDecodeRequest

func JsonDecodeRequest(text: str, ok &: bool): Request
Decodes one request.

The example for this item is shown with the ones above: rpc-Methods.salam

JsonDecodeResponse

func JsonDecodeResponse(text: str, ok &: bool): Response
Decodes one response.

The example for this item is shown with the ones above: rpc-Messages.salam

JsonDecodeResponses

func JsonDecodeResponses(text: str, ok &: bool): Responses
One response or an array of responses.

The example for this item is shown with the ones above: rpc-Messages.salam

JsonTopLevelError

func JsonTopLevelError(e: Error): str
A JSON-RPC error response with a null id.

The example for this item is shown with the ones above: rpc-Messages.salam

Register

func Register(name: str, fn: i64)
Registers a routine for a method; the routine takes the call's number.

The example for this item is shown with the ones above: rpc-Methods.salam

RegisterDoc

func RegisterDoc(name: str, fn: i64, doc: str)
Like the routine above, with a description.

The example for this item is shown with the ones above: rpc-Methods.salam

Unregister

func Unregister(name: str): bool
Removes a method.

The example for this item is shown with the ones above: rpc-Methods.salam

HasMethod

func HasMethod(name: str): bool
The method is registered.

The example for this item is shown with the ones above: rpc-Methods.salam

MethodCount

func MethodCount(): int
The number of methods.

The example for this item is shown with the ones above: rpc-Methods.salam

ListMethods

func ListMethods(): Vector<str>
The names of every method.

The example for this item is shown with the ones above: rpc-Methods.salam

MethodDoc

func MethodDoc(name: str): str
A method's description.

The example for this item is shown with the ones above: rpc-Methods.salam

ResetRegistry

func ResetRegistry()
Removes every method.

The example for this item is shown with the ones above: rpc-Methods.salam

CallRequest

func CallRequest(slot: i64): Request
The current call's request.

The example for this item is shown with the ones above: rpc-Methods.salam

CallMethodName

func CallMethodName(slot: i64): str
The method name.

The example for this item is shown with the ones above: rpc-Methods.salam

CallParams

func CallParams(slot: i64): value.Value
All the parameters.

The example for this item is shown with the ones above: rpc-Methods.salam

CallIsNotification

func CallIsNotification(slot: i64): bool
The call is a notification and its answer is not sent.

The example for this item is shown with the ones above: rpc-Methods.salam

CallParamCount

func CallParamCount(slot: i64): int
The number of parameters.

The example for this item is shown with the ones above: rpc-Methods.salam

CallParam

func CallParam(slot: i64, key: str, pos: int): value.Value
A parameter by name or by position.

The example for this item is shown with the ones above: rpc-Methods.salam

CallParamInt

func CallParamInt(slot: i64, key: str, pos: int): i64
A numeric parameter.

The example for this item is shown with the ones above: rpc-Methods.salam

CallParamFloat

func CallParamFloat(slot: i64, key: str, pos: int): f64
A float parameter.

The example for this item is shown with the ones above: rpc-Methods.salam

CallParamStr

func CallParamStr(slot: i64, key: str, pos: int): str
A text parameter.

The example for this item is shown with the ones above: rpc-Methods.salam

CallParamBool

func CallParamBool(slot: i64, key: str, pos: int): bool
A boolean parameter.

The example for this item is shown with the ones above: rpc-Methods.salam

Reply

func Reply(slot: i64, result: value.Value)
Answers with a value.

The example for this item is shown with the ones above: rpc-Methods.salam

ReplyInt

func ReplyInt(slot: i64, n: i64)
A numeric answer.

The example for this item is shown with the ones above: rpc-Methods.salam

ReplyFloat

func ReplyFloat(slot: i64, n: f64)
A float answer.

The example for this item is shown with the ones above: rpc-Methods.salam

ReplyStr

func ReplyStr(slot: i64, s: str)
A text answer.

The example for this item is shown with the ones above: rpc-Methods.salam

ReplyBool

func ReplyBool(slot: i64, b: bool)
A boolean answer.

The example for this item is shown with the ones above: rpc-Methods.salam

ReplyNull

func ReplyNull(slot: i64)
A null answer.

The example for this item is shown with the ones above: rpc-Methods.salam

Fail

func Fail(slot: i64, code: int, message: str)
Answers with an error.

The example for this item is shown with the ones above: rpc-Methods.salam

FailWithData

func FailWithData(slot: i64, code: int, message: str, data: value.Value)
An error with extra data.

The example for this item is shown with the ones above: rpc-Methods.salam

FailInvalidParams

func FailInvalidParams(slot: i64, message: str)
The invalid parameter error.

The example for this item is shown with the ones above: rpc-Methods.salam

Invoke

func Invoke(req: Request): Response
Runs one request with the registered methods.

The example for this item is shown with the ones above: rpc-Methods.salam

NewServer

func NewServer(port: int, codec: int): Server
A new server with a port and a codec.

The example for this item is shown with the ones above: rpc-Client.salam

SetFraming

func SetFraming(s &: Server, framing: int)
The server's framing.

The example for this item is shown with the ones above: rpc-Client.salam

InvokeBatch

func InvokeBatch(b: Batch): Responses
Runs every request of a batch; notifications have no answer.

The example for this item is shown with the ones above: rpc-Methods.salam

HandlePayload

func HandlePayload(codec: int, payload: compress.ByteBuf): compress.ByteBuf
Processes one whole payload and returns the encoded answer.

The example for this item is shown with the ones above: rpc-Serve.salam

HandleText

func HandleText(text: str): str
Processes one JSON-RPC text and returns the answer; for notifications, an empty string. For putting RPC behind an HTTP route.

The example for this item is shown with the ones above: rpc-Methods.salam

ServeConn

func ServeConn(fd: i64, codec: int, framing: int): int
Answers one connection until it closes.

The example for this item is shown with the ones above: rpc-Serve.salam

Listen

func Listen(s &: Server): bool
Starts listening.

The example for this item is shown with the ones above: rpc-Client.salam

Port

func Port(s: Server): int
The port actually taken.

The example for this item is shown with the ones above: rpc-Client.salam

ServeCount

func ServeCount(s &: Server, n: int): int
Answers n connections and returns.

The example for this item is shown with the ones above: rpc-Client.salam

Serve

func Serve(s &: Server)
Answers connections until it is stopped.

The example for this item is shown with the ones above: rpc-Client.salam

StopServer

func StopServer(s &: Server)
Stops the server.

The example for this item is shown with the ones above: rpc-Client.salam

ServeStdio

func ServeStdio(framing: int): int
Reads the requests from standard input and writes the answer to the output, like a language server (LSP).

The example for this item is shown with the ones above: rpc-Serve.salam

MsgpackEncodeRequest

func MsgpackEncodeRequest(r: Request): compress.ByteBuf
Encodes a request into MessagePack-RPC.

The example for this item is shown with the ones above: rpc-Messages.salam

MsgpackEncodeResponse

func MsgpackEncodeResponse(r: Response): compress.ByteBuf
Encodes a response into MessagePack-RPC.

The example for this item is shown with the ones above: rpc-Messages.salam

MsgpackDecodeBatch

func MsgpackDecodeBatch(b: compress.ByteBuf): Batch
Turns a MessagePack-RPC message back into a batch of requests.

The example for this item is shown with the ones above: rpc-Messages.salam

MsgpackDecodeResponse

func MsgpackDecodeResponse(b: compress.ByteBuf, ok &: bool): Response
Decodes a MessagePack-RPC response.

The example for this item is shown with the ones above: rpc-Messages.salam

NewStream

func NewStream(fd: i64): Stream
A stream over a socket.

The example for this item is shown with the ones above: rpc-Serve.salam

NewMemStream

func NewMemStream(): Stream
A stream in memory, for testing and for processing data you already have.

The example for this item is shown with the ones above: rpc-Frames.salam

FreeStream

func FreeStream(s &: Stream)
Frees the stream.

The example for this item is shown with the ones above: rpc-Frames.salam

FeedStr

func FeedStr(s &: Stream, text: str)
Adds a text to a memory stream.

The example for this item is shown with the ones above: rpc-Frames.salam

FeedBuf

func FeedBuf(s &: Stream, b: compress.ByteBuf)
Adds a buffer to a memory stream.

The example for this item is shown with the ones above: rpc-Frames.salam

StreamPending

func StreamPending(s: Stream): int
The bytes not read yet.

The example for this item is shown with the ones above: rpc-Frames.salam

StreamClosed

func StreamClosed(s: Stream): bool
The stream is closed.

The example for this item is shown with the ones above: rpc-Frames.salam

FrameEncode

func FrameEncode(kind: int, payload: compress.ByteBuf): compress.ByteBuf
Frames a payload with the given framing.

The example for this item is shown with the ones above: rpc-Messages.salam

FrameEncodeStr

func FrameEncodeStr(kind: int, payload: str): compress.ByteBuf
Frames a text.

The example for this item is shown with the ones above: rpc-Frames.salam

ReadFrame

func ReadFrame(s &: Stream, kind: int, ok &: bool): compress.ByteBuf
Reads the next frame.

The example for this item is shown with the ones above: rpc-Frames.salam

ReadFrameStr

func ReadFrameStr(s &: Stream, kind: int, ok &: bool): str
The next frame as text.

The example for this item is shown with the ones above: rpc-Frames.salam

WriteFrame

func WriteFrame(fd: i64, kind: int, payload: compress.ByteBuf): bool
Writes a frame over the socket.

The example for this item is shown with the ones above: rpc-Serve.salam

WriteFrameStr

func WriteFrameStr(fd: i64, kind: int, payload: str): bool
Frames a text and writes it over the socket.

The example for this item is shown with the ones above: rpc-Serve.salam

DialClient

func DialClient(host: str, port: int, codec: int): Client
Connects to an RPC server with the given codec; the codec's default framing is used.

The example for this item is shown with the ones above: rpc-Client.salam

ClientFromFd

func ClientFromFd(fd: i64, codec: int): Client
A client over an open socket.

The example for this item is shown with the ones above: rpc-Serve.salam

ClientSetFraming

func ClientSetFraming(c &: Client, framing: int)
Changes the client's framing; it must be the same as the server's.

The example for this item is shown with the ones above: rpc-Client.salam

ClientOk

func ClientOk(c: Client): bool
The client is healthy.

The example for this item is shown with the ones above: rpc-Client.salam

ClientError

func ClientError(c: Client): str
The client's last error.

The example for this item is shown with the ones above: rpc-Client.salam

CloseClient

func CloseClient(c &: Client)
Closes the connection.

The example for this item is shown with the ones above: rpc-Client.salam

Call

func Call(c &: Client, method: str, params: value.Value): Response
Calls the method with parameters and waits for the answer.

The example for this item is shown with the ones above: rpc-Methods.salam

CallNoParams

func CallNoParams(c &: Client, method: str): Response
A method with no parameters.

The example for this item is shown with the ones above: rpc-Client.salam

CallArgs

func CallArgs(c &: Client, method: str, args: Vector<value.Value>): Response
A method with a list of arguments.

The example for this item is shown with the ones above: rpc-Client.salam

Notify

func Notify(c &: Client, method: str, params: value.Value): bool
Sends a notification; no answer comes back.

The example for this item is shown with the ones above: rpc-Methods.salam

CallBatch

func CallBatch(c &: Client, reqs: Vector<Request>): Responses
Sends several requests at once and returns the answers.

The example for this item is shown with the ones above: rpc-Client.salam

ResultInt

func ResultInt(r: Response): i64
The result as a number.

The example for this item is shown with the ones above: rpc-Methods.salam

ResultFloat

func ResultFloat(r: Response): f64
The result as a float.

The example for this item is shown with the ones above: rpc-Messages.salam

ResultStr

func ResultStr(r: Response): str
The result as text.

The example for this item is shown with the ones above: rpc-Messages.salam

ResultBool

func ResultBool(r: Response): bool
The result as a boolean.

The example for this item is shown with the ones above: rpc-Messages.salam

IsErrorResponse

func IsErrorResponse(r: Response): bool
The response is an error.

The example for this item is shown with the ones above: rpc-Messages.salam

ErrorCode

func ErrorCode(r: Response): int
The response's error code.

The example for this item is shown with the ones above: rpc-Messages.salam

ErrorMessage

func ErrorMessage(r: Response): str
The response's error message.

The example for this item is shown with the ones above: rpc-Messages.salam

CallHTTP

func CallHTTP(url: str, method: str, params: value.Value, id: i64): Response
Sends a JSON-RPC request with POST to an HTTP address.

The example for this item is shown with the ones above: rpc-Client.salam

NewError

func NewError(code: int, message: str): Error
An error with a code and a message.

The example for this item is shown with the ones above: rpc-Messages.salam

StdError

func StdError(code: int): Error
A standard error with that code's default message.

The example for this item is shown with the ones above: rpc-Messages.salam

ErrorWithData

func ErrorWithData(code: int, message: str, data: value.Value): Error
An error with extra data.

The example for this item is shown with the ones above: rpc-Messages.salam

NewRequest

func NewRequest(method: str, params: value.Value, id: i64): Request
A request with a numeric id.

The example for this item is shown with the ones above: rpc-Messages.salam

NewRequestStrId

func NewRequestStrId(method: str, params: value.Value, id: str): Request
A request with a text id.

The example for this item is shown with the ones above: rpc-Messages.salam

NewNotification

func NewNotification(method: str, params: value.Value): Request
A notification, that is a request that wants no answer.

The example for this item is shown with the ones above: rpc-Messages.salam

IsNotification

func IsNotification(r: Request): bool
It is a notification.

The example for this item is shown with the ones above: rpc-Methods.salam

NewResponse

func NewResponse(id: value.Value, result: value.Value): Response
A response with a result.

The example for this item is shown with the ones above: rpc-Messages.salam

NewErrorResponse

func NewErrorResponse(id: value.Value, e: Error): Response
An error response.

The example for this item is shown with the ones above: rpc-Messages.salam

ParamCount

func ParamCount(r: Request): int
The number of parameters.

The example for this item is shown with the ones above: rpc-Methods.salam

ParamAt

func ParamAt(r: Request, i: int): value.Value
The parameter at this position.

The example for this item is shown with the ones above: rpc-Messages.salam

ParamNamed

func ParamNamed(r: Request, key: str): value.Value
The parameter with this name.

The example for this item is shown with the ones above: rpc-Messages.salam

Param

func Param(r: Request, key: str, pos: int): value.Value
The parameter by name, or by position if the parameters are an array; for taking both shapes.

The example for this item is shown with the ones above: rpc-Methods.salam

ParamInt

func ParamInt(r: Request, key: str, pos: int): i64
A numeric parameter.

The example for this item is shown with the ones above: rpc-Methods.salam

ParamFloat

func ParamFloat(r: Request, key: str, pos: int): f64
A float parameter.

The example for this item is shown with the ones above: rpc-Methods.salam

ParamStr

func ParamStr(r: Request, key: str, pos: int): str
A text parameter.

The example for this item is shown with the ones above: rpc-Methods.salam

ParamBool

func ParamBool(r: Request, key: str, pos: int): bool
A boolean parameter.

The example for this item is shown with the ones above: rpc-Methods.salam

HasParam

func HasParam(r: Request, key: str, pos: int): bool
The parameter was given.

The example for this item is shown with the ones above: rpc-Messages.salam

CodecName

func CodecName(codec: int): str
The codec's name, like json-rpc-2.0.

The example for this item is shown with the ones above: rpc-Messages.salam

CodecDefaultFraming

func CodecDefaultFraming(codec: int): int
The codec's default framing: line for JSON and length prefixed for MessagePack.

The example for this item is shown with the ones above: rpc-Messages.salam

EncodeRequest

func EncodeRequest(codec: int, r: Request): compress.ByteBuf
Encodes a request with the given codec.

The example for this item is shown with the ones above: rpc-Messages.salam

EncodeResponses

func EncodeResponses(codec: int, rs: Responses): compress.ByteBuf
Encodes the responses.

The example for this item is shown with the ones above: rpc-Messages.salam

DecodeBatch

func DecodeBatch(codec: int, payload: compress.ByteBuf): Batch
Turns a received payload back into a batch of requests.

The example for this item is shown with the ones above: rpc-Methods.salam

DecodeResponse

func DecodeResponse(codec: int, payload: compress.ByteBuf, ok &: bool): Response
Decodes a response.

The example for this item is shown with the ones above: rpc-Messages.salam

EncodeTopLevelError

func EncodeTopLevelError(codec: int, e: Error): compress.ByteBuf
An error response with no id, for when the request could not be read.

The example for this item is shown with the ones above: rpc-Messages.salam