README.md

July 6, 2026 · View on GitHub

 __                          
/\ \__         __            
\ \ ,_\    __ /\_\    ___    
 \ \ \/  /'_ `\/\ \ /' _ `\  
  \ \ \_/\ \L\ \ \ \/\ \/\ \ 
   \ \__\ \____ \ \_\ \_\ \_\
    \/__/\/___L\ \/_/\/_/\/_/
           /\____/           
           \_/__/

any traffic in - any traffic out. A Rust construction kit for building gateways of your own shape: one core, endless batteries

ci crates.io docs.rs

HISTORY | DEMOS | EXAMPLES | DOCS

Important

active development is continuing: there is no stable version yet

Why Tgin?

  • Composability: every gateway is ingress → egress; balancers, routers and retries are decorators that wrap egresses — new behavior without touching the core

  • Type safety: an incompatible ingress/egress pair is a failure to compile

  • Batteries included: HTTP server & client, Telegram Bot API (longpoll and webhook), RabbitMQ, Kafka, WebSocket tunnels, round-robin / fan-out balancers, predicate router, retry with backoff

  • Honest delivery: the reply of every message doubles as its ack — RabbitMQ ack/nack/requeue and Telegram offset advancement are driven by the real downstream outcome

  • Backpressure end to end: full channels turn into HTTP 429 and broker qos instead of unbounded memory

  • Per-key ordering: messages with the same key (one Telegram chat, one entity) stay ordered, different keys run in parallel

  • Graceful shutdown: SIGINT drains in-flight messages, then stops

  • Embeddable: tgin is a library, not a daemon — your gateway is a ~20 line Rust binary you fully control

Architecture Overview

   ingress                     egress
HTTP | Telegram | RabbitMQ | Kafka | Tunnel

   Envelope<I, O>  (data + meta + reply)

 [ Route | RoundRobin | All | Retry ]

HTTP | Telegram | RabbitMQ | Kafka | Tunnel

Quick start

# Clone the repository
git clone https://github.com/chesnokpeter/tgin.git
cd tgin

# Run a case
cargo run --example reverse_proxy
BOT_TOKEN=... cargo run --example telegram_balancer
TUNNEL_TOKEN=... cargo run --example tunnel_server

# Or bring up a full live stack (broker + backends + tgin)
cd demos/kafka-bridge && docker compose up --build

Use as a library

tgin is a library crate — your gateway is your own ~20 line binary:

cargo add tgin

or in Cargo.toml:

[dependencies]
tgin = "0.1"

Configuration

Your gateway is a Rust builder — every piece is a value you construct and compose:

let server = HttpServer::new("0.0.0.0:8080");
let http = HttpClient::new();

Tgin::new()
    .pipeline(
        HttpIngress::catch_all(&server),
        Route::new()
            .when(
                |request: &RequestData| request.uri.path().starts_with("/api"),
                RoundRobin::new()
                    .to(HttpEgress::new(&http, "http://127.0.0.1:3001"))
                    .to(HttpEgress::new(&http, "http://127.0.0.1:3002")),
            )
            .otherwise(HttpEgress::new(&http, "http://127.0.0.1:3000")),
    )
    .run()
    .await;

Cases

one core, different hands:

nginx case — reverse proxy with routing, balancing and failover → examples/reverse_proxy.rs

ngrok case — expose localhost to the internet through a WebSocket tunnel (in NAT) → examples/tunnel_server.rs + examples/tunnel_client.rs

telegram case — the original tgin: balance updates across bot instances, webhook or longpoll on both sides, per-chat ordering for free. Bots can even poll tgin itself — it recreates Telegram getUpdates semantics inside your cluster, offsets included → examples/telegram_balancer.rs, examples/telegram_webhook_balancer.rs, examples/telegram_longpoll_balancer.rs

bridge case — HTTP in, broker out; queue in, Telegram message out. One binary can run several pipelines at once → examples/http_to_rabbit.rs, examples/rabbit_to_telegram.rs, examples/ingestion_pipeline.rs, examples/kafka_bridge.rs

gateway case — hide your bot token behind your own API → examples/telegram_api_gateway.rs

Demos

live compose stacks under demos/ — real brokers, real backends, failure drills to run yourself:

  • demos/reverse-proxy — routing + balancing, kill a backend and watch failover
  • demos/tunnel — reach a container that publishes no ports, kill the agent and watch it reconnect
  • demos/ingestion — HTTP → RabbitMQ at-least-once, kill the worker and nothing is lost
  • demos/kafka-bridge — HTTP → Kafka → worker with honest offset commits

each is one docker compose up --build plus a README walkthrough

Batteries

kindbatterywhat it does
ingressHttpIngressserve a path, a method or catch-all on a shared HttpServer
ingressKafkaIngressconsume a topic in a consumer group; offsets commit only after downstream confirms, failures seek back and redeliver
ingressTelegramBotPollingIngressgetUpdates longpoll from Telegram, offset advances only after delivery, per-chat key
ingressTelegramBotWebhookIngresswebhook endpoint with x-telegram-bot-api-secret-token validation
ingressRabbitmqIngressconsume a durable queue, qos prefetch, ack/nack/requeue by outcome
ingressTunnelIngressagent side of the tunnel: outbound connect + reconnect
egressHttpEgressforward to an upstream with proper proxy headers
egressKafkaEgressproduce with acks=all; meta.key becomes the partition key, so per-chat / per-entity order survives the hop
egressTelegramBotWebhookEgresspush updates to a bot instance the way Telegram does, secret header included
egressTelegramBotPollingEgresshost a getUpdates endpoint — unmodified longpoll bots poll tgin as if it were Telegram, ack by offset
egressTelegramBotApiEgresscall the Bot API: fixed method or pass-through, 429/5xx/4xx mapped honestly
egressRabbitmqEgresspublish persistent messages with publisher confirms
egressTunnelEgressserver side of the tunnel: multiplex requests over one WebSocket
decoratorRoutepick an egress by predicate, otherwise fallback
decoratorRoundRobinrotate across egresses, failover on retryable errors
decoratorAllfan out every message to every egress
decoratorRetryretry retryable errors with exponential backoff
sharedHttpServer / HttpClient / Rabbitresources you construct once and share across batteries

Future features

  • Config file on top of compiled batteries — declare pipelines in a config instead of Rust, validated at startup, invalid pairs rejected before serving (Envoy/Vector style)
  • Hot config reload — swap pipeline wiring on the fly, without restarting the process
  • Transform / processing decorators — map, filter and enrich messages between ingress and egress
  • Metrics, tracing, logging
  • TLS termination
  • Streaming bodies & WebSocket passthrough
  • More batteries: NATS, Redis, gRPC
  • Performance harness

Main Goal

Provide a universal, embeddable toolkit where any traffic can be taken in, routed, distributed and transformed on the way out — one frozen core, endless batteries