A modern, colorful terminal-based chat application written in Rust with async/await support.
- 🎨 Colorized Output - Beautiful, color-coded terminal interface with timestamps
- 👥 Multi-user Support - Multiple clients can connect simultaneously
- 🔄 Real-time Messaging - Instant message broadcasting to all connected users
- 💬 Direct Messaging - Send private messages to specific users with
/dmand/rcommands - 📁 File Transfer - Send files up to 100MB to other users with
/sendcommand (requires acceptance) - 🏷️ Username Colorization - Each user gets a unique, consistent color
- ⚡ Async I/O - Built on Tokio for high-performance async networking
- 🔧 Modular Architecture - Clean separation between client, server, and shared code
- 🛡️ Smart Username Handling - Automatic renaming for duplicate usernames
- 🔁 Auto-Reconnect - Exponential backoff reconnection when server goes down
- 🔒 Security Hardened - Rate limiting, input validation, connection limits, and memory safety
- 🔐 Native TLS Support - Built-in TLS encryption with Let's Encrypt certificates
- 📊 Rich Logging - Categorized logs (INFO, ERROR, WARN, OK, SYSTEM, CHAT)
- 📝 Command History - Full readline support with persistent command history (up to 1000 commands)
- ⌨️ Tab Completion - Smart autocomplete for commands and usernames
- 💡 Inline Hints - Visual hints showing available completions as you type
- 🚀 Production Ready - Docker and native systemd deployment options
- 👮 Admin Commands - Server-side
/kick,/ban,/renameand user management - 📝 User Status - Set a custom status message visible to other users
- 🔢 Version Compatibility - Client/server version checking with upgrade notifications
The project is organized into three crates:
- client - Terminal client application
- server - Multi-threaded chat server
- shared - Shared code (message protocol, networking, logging)
- Rust 1.75+ (edition 2024)
- Cargo
Download the latest release for your platform from GitHub Releases.
# Download
curl -LO https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_client-linux-x86_64
curl -LO https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_server-linux-x86_64
# Make executable
chmod +x rust_chat_client-linux-x86_64 rust_chat_server-linux-x86_64
# Run client
./rust_chat_client-linux-x86_64
# Run server
./rust_chat_server-linux-x86_64# Download
curl -LO https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_client-linux-arm64
curl -LO https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_server-linux-arm64
# Make executable
chmod +x rust_chat_client-linux-arm64 rust_chat_server-linux-arm64
# Run client
./rust_chat_client-linux-arm64
# Run server
./rust_chat_server-linux-arm64# Download
curl -LO https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_client-macos-arm64
curl -LO https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_server-macos-arm64
# Make executable
chmod +x rust_chat_client-macos-arm64 rust_chat_server-macos-arm64
# Run client (may need to allow in System Preferences > Security on first run)
./rust_chat_client-macos-arm64
# Run server
./rust_chat_server-macos-arm64# Download
curl -LO https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_client-macos-x86_64
curl -LO https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_server-macos-x86_64
# Make executable
chmod +x rust_chat_client-macos-x86_64 rust_chat_server-macos-x86_64
# Run client (may need to allow in System Preferences > Security on first run)
./rust_chat_client-macos-x86_64
# Run server
./rust_chat_server-macos-x86_64# Download (PowerShell)
Invoke-WebRequest -Uri "https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_client-windows-x86_64.exe" -OutFile "rust_chat_client.exe"
Invoke-WebRequest -Uri "https://github.com/mikemiles-dev/rust_chat/releases/latest/download/rust_chat_server-windows-x86_64.exe" -OutFile "rust_chat_server.exe"
# Run client
.\rust_chat_client.exe
# Run server
.\rust_chat_server.exeAll binaries support these environment variables:
# Client
CHAT_SERVER="tls://milesrust.chat:8443" CHAT_USERNAME="YourName" ./rust_chat_client-<platform>
# Server
CHAT_SERVER_ADDR="0.0.0.0:8080" CHAT_SERVER_MAX_CLIENTS="100" ./rust_chat_server-<platform>Connect to the live server instantly with Docker (no installation required):
# Interactive mode (will prompt for username)
docker run -it --rm ghcr.io/mikemiles-dev/rust_chat-client:latest
# Connect to live server with username
docker run -it --rm \
-e CHAT_SERVER=tls://milesrust.chat:8443 \
-e CHAT_USERNAME=YourName \
ghcr.io/mikemiles-dev/rust_chat-client:latest
# Connect to local server
docker run -it --rm \
-e CHAT_SERVER=127.0.0.1:8080 \
-e CHAT_USERNAME=YourName \
ghcr.io/mikemiles-dev/rust_chat-client:latestImage Details:
- Registry:
ghcr.io/mikemiles-dev/rust_chat-client - Tags:
latest, version tags (e.g.,v1.0.0) - Platforms: linux/amd64, linux/arm64
To build your own image:
docker build -f client/Dockerfile -t rust-chat-client .
docker run -it --rm rust-chat-clientcargo run --bin serverThe server will start on 0.0.0.0:8080 by default.
You can use server commands:
/help # Show available commands
/list # List connected users
/kick USER # Kick a user
/rename U N # Rename user U to N
/ban USER # Ban a user (by IP)
/ban IP # Ban an IP directly
/unban IP # Unban an IP
/banlist # List banned IPs
/quit # Shutdown server
Configure the server using environment variables:
# Custom address and port
CHAT_SERVER_ADDR="127.0.0.1:9000" cargo run --bin server
# Custom max clients
CHAT_SERVER_MAX_CLIENTS="50" cargo run --bin serverOption 1: Connect to Live Demo Server (Default)
The client connects to the live TLS-secured server by default:
cargo run --bin client
# Press Enter to accept default server (tls://milesrust.chat:8443)
# Enter your usernameOr skip the prompts with environment variables:
CHAT_USERNAME="YourName" cargo run --bin clientOption 2: Connect to Local Server
To connect to a local development server instead:
CHAT_SERVER="127.0.0.1:8080" cargo run --bin clientOr enter the server address when prompted.
Environment Variables:
# Connect to local server with custom username
CHAT_SERVER="127.0.0.1:8080" CHAT_USERNAME="Alice" cargo run --bin client
# Connect to custom server
CHAT_SERVER="tls://your-server.com:8443" CHAT_USERNAME="Bob" cargo run --bin clientFor production deployment with TLS encryption:
- deploy/digital_ocean/ - Deploy on Digital Ocean with tmux + native TLS
Complete setup scripts and documentation included.
Once connected to the server, clients can use the following commands:
/help- Display available commands/quit- Exit the chat application/list- List all connected users (with their status if set)/dm <USERNAME> <MESSAGE>- Send a direct message to a specific user/r <MESSAGE>- Reply to the last user who sent you a DM/send <USERNAME> <FILEPATH>- Request to send a file to a specific user (max 100MB)/accept <USERNAME>- Accept a pending file transfer from a user/reject <USERNAME>- Reject a pending file transfer from a user/rename <NEW_NAME>- Change your username/status <MESSAGE>- Set your status (visible in/list)/status- Clear your status- Any other text - Send a message to all connected users
While the server is running, administrators can use these commands:
/helpor/h- Display available server commands/list- Show all currently connected users with count/kick <username>- Kick a user from the server/rename <username> <newname>- Rename a user/ban <username>- Ban a user by their username (resolves to IP)/ban <ip>- Ban an IP address directly/unban <ip>- Unban an IP address/banlist- List all banned IP addresses/quitor/q- Gracefully shutdown the server
Both client and server support advanced input features powered by rustyline:
Command History:
- ↑/↓ arrows - Navigate through previous commands
- Ctrl+R - Reverse search through history
- Persistent - Up to 1000 commands stored per session
Tab Completion:
- Client: Type
/then pressTABto see all commands - Client: Type
/dmthen pressTABto autocomplete usernames - Server: Type
/then pressTABto see all server commands - Smart filtering - Only shows matching completions
Visual Hints:
- Inline gray text shows possible completions as you type
- Multiple matches display all options
Example:
# Type "/h" and see hint showing "elp"
/h[elp]
# Press TAB to complete
/help
# Type "/dm A" and press TAB to see users starting with A
/dm Alice
# Press ↑ to repeat last command[12:34:56] [INFO] Enter Chat Server (default: tls://milesrust.chat:8443):
[12:34:58] [INFO] Enter Chat Name (default: Guest):
Alice
[12:34:59] [SYSTEM] Alice has joined the chat
Alice █
[12:35:02] [SYSTEM] Bob has joined the chat
Alice hello everyone!
[12:35:05] [CHAT] Bob: hi Alice!
Alice /dm Bob Hey, want to chat privately?
[12:35:10] [DM] from Bob: Sure thing!
Alice /r Perfect! Let's discuss the project.
[12:34:50] [OK] Chat Server started at 0.0.0.0:8080
[12:34:50] [INFO] To change address, set CHAT_SERVER_ADDR environment variable
[12:34:50] [INFO] To change max clients, set CHAT_SERVER_MAX_CLIENTS environment variable
[12:34:50] [INFO] Server commands: /help, /list, /quit
[12:34:59] [SYSTEM] Alice has joined the chat
[12:35:02] [SYSTEM] Bob has joined the chat
/list
[12:35:15] [INFO] Connected users (2):
[12:35:15] [INFO] - Alice - AFK for lunch
[12:35:15] [INFO] - Bob
[12:35:30] [SYSTEM] Charlie has joined the chat
/rename Charlie Chuck
[12:35:32] [OK] Renaming user 'Charlie' to 'Chuck'
[12:35:32] [CHAT] Charlie is now known as Chuck (renamed by server)
/kick Bob
[12:35:45] [WARN] Kicking user: Bob
[12:35:45] [SYSTEM] Bob has left the chat
/ban Alice
[12:35:50] [WARN] Banned IP 192.168.1.100 (user 'Alice')
[12:35:50] [INFO] Disconnecting user 'Alice' from banned IP
[12:35:50] [SYSTEM] Alice has left the chat
/banlist
[12:35:55] [INFO] Banned IPs (1):
[12:35:55] [INFO] - 192.168.1.100
/unban 192.168.1.100
[12:36:00] [OK] Unbanned IP 192.168.1.100
/quit
[12:36:05] [INFO] Server shutting down...
rust_chat/
├── client/
│ └── src/
│ ├── main.rs # Entry point and setup
│ ├── client.rs # Client logic and message handling
│ ├── input.rs # Client command processing
│ ├── completer.rs # Tab completion for commands & usernames
│ └── readline_helper.rs # Rustyline integration with async
├── server/
│ └── src/
│ ├── main.rs # Server entry point and command handling
│ ├── input.rs # Server command processing
│ ├── completer.rs # Tab completion for server commands
│ ├── readline_helper.rs # Rustyline integration with async
│ └── user_connection/
│ ├── mod.rs # UserConnection struct and event loop
│ ├── error.rs # Error types and Display impl
│ ├── handlers.rs # Message processing logic
│ └── rate_limiting.rs # Token bucket rate limiter
├── shared/
│ └── src/
│ ├── lib.rs # Module exports
│ ├── input.rs # Shared UserInput trait
│ ├── logger.rs # Colorized logging utilities
│ ├── message.rs # Message protocol
│ └── network.rs # TCP message handling
└── deploy/
└── digital_ocean/
├── setup-certificates.sh # Get Let's Encrypt TLS certificates
├── start-server.sh # Start server in tmux with TLS
├── README.md # Complete Digital Ocean guide
└── QUICK_START.md # Quick reference
All output is color-coded by category:
- INFO (Cyan) - General information
- OK (Green) - Success messages
- ERROR (Red) - Error messages
- WARN (Yellow) - Warnings
- SYSTEM (Magenta) - User join/leave notifications
- CHAT (White) - Chat messages with colored usernames
Each username is assigned a consistent color using hash-based selection from 12 vibrant colors. The same username always appears in the same color, making it easy to follow conversations.
If you try to join with a username that's already taken, the server automatically appends a random 4-digit suffix (e.g., Alice_1234).
Powered by rustyline, both client and server feature a rich command-line experience:
Command History Features:
- Navigation: Use ↑/↓ arrow keys to browse through command history
- Reverse Search: Press Ctrl+R to search backwards through history
- Persistent Storage: Up to 1,000 commands remembered per session
- Auto-add: Commands are automatically added to history after execution
Tab Completion Features:
- Command Completion: Press TAB after typing
/to see all available commands - Username Completion (Client only): Type
/dmand press TAB to autocomplete usernames from connected users - Smart Filtering: Completions filter based on what you've already typed
- Multiple Matches: Shows all matching options when ambiguous
Visual Hints:
- Inline gray text appears as you type, showing the most likely completion
- Helps you discover commands without referring to documentation
Implementation Details:
- Runs in a separate blocking thread to maintain async performance
- Communicates with async runtime via
tokio::sync::mpscchannels - Client tracks connected users list for username autocomplete
- Updates dynamically when
/listcommand is executed
Example interaction:
# Type partial command
$ /h
↳ [gray hint: "elp" shown]
# Press TAB
$ /help
# Type /dm and TAB to see all users
$ /dm [TAB]
Alice Bob Charlie
# Type first letter and TAB
$ /dm A[TAB]
$ /dm AliceIf the connection to the server is lost, the client automatically attempts to reconnect with exponential backoff:
- Initial delay: 1 second
- Maximum delay: 60 seconds
- Strategy: Doubles the wait time after each failed attempt (1s → 2s → 4s → 8s → 16s → 32s → 60s)
- Preservation: Your username and last DM sender are preserved across reconnections
- Auto-rejoin: Automatically rejoins the server with the same username when reconnected
- Ghost session reclaim: If your old connection is still "alive" on the server (within 60s timeout), you'll seamlessly reclaim your session without being renamed
Example reconnection sequence:
Disconnected from server
Attempting to reconnect to 127.0.0.1:8080 (attempt 1)...
Reconnection attempt 1 failed: Connection refused. Retrying in 1s...
Attempting to reconnect to 127.0.0.1:8080 (attempt 2)...
Reconnection attempt 2 failed: Connection refused. Retrying in 2s...
...
Attempting to reconnect to 127.0.0.1:8080 (attempt 5)...
Reconnected to server!
Alice has joined the chat
Ghost Session Reclaim: When you disconnect unexpectedly (network drop, laptop sleep, etc.), your session may still be "alive" on the server for up to 60 seconds until the ping timeout detects it. Previously, reconnecting during this window would give you a renamed username (e.g., Alice_1234). Now, the server recognizes it's the same client (via session token and IP matching) and lets you reclaim your original username seamlessly.
Set a custom status message that other users can see:
- Set status:
/status <message>- Set your status (e.g.,/status AFK for lunch) - Clear status:
/status- Remove your status - View statuses: Use
/listto see all users with their statuses - Max length: 128 characters
- Persistence: Status persists across reconnections (network drops, restarts)
- Auto-cleanup: Status is cleared on explicit
/quit, kick, or ban
Example:
# Set your status
/status In a meeting
# Other users see when they /list:
Current users online:
- Alice - In a meeting
- Bob
- Charlie - BRB
# Clear your status
/statusSend private messages to specific users:
- Send a DM:
/dm <username> <message>- Send a direct message to a specific user - Reply to DM:
/r <message>- Quick reply to the last person who sent you a DM - Privacy: The server logs that DMs are happening but doesn't display the message content
- Validation: Server validates that the recipient exists before sending
Send files directly to other users with acceptance:
- Request transfer:
/send <username> <filepath>- Request to send any file up to 100MB - Accept transfer:
/accept <sender>- Accept a pending file transfer - Reject transfer:
/reject <sender>- Reject a pending file transfer - Auto-save: Accepted files are automatically saved to
downloads/directory - Privacy: Files are sent directly to the recipient (server relays but doesn't store)
- Validation: Server validates recipient exists before transferring
- Supported: All file types (images, documents, archives, etc.)
Example:
# Sender requests to send a file
/send Alice /path/to/document.pdf
# Output: Requesting to send 'document.pdf' (1.2 MB) to Alice...
# Output: File transfer request sent. Waiting for Alice to accept...
# Recipient (Alice) sees:
[FILE REQUEST from Bob]: 'document.pdf' (1.2 MB)
Use /accept Bob to accept or /reject Bob to decline
# Alice accepts:
/accept Bob
# Output: Accepting file 'document.pdf' from Bob...
# Bob's client then sends the file:
# Output: Bob accepted file transfer for 'document.pdf'
# Output: Sending file 'document.pdf' (1234567 bytes) to Alice...
# Output: File 'document.pdf' sent to Alice
# Alice receives:
[FILE from Bob]: 'document.pdf' (1234567 bytes)
File saved to: downloads/document.pdfThe application implements comprehensive security measures to protect against common network attacks:
- Username Validation:
- Maximum length: 32 characters
- Allowed characters: alphanumeric, underscore, and hyphen only
- Empty usernames rejected
- Message Validation:
- Maximum message size: 8KB (prevents memory exhaustion)
- Maximum content length: 1KB per message
- Empty messages blocked (client and server-side)
- Integer overflow protection with safe type conversion
- Token Bucket Algorithm: 10 messages per second per connection
- Auto-refill: Resets every second
- Smart Filtering: Join messages excluded from rate limits
- User Feedback: Clients receive "Rate limit exceeded" errors
- Protection Against: Spam floods, DoS attacks, message bombing
- Connection Limits: Configurable max clients (default: 100)
- Enforcement: Server rejects new connections when at capacity
- Atomic Tracking: Thread-safe connection counting
- Auto-cleanup: Connections automatically decremented on disconnect
- Graceful Handling: Proper cleanup on all disconnect scenarios
- Zero
unsafeCode: Entire codebase is memory-safe Rust - No
.unwrap()Panics: All error paths use safeResultpropagation - Bounded Allocations: All memory allocations are size-limited
- Overflow Protection: Integer conversions use
try_from()for safety
- Message Size Limits: 8KB maximum per message
- Chunked Protocol: Supports large messages without blocking
- Acknowledgment System: "OK" handshake prevents desynchronization
- Clean Disconnects: Explicit connection shutdown before reconnect
- Backpressure Handling: Broadcast channel sized for burst traffic
- Validated Inputs: All user inputs are validated before processing
- Error Messages: Clear feedback sent to clients for invalid operations
- Logging: Security events logged with warnings
- Graceful Degradation: Invalid requests don't crash the server
| Security Feature | Implementation |
|---|---|
| Max Message Size | 8KB |
| Max File Size | 100MB |
| Max Username Length | 32 characters |
| Max Message Content | 1KB |
| Rate Limit | 10 messages/second |
| Connection Limit | Configurable (default: 100) |
| Memory Safety | 100% safe Rust |
| Input Validation | Comprehensive |
Note: For production deployment, TLS encryption is built-in. Consider adding authentication and E2E encryption for enhanced security.
The client and server perform version checking on connection:
- Automatic Check: Client sends its version to the server on connect
- Mismatch Handling: If versions don't match, server disconnects client with an error
- Upgrade Instructions: Error message includes a link to the GitHub README for upgrade instructions
- Compile-time Version: Version is automatically derived from
Cargo.toml
Example version mismatch error:
[ERROR] Version mismatch: client v0.1.8 != server v0.1.9
[ERROR] Please upgrade your binary or Docker image. See: https://github.com/mikemiles-dev/rust_chat#readme
Messages are sent over TCP with a custom chunked protocol that supports:
- Join notifications
- Leave notifications
- Chat messages
- Direct messages
- Username renames
- User list requests
- User status updates
- File transfers
- Version checking
- Error messages
cargo buildcargo build --releasecargo test# Run clippy
cargo clippy --all-targets --all-features
# Run with strict warnings
cargo clippy --all-targets --all-features -- -D warningsDeploy to Digital Ocean with native TLS encryption:
deploy/digital_ocean/ - Complete deployment guide
- ✅ Interactive setup script for Let's Encrypt certificates
- ✅ Native TLS encryption (no reverse proxy needed)
- ✅ Server management via tmux
- ✅ Interactive server commands (
/kick,/list, etc.) - ✅ Auto-renewal for certificates
- ✅ Runs on port 8443
See deploy/digital_ocean/QUICK_START.md for rapid deployment or deploy/digital_ocean/README.md for complete documentation.
- tokio - Async runtime with full features
- colored - Terminal colors for output
- chrono - Timestamp formatting
- rustyline - Readline-like library for command history and tab completion
- rand - Random username generation for collision handling
- tokio-rustls - Native TLS implementation
- rustls - Modern TLS library
- rustls-pemfile - PEM certificate parsing
- webpki-roots - Mozilla's root certificates for TLS validation
- Certbot - Let's Encrypt certificate management
- tmux - Terminal multiplexer for server management
- Docker - Optional containerized client deployment
Contributions are welcome! Please ensure:
- Code passes
cargo clippywith no warnings - Code is properly formatted with
cargo fmt - All tests pass with
cargo test
This project is available for educational and personal use.
- TLS/SSL encryption - Implemented with native TLS (tokio-rustls)
- File sharing - Send files up to 100MB with
/sendcommand (requires recipient acceptance) - End-to-end encryption for direct messages
- User authentication system
- Chat rooms/channels
- Message history and persistence
- Read timeouts for slowloris protection
- GUI client
