Add your description here
Project description
CHUK Protocol Server
A modern Python framework for building server applications that work across multiple transport protocols: Telnet, TCP, and WebSocket. Create a server once and make it accessible from traditional terminal clients, command-line tools, and web browsers.
Features
- Multiple Transport Protocols: Run your server on Telnet, TCP, and WebSocket simultaneously
- Unified Handler Interface: Write your application logic once, deploy everywhere
- Configurable: YAML-based configuration with transport-specific options
- Graceful Shutdown: Proper connection handling and clean termination
- Protocol Detection: Automatic Telnet negotiation detection with fallback
- Session Management: Connection limits, timeouts, and custom welcome messages
- Async Architecture: Built on Python's asyncio for efficient handling of concurrent connections
- Proper Telnet Protocol Implementation: Full support for telnet option negotiation and subnegotiation
- Dual-Mode Operation: Supports both line mode and character mode terminal handling
- Robust Error Handling: Graceful handling of connection issues and unexpected client behavior
- Session Monitoring: Optional monitoring of WebSocket sessions for debugging and analysis
Requirements
- Python 3.7+
- Dependencies:
- websockets
- pyyaml
- asyncio
Installation
# Install from PyPI
pip install chuk-protocol-server
# Or install from source
git clone https://github.com/yourusername/chuk-protocol-server.git
cd chuk-protocol-server
pip install -e .
# Optional: Install development dependencies
pip install -e ".[dev]"
Quick Start
- Create a handler class that inherits from one of the base handlers
- Configure your server with a YAML file
- Launch your server using the server launcher
uv run server-launcher -c src/chuk_protocol_server/sample_servers/echo_server/config.yaml
Client Connections
Your server will be accessible from multiple client types:
Telnet Client
Connect to the Telnet transport using a traditional Telnet client:
telnet localhost 8023
The server will negotiate Telnet options and provide a full-featured terminal experience.
TCP Client (netcat)
Connect to the TCP transport using netcat or similar tools:
nc localhost 8024
This provides a simple line-based interface without Telnet negotiation.
WebSocket Client
Connect to the WebSocket transport using any WebSocket client:
Command-line with websocat
# Install websocat if needed (https://github.com/vi/websocat)
websocat --exit-on-eof ws://localhost:8025/ws
Browser JavaScript
const ws = new WebSocket('ws://localhost:8025/ws');
ws.onmessage = function(event) { console.log('Received:', event.data); };
ws.onopen = function() { console.log('Connected!'); };
ws.onclose = function() { console.log('Disconnected'); };
// Send a message
ws.send('hello');
Configuration
The framework uses YAML configuration files for server setup:
# Single server configuration
host: 0.0.0.0
port: 8023
transport: telnet
handler_class: sample_servers.echo_server:EchoTelnetHandler
# OR
# Multi-transport configuration
servers:
telnet:
host: "0.0.0.0"
port: 8023
transport: "telnet"
handler_class: "sample_servers.echo_server:EchoTelnetHandler"
max_connections: 100
connection_timeout: 300
welcome_message: "Welcome to the Telnet Server!"
tcp:
host: "0.0.0.0"
port: 8024
transport: "tcp"
handler_class: "sample_servers.echo_server:EchoTelnetHandler"
max_connections: 100
connection_timeout: 300
welcome_message: "Welcome to the TCP Server!"
websocket:
host: "0.0.0.0"
port: 8025
transport: "websocket"
ws_path: "/ws"
handler_class: "sample_servers.echo_server:EchoTelnetHandler"
use_ssl: false
allow_origins:
- "*"
max_connections: 100
connection_timeout: 300
welcome_message: "Welcome to the WebSocket Server!"
enable_monitoring: true
monitor_path: "/monitor"
Configuration Options
| Option | Description | Default |
|---|---|---|
| host | Bind address | 0.0.0.0 |
| port | Listen port | 8023 |
| transport | Protocol type (telnet, tcp, websocket, ws_telnet) | telnet |
| handler_class | Handler class path (module:ClassName) | Required |
| max_connections | Maximum concurrent connections | 100 |
| connection_timeout | Session timeout in seconds | 300 |
| welcome_message | Message displayed on connection | None |
| ws_path | Path for WebSocket endpoint | /ws |
| allow_origins | CORS allowed origins | ["*"] |
| use_ssl | Enable SSL/TLS (WebSocket) | false |
| ssl_cert | Path to SSL certificate | None |
| ssl_key | Path to SSL key | None |
| ping_interval | WebSocket ping interval in seconds | 30 |
| ping_timeout | WebSocket ping timeout in seconds | 10 |
| enable_monitoring | Enable session monitoring (WebSocket) | false |
| monitor_path | Path for monitoring endpoint | /monitor |
Creating Handlers
Handlers define your server's behavior. Extend one of the base handler classes:
#!/usr/bin/env python3
from chuk_protocol_server.handlers.telnet_handler import TelnetHandler
class EchoTelnetHandler(TelnetHandler):
async def on_command_submitted(self, command: str) -> None:
if command.lower() == 'help':
await self.send_line("Available commands: help, info, quit")
else:
await self.send_line(f"Echo: {command}")
async def process_line(self, line: str) -> bool:
if line.lower() in ['quit', 'exit', 'q']:
await self.end_session("Goodbye!")
return False
await self.on_command_submitted(line)
await self.show_prompt()
return True
For more advanced customization, override additional methods:
class AdvancedHandler(TelnetHandler):
def __init__(self, reader, writer):
super().__init__(reader, writer)
self.custom_state = {}
async def show_prompt(self) -> None:
# Customize the prompt
await self.send_raw(b"my-app> ")
async def process_character(self, char: str) -> bool:
# Custom character processing
# Return False to terminate the connection
return await super().default_process_character(char)
Handler Classes
The framework provides several handler classes that you can extend:
- BaseHandler: Basic connection handling with raw I/O
- CharacterHandler: Character-by-character processing for interactive applications
- LineHandler: Line-by-line processing for simpler command interfaces
- TelnetHandler: Full telnet protocol support with negotiation
Choose the appropriate base class based on your application's needs.
Architecture
The framework is built on a layered architecture:
- Servers: Handle transport-specific connection management (Telnet, TCP, WebSocket)
- Handlers: Process client input and generate responses
- Adapters: Bridge between different transport types and handlers
This modular design allows for:
- Transport Layer: Manages network protocols and connections
- Character Protocol Layer: Character-by-character reading and processing
- Telnet Protocol Layer: Telnet-specific protocol handling and negotiation
- Application Logic Layer: Custom application behavior
Running the Server
Launch your server with the server launcher module:
# With a configuration file
python -m chuk_protocol_server.server_launcher -c config/my_server.yaml
# Direct handler specification
python -m chuk_protocol_server.server_launcher my_package.handlers:MyHandler --port 8000
# Verbose logging
python -m chuk_protocol_server.server_launcher -c config/my_server.yaml -vv
Example Handlers
Here are examples of handlers for different use cases:
Echo Server Handler
from chuk_protocol_server.handlers.telnet_handler import TelnetHandler
class EchoHandler(TelnetHandler):
async def on_command_submitted(self, command: str) -> None:
await self.send_line(f"Echo: {command}")
Command Processor Handler
from chuk_protocol_server.handlers.line_handler import LineHandler
class CommandHandler(LineHandler):
def __init__(self, reader, writer):
super().__init__(reader, writer)
self.commands = {
"help": self.cmd_help,
"status": self.cmd_status,
"uptime": self.cmd_uptime
}
async def process_line(self, line: str) -> bool:
if not line.strip():
await self.show_prompt()
return True
parts = line.split(maxsplit=1)
cmd = parts[0].lower()
args = parts[1] if len(parts) > 1 else ""
if cmd in ["quit", "exit"]:
await self.end_session("Goodbye!")
return False
if cmd in self.commands:
await self.commands[cmd](args)
else:
await self.send_line(f"Unknown command: {cmd}")
await self.show_prompt()
return True
async def cmd_help(self, args):
await self.send_line("Available commands: help, status, uptime, quit")
async def cmd_status(self, args):
await self.send_line("Server status: OK")
async def cmd_uptime(self, args):
await self.send_line("Server uptime: 3 days, 4 hours")
Terminal Handling
The framework includes sophisticated terminal handling that correctly negotiates capabilities with telnet clients:
- Initial Negotiation: Establishes proper terminal settings at connection time
- Visual Feedback: Echoes characters and provides appropriate visual feedback
- Control Character Handling: Properly processes CR, LF, backspace, and other control characters
- Window Size: Adapts to client terminal dimensions when available
- Terminal Type: Detects client terminal type for specialized behavior
Session Monitoring
For WebSocket servers, you can enable session monitoring to observe client interactions:
websocket:
# ... other options ...
enable_monitoring: true
monitor_path: "/monitor"
Connect to the monitoring endpoint with a WebSocket client:
// Monitor all sessions
const monitor = new WebSocket('ws://localhost:8025/monitor');
monitor.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('Session event:', data);
};
// Watch a specific session
monitor.send(JSON.stringify({
type: 'watch_session',
session_id: 'SESSION_ID'
}));
Extending the Framework
Adding a New Transport
- Create a new server class extending
BaseServer - Implement required methods for your transport
- Add the transport type to the server launcher
Creating Custom Handlers
- Extend one of the base handler classes (BaseHandler, CharacterHandler, LineHandler, TelnetHandler)
- Implement your application logic
- Configure the server to use your handler
Logging
The framework includes comprehensive logging to assist with debugging:
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
Different components use different loggers:
chuk-protocol-server: Main logger for server eventsbase-server: Server lifecycle eventscharacter-handler: Character processing eventswebsocket-adapter: WebSocket connection eventsws-plain-server: WebSocket server events
Performance Considerations
- The server uses asyncio for efficient handling of multiple connections
- Character-by-character processing is more CPU-intensive than line mode
- Connection cleanup is handled carefully to prevent resource leaks
- WebSocket connections include ping/pong frames to detect disconnects
Troubleshooting
Common issues and solutions:
- ^M characters visible: Check that proper terminal negotiations are being sent
- No character echo: Verify ECHO option negotiation
- Slow performance: Reduce logging level in production environments
- Connection resets: Ensure proper error handling in custom handlers
- WebSocket client doesn't exit: Use the
--exit-on-eofflag with websocat
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
Acknowledgements
- Telnet protocol specifications (RFCs 854, 855, 856, etc.)
- The asyncio library for elegant async/await support
- The websockets library for WebSocket protocol support
- The Python community for inspiration and feedback
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file chuk_protocol_server-0.1.1.tar.gz.
File metadata
- Download URL: chuk_protocol_server-0.1.1.tar.gz
- Upload date:
- Size: 50.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80ad1045bd3093341ecd88366feaf9d045dec1302f9a430877bf4c890e37244a
|
|
| MD5 |
5a9748920f10f58ceef01729254fd403
|
|
| BLAKE2b-256 |
fb4665c648487f60c71afc245602062f7325bf6dd764ab7b4b218505f5cffd01
|
File details
Details for the file chuk_protocol_server-0.1.1-py3-none-any.whl.
File metadata
- Download URL: chuk_protocol_server-0.1.1-py3-none-any.whl
- Upload date:
- Size: 67.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fed96890f3eb122f0f775a3391133022e56138e52ed47cf8f0c1f238a09fff53
|
|
| MD5 |
52e9bde8dbdb05935810652d636190f0
|
|
| BLAKE2b-256 |
90b30a184e23b8c3bceb0a554ae31760364a07fb9afb50e6f6b0b6fc93d2a6bb
|