Skip to content

singchia/geminio-rs

Repository files navigation

geminio-rs

Rust port of singchia/geminio — one connection, bidirectional RPC, acknowledged messaging, and stream multiplexing behind a single async Conn.

Status: 0.1.0-dev — active pre-1.0 port. The core stack is in place: packet codecs, TCP transport, handshake, heartbeat, connection FSM, multiplexer/dialogue FSM, application End/Stream, bidirectional RPC, acknowledged messaging, and Go↔Rust interop coverage. The upstream Go implementation at v1.3.0-rc.2 remains the reference for behavior and wire format.

Why a Rust port

Go's geminio leans hard on goroutines + channels + GC for teardown coordination. Every bug we've fixed under chaos testing (send-on-closed-channel, nil-pointer after fini(), Write vs Close races) is a class of bug that Rust's ownership model turns into compile errors.

Trade-off: more explicit lifetime management, more verbose handler signatures. Upside: the race-detector flakes that motivated the go-timer fix in v1.3.0-rc.2 simply can't compile.

Repository layout

geminio-rs/
├── Cargo.toml                 # workspace root
├── Cargo.lock                 # committed (lib + bin reproducibility)
├── rust-toolchain.toml        # Rust toolchain pin (1.90)
├── rustfmt.toml / clippy.toml # style + lint config
├── deny.toml                  # cargo-deny: licenses + advisories
├── .editorconfig
├── .github/workflows/
│   ├── ci.yml                 # check / fmt / clippy / test (3 OS) / doc
│   └── audit.yml              # cargo-deny on Cargo.toml change + weekly cron
├── crates/                    # workspace members
│   ├── geminio/               # public facade — what downstream depends on
│   ├── conn/                  # Connection: transport, heartbeat, FSM
│   ├── mux/                   # Multiplexer / Dialogue: logical streams, routing
│   └── app/                   # Application: End, Stream, RPC, messaging
├── tools/
│   ├── interop/               # Go helper for cross-language tests
│   └── file_stream_server/    # Go server example for Rust-client file receive
├── README.md                  # this file
├── CHANGELOG.md               # Keep a Changelog
├── CONTRIBUTING.md            # workflow + style rules
└── ROADMAP.md                 # vertical slices toward Go v1.3.x parity

The three internal crates (conn / mux / app) are dropped of the geminio- prefix because the workspace itself already says geminio. The public geminio crate re-exports them so downstream code only needs one dependency:

use geminio::{End, Stream};       // app facade
use geminio::conn::Conn;          // if you need the lower layer
use geminio::mux::Dialogue;       // ditto

The Go ↔ Rust mapping:

Go package Rust crate
github.com/singchia/geminio/conn crates/conn
github.com/singchia/geminio/multiplexer crates/mux
github.com/singchia/geminio/application crates/app
github.com/singchia/geminio (top-level) crates/geminio

Each crate's src/ mirrors the Go-side decomposition (packet/, transport/, fsm.rs, heartbeat.rs, etc.) so a reader who knows the Go side can navigate by symbol.

Building

cargo check --workspace
cargo test --workspace --all-targets
cargo bench  -p geminio --bench throughput          # criterion benches
cargo run    -p geminio --example smoke             # raw packet demo
cargo run    -p geminio --example rpc_echo          # bidirectional RPC
cargo run    -p geminio --example pubsub            # acknowledged messaging
cargo run    -p geminio --example stream_loopback   # AsyncRead+Write Stream
cargo run    -p geminio --example recv_file_from_go # Rust client receiving from Go server
make interop                                        # Go ↔ Rust wire-compat tests

Benchmarks (Apple M4, dev box, payload 16 B → 4 KiB)

rpc/16        ~74 µs/iter   ~13.5K ops/sec
rpc/256       ~77 µs/iter   ~13.0K ops/sec   3.2 MiB/s
rpc/4096      ~87 µs/iter   ~11.5K ops/sec    45 MiB/s
publish/16    ~73 µs/iter
publish/4096  ~80 µs/iter                     49 MiB/s
open_dialogue ~30 µs/iter

Each call/publish currently opens a fresh dialogue (full Session handshake + Dismiss); a dialogue-pooling pass is on the post-1.0 list.

Status snapshot

  • Workspace skeleton, layered traits.
  • Project hygiene: CI, rustfmt, clippy, cargo-deny.
  • conn::packet: header + frame codec, byte-for-byte compatible with the Go wire format.
  • conn::transport::tcp: framed read / framed write over tokio::net.
  • conn: handshake, connection FSM, heartbeat, graceful close, TCP Conn driver.
  • mux: Session / Dismiss payloads, Dialogue FSM, open / dismiss handshake, routing, write scheduling.
  • app: End, Stream (AsyncRead + AsyncWrite), bidirectional RPC, acknowledged messaging.
  • Cross-language interop: Go server ↔ Rust client and Rust server ↔ Go client RPC/publish checks.
  • Hardening coverage: app lifecycle chaos, wire-level chaos, close-race tests, throughput benches.
  • Full Go v1.3.x scenario parity audit.
  • API freeze for 1.0 (#[non_exhaustive] review, public surface cleanup).
  • Documented examples for every major Go-side example.

See ROADMAP.md for the full plan.

License

Apache-2.0 — same as the upstream Go implementation.

About

Rust port of singchia/geminio — one connection: bidirectional RPC, acknowledged messaging, and stream multiplexing behind a single async Conn.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors