asyncio and msgpack to asynchronously serialize network events and arbitrary data structures, delivering them to your high-level classes through simple callback methods.
Architecture Philosophy
repod is built on a simple philosophy: you shouldn’t have to think about sockets, buffers, or polling. Instead, you define callback methods that handle specific message types, and the library routes everything for you. The architecture is based on:- asyncio for non-blocking I/O
- msgpack for efficient binary serialization
- Action-based dispatch for clean message routing
- Background threads on the client to keep your game loop synchronous
Core Components
repod provides four main building blocks:Server
TheServer class manages multiple client connections. It runs an asyncio event loop that:
- Accepts incoming TCP connections
- Creates a new
Channelinstance for each client - Manages the lifecycle of all channels
- Provides broadcast methods like
send_to_all()
server.py
launch() method is a convenience wrapper that:
- Starts the server with
await start() - Runs the event loop with
await run() - Handles
KeyboardInterruptgracefully - Cleans up with
await stop()
Channel
TheChannel class represents a single network connection. On the server side, each connected client gets its own Channel instance.
channel.py
- A reference to the parent
Serverviaself.server - The remote address via
self.addr - A
send()method for sending messages to this specific client - Lifecycle hooks:
on_connect(),on_close(),on_error()
Client
TheClient class is the low-level TCP client. It runs asyncio in a background daemon thread so your main game loop can remain fully synchronous.
low_level_client.py
Client directly — they use ConnectionListener instead.
ConnectionListener
TheConnectionListener class is a high-level mixin that wraps Client and provides a synchronous API for your game loop.
game_client.py
pump() once per frame:
- Drains the receive queue from the background thread
- Dispatches each message to the matching
Network_{action}method - Falls back to
network_received()if no handler exists
How It Works
Here’s the complete flow when a client sends a message:Message dispatch
The channel’s
_dispatch() method routes the message to Network_chat() based on the "action" keyThread Model
Server Threading
The server has two modes:- Foreground mode (default):
launch()runs the asyncio loop in the main thread - Background mode:
start_background()runs the asyncio loop in a daemon thread
background_server.py
Client Threading
The client always runs asyncio in a background daemon thread. Your main thread:- Calls
send()(thread-safe) - Calls
pump()to process queued messages (main thread only)
- Runs
_read_loop()and_write_loop() - Enqueues received messages to
_receive_queue - Writes outgoing messages from
_send_queue
The
send() method is thread-safe and can be called from any thread. The pump() method is not thread-safe and must only be called from your main game loop.Next Steps
Client-Server Model
Deep dive into server lifecycle, channels, and the background thread model
Actions & Dispatch
Learn how action-based message routing works
Serialization
Understand msgpack and length-prefix framing
Quick Start
Build your first server and client