hexz_cli/cmd/sys/serve.rs
1//! HTTP server for exposing Hexz snapshots over network protocols.
2//!
3//! This command starts a server that exposes Hexz snapshot data over various
4//! network protocols (HTTP, NBD, S3), enabling remote access without local
5//! snapshot files. Supports daemon mode for background operation and is designed
6//! for high-performance remote snapshot access.
7//!
8//! # Server Modes
9//!
10//! ## HTTP Mode (Default)
11//!
12//! **Protocol:** HTTP/1.1 with Range request support
13//! **Port:** Configurable (default: varies by invocation)
14//! **Endpoints:**
15//! - `GET /disk` - Serves disk image stream
16//! - `GET /memory` - Serves memory dump stream (if present)
17//! - `GET /info` - Returns snapshot metadata (JSON)
18//!
19//! **Range Request Support:**
20//! - Supports `Range: bytes=start-end` header
21//! - Enables efficient random access and partial reads
22//! - Used by HTTP storage backend for transparent remote mounting
23//!
24//! **Use Cases:**
25//! - Remote snapshot access over networks
26//! - HTTP storage backend testing
27//! - Web-based snapshot browsing
28//! - Container registry-like snapshot distribution
29//!
30//! **Performance:**
31//! - Sequential reads: ~100-500 MB/s (network-bound)
32//! - Random reads: ~1000-5000 IOPS (depends on network latency)
33//! - Concurrent connections: Handled via Tokio async runtime
34//!
35//! ## NBD Mode (`--nbd`)
36//!
37//! **Protocol:** NBD (Network Block Device) protocol
38//! **Port:** Configurable
39//! **Features:**
40//! - Block device semantics (read-only currently)
41//! - Compatible with standard NBD clients (`nbd-client`)
42//! - Lower overhead than HTTP for sequential access
43//!
44//! **Use Cases:**
45//! - Remote block device mounting
46//! - Performance testing and benchmarking
47//! - Integration with NBD-aware tools
48//!
49//! **Client Usage:**
50//! ```bash
51//! # Start NBD server
52//! hexz serve snapshot.hxz --nbd --port 10809
53//!
54//! # Connect from client
55//! sudo nbd-client server-ip 10809 /dev/nbd0
56//! sudo mount /dev/nbd0 /mnt
57//! ```
58//!
59//! ## S3 Gateway Mode (`--s3`)
60//!
61//! **Protocol:** S3-compatible REST API
62//! **Status:** Not yet implemented
63//! **Planned Features:**
64//! - S3 GetObject with range support
65//! - Bucket/object listing
66//! - Compatible with S3 storage backend
67//!
68//! # Server Configuration
69//!
70//! **Port Binding:**
71//! - Binds to `127.0.0.1:<port>` (localhost only)
72//! - Default ports vary by mode (consult CLI help)
73//! - Ensure firewall rules allow inbound connections
74//!
75//! **Daemon Mode:**
76//! - Detaches from terminal and runs in background
77//! - Logs redirected to `/tmp/hexz-serve.log` and `/tmp/hexz-serve.err`
78//! - Working directory: Current directory (not `/`)
79//! - No PID file created (use systemd or similar for management)
80//!
81//! **Snapshot Loading:**
82//! - Opens snapshot read-only
83//! - Loads compression dictionary if present
84//! - Initializes appropriate decompressor (LZ4 or Zstd)
85//! - No caching configured (each request decompresses on-demand)
86//!
87//! # Security Considerations
88//!
89//! **WARNING:** This server has no authentication or encryption.
90//!
91//! - **Do not expose to untrusted networks**
92//! - Use behind a reverse proxy (nginx, haproxy) for production
93//! - Consider TLS termination at proxy level
94//! - Implement authentication at proxy layer
95//!
96//! **Recommendations:**
97//! - Bind to localhost (`127.0.0.1`) for local access
98//! - Use SSH tunneling for remote access: `ssh -L 8080:localhost:8080 server`
99//! - Deploy behind VPN for internal network access
100//! - Use firewall rules to restrict access
101//!
102//! # Performance Tuning
103//!
104//! **Concurrency:**
105//! - Uses Tokio multi-threaded runtime (all CPU cores)
106//! - Each connection handled concurrently
107//! - No per-connection memory overhead beyond request buffers
108//!
109//! **Compression:**
110//! - Decompression happens on-demand for each request
111//! - No server-side caching (stateless design)
112//! - LZ4: ~800-2000 MB/s decompression per core
113//! - Zstd: ~400-800 MB/s decompression per core
114//!
115//! **Network:**
116//! - Performance limited by network bandwidth and latency
117//! - Use 10 GbE or faster for multi-GB snapshots
118//! - Consider proximity to clients (same datacenter/region)
119//!
120//! # Common Usage Patterns
121//!
122//! ```bash
123//! # Start HTTP server on port 8080
124//! hexz serve snapshot.hxz --port 8080
125//!
126//! # Start as daemon (background process)
127//! hexz serve snapshot.hxz --port 8080 --daemon
128//!
129//! # Start NBD server
130//! hexz serve snapshot.hxz --nbd --port 10809
131//!
132//! # Access from remote client
133//! curl -H "Range: bytes=0-1024" http://server:8080/disk
134//!
135//! # Mount via HTTP backend
136//! hexz mount http://server:8080 /mnt
137//! ```
138
139use anyhow::Result;
140use daemonize::Daemonize;
141use hexz_core::File as HexzFile;
142use hexz_core::store::local::FileBackend;
143use std::fs::File;
144use std::sync::Arc;
145
146/// Executes the serve command to start a network server.
147///
148/// Opens a Hexz snapshot and starts a server that exposes it over HTTP, NBD,
149/// or S3 protocol. The server runs until interrupted (Ctrl+C) or, in daemon mode,
150/// until explicitly killed.
151///
152/// # Arguments
153///
154/// * `hexz_path` - Path to the `.hxz` snapshot file to serve
155/// * `port` - TCP port to bind to
156/// * `daemon` - If true, daemonize the process and run in background
157/// * `nbd` - If true, use NBD protocol; otherwise use HTTP
158/// * `s3` - If true, use S3 gateway mode (not yet implemented)
159///
160/// # Server Startup Sequence
161///
162/// 1. **Daemonization** (if requested):
163/// - Detach from terminal
164/// - Redirect stdout to `/tmp/hexz-serve.log`
165/// - Redirect stderr to `/tmp/hexz-serve.err`
166///
167/// 2. **Snapshot Loading**:
168/// - Open snapshot file via `FileBackend`
169/// - Read and parse header
170/// - Load compression dictionary if present
171/// - Initialize decompressor (LZ4 or Zstd)
172///
173/// 3. **Server Start**:
174/// - Create Tokio multi-threaded runtime
175/// - Start HTTP or NBD server on specified port
176/// - Listen for incoming connections
177///
178/// 4. **Serving**:
179/// - Handle requests until process is interrupted
180/// - Each request decompresses data on-demand
181/// - No persistent state or caching
182///
183/// # Protocol Selection
184///
185/// - If `nbd=true`: Start NBD server via `hexz_server::serve_nbd()`
186/// - If `s3=true`: Reserved for future S3 gateway (currently prints error)
187/// - Otherwise: Start HTTP server via `hexz_server::serve_http()`
188///
189/// # Errors
190///
191/// Returns an error if:
192/// - Snapshot file cannot be opened or read
193/// - Header or dictionary cannot be parsed (corrupted snapshot)
194/// - Port is already in use (address binding fails)
195/// - Daemonization fails (resource limits, permissions)
196/// - Server fails to start (Tokio runtime error)
197///
198/// # Examples
199///
200/// ```no_run
201/// use hexz_cli::cmd::sys::serve;
202///
203/// // Start HTTP server on port 8080
204/// serve::run(
205/// "snapshot.hxz".to_string(),
206/// 8080,
207/// false, // not daemon
208/// false, // HTTP mode
209/// false, // not S3
210/// )?;
211///
212/// // Start NBD server as daemon
213/// serve::run(
214/// "snapshot.hxz".to_string(),
215/// 10809,
216/// true, // daemon mode
217/// true, // NBD mode
218/// false,
219/// )?;
220/// # Ok::<(), anyhow::Error>(())
221/// ```
222pub fn run(hexz_path: String, port: u16, daemon: bool, nbd: bool, s3: bool) -> Result<()> {
223 if daemon {
224 let log_dir = std::env::var("XDG_RUNTIME_DIR")
225 .or_else(|_| std::env::var("TMPDIR"))
226 .unwrap_or_else(|_| "/tmp".to_string());
227 let stdout = File::create(format!("{}/hexz-serve.log", log_dir))
228 .or_else(|_| File::create("/dev/null"))?;
229 let stderr = File::create(format!("{}/hexz-serve.err", log_dir))
230 .or_else(|_| File::create("/dev/null"))?;
231
232 Daemonize::new()
233 .working_directory(".")
234 .stdout(stdout)
235 .stderr(stderr)
236 .start()?;
237 } else {
238 println!("Starting Hexz server on port {}", port);
239 }
240
241 tokio::runtime::Builder::new_multi_thread()
242 .enable_all()
243 .build()?
244 .block_on(async {
245 let backend = Arc::new(FileBackend::new(std::path::Path::new(&hexz_path))?);
246 let snap = HexzFile::open(backend, None)?;
247
248 if nbd {
249 hexz_server::serve_nbd(snap, port).await
250 } else if s3 {
251 eprintln!("Error: S3 gateway feature is not yet implemented.");
252 Ok(())
253 } else {
254 hexz_server::serve_http(snap, port).await
255 }
256 })
257}