initial commit
This commit is contained in:
142
interfaces/websocket/server/cmd/README.md
Normal file
142
interfaces/websocket/server/cmd/README.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# Circles WebSocket Server Binary
|
||||
|
||||
A command-line WebSocket server for hosting Circles with authentication and TLS support.
|
||||
|
||||
## Binary: Server
|
||||
|
||||
### Installation
|
||||
|
||||
Build the binary:
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
# Basic usage - starts server on localhost:8443
|
||||
cargo run
|
||||
|
||||
# Custom host and port
|
||||
cargo run -- --host 0.0.0.0 --port 9000
|
||||
|
||||
# Enable authentication
|
||||
cargo run -- --auth
|
||||
|
||||
# Enable TLS/WSS with certificates
|
||||
cargo run -- --tls --cert /path/to/cert.pem --key /path/to/key.pem
|
||||
|
||||
# Use separate TLS port
|
||||
cargo run -- --tls --cert cert.pem --key key.pem --tls-port 8444
|
||||
|
||||
# Custom Redis URL
|
||||
cargo run -- --redis-url redis://localhost:6379/1
|
||||
|
||||
# Increase verbosity
|
||||
cargo run -- -v # Debug logging
|
||||
cargo run -- -vv # Full debug logging
|
||||
cargo run -- -vvv # Trace logging
|
||||
```
|
||||
|
||||
### Command-Line Options
|
||||
|
||||
| Option | Short | Default | Description |
|
||||
|--------|-------|---------|-------------|
|
||||
| `--host` | `-H` | `127.0.0.1` | Server bind address |
|
||||
| `--port` | `-p` | `8443` | Server port |
|
||||
| `--redis-url` | | `redis://127.0.0.1/` | Redis connection URL |
|
||||
| `--auth` | | `false` | Enable secp256k1 authentication |
|
||||
| `--tls` | | `false` | Enable TLS/WSS support |
|
||||
| `--cert` | | | Path to TLS certificate file (required with --tls) |
|
||||
| `--key` | | | Path to TLS private key file (required with --tls) |
|
||||
| `--tls-port` | | | Separate port for TLS connections |
|
||||
| `--verbose` | `-v` | | Increase verbosity (stackable) |
|
||||
|
||||
### Configuration Examples
|
||||
|
||||
#### Development Server
|
||||
```bash
|
||||
# Simple development server
|
||||
cargo run
|
||||
|
||||
# Development with authentication
|
||||
cargo run -- --auth
|
||||
```
|
||||
|
||||
#### Production Server
|
||||
```bash
|
||||
# Production with TLS and authentication
|
||||
cargo run -- \
|
||||
--host 0.0.0.0 \
|
||||
--port 8080 \
|
||||
--tls \
|
||||
--tls-port 8443 \
|
||||
--cert /etc/ssl/certs/circles.pem \
|
||||
--key /etc/ssl/private/circles.key \
|
||||
--auth \
|
||||
--redis-url redis://redis-server:6379/0
|
||||
```
|
||||
|
||||
#### Custom Redis Configuration
|
||||
```bash
|
||||
# Connect to remote Redis with authentication
|
||||
cargo run -- --redis-url redis://username:password@redis.example.com:6379/2
|
||||
```
|
||||
|
||||
### Logging Levels
|
||||
|
||||
The server supports multiple verbosity levels:
|
||||
|
||||
- **Default** (`cargo run`): Shows only warnings and circle_ws_lib info
|
||||
- **Debug** (`-v`): Shows debug info for circle_ws_lib, info for actix
|
||||
- **Full Debug** (`-vv`): Shows debug for all components
|
||||
- **Trace** (`-vvv+`): Shows trace-level logging for everything
|
||||
|
||||
### TLS/SSL Configuration
|
||||
|
||||
When using `--tls`, you must provide both certificate and key files:
|
||||
|
||||
```bash
|
||||
# Generate self-signed certificate for testing
|
||||
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
|
||||
|
||||
# Run server with TLS
|
||||
cargo run -- --tls --cert cert.pem --key key.pem
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
When `--auth` is enabled, clients must complete secp256k1 authentication:
|
||||
1. Client connects to WebSocket
|
||||
2. Server sends authentication challenge
|
||||
3. Client signs challenge with private key
|
||||
4. Server verifies signature and grants access
|
||||
|
||||
### Redis Integration
|
||||
|
||||
The server uses Redis for:
|
||||
- Session management
|
||||
- Message persistence
|
||||
- Cross-instance communication (in clustered deployments)
|
||||
|
||||
Supported Redis URL formats:
|
||||
- `redis://localhost/` - Local Redis, default database
|
||||
- `redis://localhost:6379/1` - Local Redis, database 1
|
||||
- `redis://user:pass@host:port/db` - Authenticated Redis
|
||||
- `rediss://host:port/` - Redis with TLS
|
||||
|
||||
### Error Handling
|
||||
|
||||
The server provides clear error messages for common configuration issues:
|
||||
- Missing TLS certificate or key files
|
||||
- Invalid Redis connection URLs
|
||||
- Port binding failures
|
||||
- Authentication setup problems
|
||||
|
||||
### Dependencies
|
||||
|
||||
- `actix-web`: Web server framework
|
||||
- `tokio-tungstenite`: WebSocket implementation
|
||||
- `redis`: Redis client
|
||||
- `rustls`: TLS implementation
|
||||
- `clap`: Command-line argument parsing
|
150
interfaces/websocket/server/cmd/main.rs
Normal file
150
interfaces/websocket/server/cmd/main.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
use hero_websocket_server::{ServerBuilder, TlsConfigError};
|
||||
use clap::Parser;
|
||||
use dotenv::dotenv;
|
||||
use log::info;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
#[clap(short = 'H', long, value_parser, default_value = "127.0.0.1")]
|
||||
host: String,
|
||||
|
||||
#[clap(short, long, value_parser, default_value_t = 8443)]
|
||||
port: u16,
|
||||
|
||||
#[clap(long, value_parser, default_value = "redis://127.0.0.1/")]
|
||||
redis_url: String,
|
||||
|
||||
#[clap(long, help = "Enable authentication")]
|
||||
auth: bool,
|
||||
|
||||
#[clap(long, help = "Enable TLS/WSS")]
|
||||
tls: bool,
|
||||
|
||||
#[clap(long, value_parser, help = "Path to TLS certificate file")]
|
||||
cert: Option<String>,
|
||||
|
||||
#[clap(long, value_parser, help = "Path to TLS private key file")]
|
||||
key: Option<String>,
|
||||
|
||||
#[clap(long, value_parser, help = "Separate port for TLS connections")]
|
||||
tls_port: Option<u16>,
|
||||
|
||||
#[clap(short, long, action = clap::ArgAction::Count, help = "Increase verbosity (-v for debug, -vv for trace)")]
|
||||
verbose: u8,
|
||||
|
||||
#[clap(long, help = "Remove timestamps from log output")]
|
||||
no_timestamp: bool,
|
||||
|
||||
#[clap(long, help = "Enable webhook handling")]
|
||||
webhooks: bool,
|
||||
|
||||
#[clap(long, value_parser, help = "Worker ID for the server")]
|
||||
worker_id: String,
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
// Configure logging based on verbosity level
|
||||
let log_config = match args.verbose {
|
||||
0 => {
|
||||
// Default: suppress actix server logs, show only hero_websocket_server info and above
|
||||
"warn,hero_websocket_server=info"
|
||||
}
|
||||
1 => {
|
||||
// -v: show debug for hero_websocket_server, info for actix
|
||||
"info,hero_websocket_server=debug,actix_server=info"
|
||||
}
|
||||
2 => {
|
||||
// -vv: show debug for everything
|
||||
"debug"
|
||||
}
|
||||
_ => {
|
||||
// -vvv and above: show trace for everything
|
||||
"trace"
|
||||
}
|
||||
};
|
||||
|
||||
std::env::set_var("RUST_LOG", log_config);
|
||||
|
||||
// Configure env_logger with or without timestamps
|
||||
if args.no_timestamp {
|
||||
env_logger::Builder::from_default_env()
|
||||
.format_timestamp(None)
|
||||
.init();
|
||||
} else {
|
||||
env_logger::init();
|
||||
}
|
||||
|
||||
// Validate TLS configuration
|
||||
if args.tls && (args.cert.is_none() || args.key.is_none()) {
|
||||
eprintln!("Error: TLS is enabled but certificate or key path is missing");
|
||||
eprintln!("Use --cert and --key to specify certificate and key files");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let mut builder = ServerBuilder::new()
|
||||
.host(args.host.clone())
|
||||
.port(args.port)
|
||||
.redis_url(args.redis_url.clone())
|
||||
.worker_id(args.worker_id.clone());
|
||||
|
||||
if args.auth {
|
||||
builder = builder.with_auth();
|
||||
}
|
||||
|
||||
if args.tls {
|
||||
if let (Some(cert), Some(key)) = (args.cert.clone(), args.key.clone()) {
|
||||
builder = builder.with_tls(cert, key);
|
||||
} else {
|
||||
eprintln!("Error: TLS is enabled but --cert or --key is missing.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(tls_port) = args.tls_port {
|
||||
builder = builder.with_tls_port(tls_port);
|
||||
}
|
||||
|
||||
if args.webhooks {
|
||||
builder = builder.with_webhooks();
|
||||
}
|
||||
|
||||
let server = match builder.build() {
|
||||
Ok(server) => server,
|
||||
Err(e) => {
|
||||
eprintln!("Error building server: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
println!("🚀 Starting Circles WebSocket Server");
|
||||
println!("📋 Configuration:");
|
||||
println!(" Host: {}", args.host);
|
||||
println!(" Port: {}", args.port);
|
||||
if let Some(tls_port) = args.tls_port {
|
||||
println!(" TLS Port: {}", tls_port);
|
||||
}
|
||||
println!(" Authentication: {}", if args.auth { "ENABLED" } else { "DISABLED" });
|
||||
println!(" TLS/WSS: {}", if args.tls { "ENABLED" } else { "DISABLED" });
|
||||
println!(" Webhooks: {}", if args.webhooks { "ENABLED" } else { "DISABLED" });
|
||||
|
||||
if args.tls {
|
||||
if let (Some(cert), Some(key)) = (&args.cert, &args.key) {
|
||||
println!(" Certificate: {}", cert);
|
||||
println!(" Private Key: {}", key);
|
||||
}
|
||||
}
|
||||
|
||||
if args.webhooks {
|
||||
println!(" Webhook secrets loaded from environment variables:");
|
||||
println!(" - STRIPE_WEBHOOK_SECRET");
|
||||
println!(" - IDENFY_WEBHOOK_SECRET");
|
||||
}
|
||||
println!();
|
||||
|
||||
let (server_task, _server_handle) = server.spawn_circle_server()?;
|
||||
server_task.await?
|
||||
}
|
Reference in New Issue
Block a user