Skip to content
Kavachकवच

gRPC: Two-way and conversations

● Intermediate4 min

Two-way streams send many messages each way; a conversation answers each message as it arrives.

use std.grpc
use std.net

pub type Line {
    text: String
}

fn echo(call: GrpcCall) -> GrpcReply {
    const lines = grpc.read_all<Line>(call) catch _ => []
    if lines.len() == 0 {
        return grpc.failed(3, "nothing to echo")
    }
    grpc.reply_stream(lines.map(l => Line(text: "echo: {l.text}")))
}

fn main() ! Error {
    const listener = try net.listen("127.0.0.1:0")
    const _server = spawn grpc.serve(listener, echo)
    const target = "http://{listener.address()}"
    const lines = [Line(text: "one"), Line(text: "two"), Line(text: "three")]
    try grpc.each_stream<Line, Line>(target, "/chat.Echo/Talk", lines, l => print(l.text))
    print("done")
    const silent: [Line] = []
    grpc.each_stream<Line, Line>(target, "/chat.Echo/Talk", silent, l => print("?")) catch e => print("silent: {e}")
}

The program ran and printed:

kavach run two-way.kav

echo: oneecho: twoecho: threedonesilent: Status(code: 3, message: "nothing to echo")
two-way.kav: Kavach code, then what running it prints

With each_stream, the client sends everything, then reads the answers. For a real back-and-forth, hold a conversation: each side answers the other's last message.

use std.grpc
use std.net

pub type Count {
    n: Int
}

fn plus_one(call: GrpcCall) -> GrpcReply {
    const c = grpc.read<Count>(call) catch _ => Count(n: 0)
    if c.n == 0 {
        return grpc.failed(3, "not a count")
    }
    print("server got {c.n}")
    grpc.reply(Count(n: c.n + 1))
}

fn main() ! Error {
    const listener = try net.listen("127.0.0.1:0")
    const _server = spawn grpc.serve_talks(listener, plus_one, ["/game.Count/Up"])
    const target = "http://{listener.address()}"
    try grpc.talk_with<Count, Count>(target, "/game.Count/Up", [Count(n: 1)], c => {
        print("client got {c.n}")
        if c.n < 6 { [Count(n: c.n + 1)] } else { none }
    })
    print("done")
    grpc.talk_with<Count, Count>(target, "/game.Count/Up", [Count(n: 0)], c => none) catch e => print("bad: {e}")
}

The program ran and printed:

kavach run talk.kav

server got 1client got 2server got 3client got 4server got 5client got 6donebad: Status(code: 3, message: "not a count")
talk.kav: Kavach code, then what running it prints

The client's function gives the next messages to send, or none to end its side.