callwire 2.0.0

High-performance bidirectional RPC over TCP with MessagePack framing — Go, Python, Rust interop
Documentation

Callwire v2

A high-performance, bidirectional RPC framework for Go, Python, and Rust over TCP with MessagePack framing. Both sides of any connection can act as a client and server simultaneously.

[!IMPORTANT] Language-Agnostic Design: Callwire is designed around a simple, clean, and fully-specified wire protocol. You can implement clients and servers in any language by following the SPEC.md.

Features

  • Multi-Language: First-class support for Go, Python, and Rust.
  • Bidirectional: Connection-symmetric. Clients can serve endpoints and servers can invoke client functions over the same socket.
  • TLS & mTLS: Secure transport with server authentication and optional Mutual TLS (mTLS).
  • Service Discovery: Built-in lightweight registry server and auto-refreshing client DiscoverPool.
  • Dynamic Reconnections: Auto-reconnect with exponential backoff on connection drops.
  • Batch API: Concurrent RPC multiplexing on a single connection.

Quick Start

Go

import "github.com/emaad/callwire"

// 1. Export local function
callwire.Export("add", func(a, b int) int { return a + b })

// 2. Call remote function using client
client, _ := callwire.Connect("localhost:9090")
addFunc := callwire.RefWithClient[int](client, "add")
result, _ := addFunc(10, 20) // 30

Python

from callwire import export, serve, Client

# 1. Export local function
@export
def add(a, b):
    return a + b

# 2. Call remote function
client = Client()
client.connect("localhost", 9090)
result = client.call("add", [10, 20]) # 30

Rust

use callwire::{Client, register_unary, serve_on};

// 1. Export local function
register_unary("add", |(a, b): (i64, i64)| -> Result<i64, String> {
    Ok(a + b)
});

// 2. Call remote function
let client = Client::connect("127.0.0.1:9090").await.unwrap();
let result: i64 = client.import("add", &(10i64, 20i64)).await.unwrap(); // 30

TLS & Mutual TLS (mTLS)

Callwire v2 supports standard TLS and client certificate verification (mTLS).

Go TLS Server & Client

// Server
cfg := callwire.TLSConfig{CertPem: cert, KeyPem: key}
callwire.ServeWithTLS("0.0.0.0:9090", cfg)

// Client
clientCfg := callwire.TLSConfig{CAPem: caCert}
client, _ := callwire.ConnectWithReconnectTLS("localhost:9090", clientCfg)

Python TLS Client

client = Client()
client.connect("localhost", 9090, tls={
    "cafile": "ca.pem",
    "certfile": "client.pem", # for mTLS
    "keyfile": "client.key"    # for mTLS
})

Rust TLS Client

let client_cfg = callwire::TlsConfig {
    cert_pem: vec![],
    key_pem: vec![],
    ca_pem: Some(ca_pem), // Server CA cert
};
let client = client_cfg.connect("127.0.0.1:9090").await.unwrap();

Service Discovery

Callwire features a built-in Service Discovery registry (itself powered by Callwire RPC).

Go Registry & Worker Setup

// 1. Start the registry server
callwire.ServeRegistry("127.0.0.1:29090")

// 2. Start a worker and register it
callwire.Export("say_hello", func(name string) string { return "Hello " + name })
go callwire.Serve("127.0.0.1:29091")
callwire.RegisterWith("127.0.0.1:29090", "hello-service", "127.0.0.1:29091")

// 3. Resolve and call using DiscoverPool
pool, _ := callwire.NewDiscoverPool("127.0.0.1:29090", "hello-service")
sayHello := callwire.DiscoverRef[string](pool, "say_hello")
reply, _ := sayHello("World") // "Hello World"

Python DiscoverPool

from callwire import DiscoverPool

pool = DiscoverPool("127.0.0.1:29090", "hello-service")
client = pool.get()
result = client.call("say_hello", ["World"])

Rust DiscoverPool

use callwire::DiscoverPool;

let pool = DiscoverPool::new("127.0.0.1:29090", "hello-service").await.unwrap();
let client = pool.get().unwrap();
let res: String = client.import("say_hello", &("World".to_string(),)).await.unwrap();

Configuration

Env Var Default Description
CALLWIRE_HOST localhost Default hostname for auto-serving & clients
CALLWIRE_PORT 9090 Default port for auto-serving & clients
CALLWIRE_AUTO 1 Set to 0 to disable automatic server launching on Export

Developer Testing

Run the full cross-language integration and unit suites:

# Go tests
cd go/callwire && go test -v ./...

# Python tests
cd python && .venv/bin/python3 -m unittest discover -s . -p "test_*.py"

# Rust tests
cd rust && cargo test -- --nocapture