Add zerotick serve command#2
Conversation
Implemented a new `serve` command that provides a Minecraft server status API mirroring the `mcstatus.io` v2 JSON response format.
Key features:
- API endpoint: `GET /v{major}/status/java/{address}` (major version from Cargo.toml)
- In-memory results caching (30 seconds)
- Per-IP rate limiting (5 req/sec)
- Styled request logging in console
- Full MOTD to HTML conversion with Minecraft color codes support
- Minimal dependencies added: axum, tower, tower-http, dashmap
Updated version to 1.0.1 in Cargo.toml.
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
There was a problem hiding this comment.
Pull request overview
Adds a new serve subcommand to ZeroTick so it can run as an HTTP API that serves Minecraft Java server status responses in an mcstatus.io v2-style JSON shape.
Changes:
- Add
zerotick serve --host/--portCLI command and wire it intomain. - Implement an Axum-based HTTP endpoint with basic in-memory caching, rate limiting, and console request logging.
- Add new web/server dependencies (
axum,dashmap, etc.) and bump crate version (used for route versioning).
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main.rs | Dispatches the new Serve command to commands::serve::run. |
| src/commands/serve.rs | New Axum server implementation for /v{N}/status/java/{address} with caching/rate limiting and mcstatus.io-like response structs. |
| src/commands/mod.rs | Exposes the new serve module. |
| src/cli.rs | Adds the Serve subcommand and its flags. |
| Cargo.toml | Adds web/server dependencies and bumps crate version. |
| Cargo.lock | Locks newly added transitive dependencies. |
Question: should the public API path be fixed at /v1/status/java/{address} (independent of crate version), or is it intended to track the crate’s major version?
| let major_version = env!("CARGO_PKG_VERSION") | ||
| .split('.') | ||
| .next() | ||
| .unwrap_or("1"); | ||
| let route = format!("/v{major_version}/status/java/{{address}}"); |
| .and_then(|mut addrs| addrs.next()) | ||
| .map(|addr| addr.ip().to_string()); | ||
|
|
||
| let retrieved_at = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64; |
| Ok(resp) => resp, | ||
| Err(e) => { | ||
| log_request(&address, client_addr, StatusCode::INTERNAL_SERVER_ERROR, start_time.elapsed(), false); | ||
| return (StatusCode::INTERNAL_SERVER_ERROR, format!("Error: {e}")).into_response(); |
| struct AppState { | ||
| cache: DashMap<String, (McStatusResponse, Instant)>, | ||
| rate_limiter: DashMap<SocketAddr, (u32, Instant)>, | ||
| } | ||
|
|
||
| pub async fn run(host: &str, port: u16) -> Result<()> { | ||
| let major_version = env!("CARGO_PKG_VERSION") | ||
| .split('.') | ||
| .next() | ||
| .unwrap_or("1"); | ||
| let route = format!("/v{major_version}/status/java/{{address}}"); | ||
|
|
||
| let state = Arc::new(AppState { | ||
| cache: DashMap::new(), | ||
| rate_limiter: DashMap::new(), | ||
| }); |
| tower-http = "0.6.8" | ||
| tower = "0.5.3" |
| let mut headers = HeaderMap::new(); | ||
| headers.insert("X-Cache-Hit", "true".parse().unwrap()); | ||
| let remaining = 30u64.saturating_sub(timestamp.elapsed().as_secs()); | ||
| headers.insert("X-Cache-Time-Remaining", remaining.to_string().parse().unwrap()); | ||
| return (headers, Json(response.clone())).into_response(); |
| let mut out = format!("<span style=\"{}\">{}", style, comp.text); | ||
| for child in &comp.extra { | ||
| out.push_str(&component_to_html(child)); | ||
| } | ||
| out.push_str("</span>"); | ||
| out |
| pub mods: Vec<McMod>, | ||
| pub software: Option<String>, | ||
| pub plugins: Vec<McPlugin>, |
| } | ||
| }; | ||
|
|
||
| let eula_blocked = crate::mojang::blocked::is_blocked(&resolved.host, resolved.port).await.unwrap_or(false); |
Implemented a new `serve` command that provides a Minecraft server status API mirroring the `mcstatus.io` v2 JSON response format.
Key features:
- API endpoint: `GET /v{major}/status/java/:address` (major version from Cargo.toml)
- In-memory results caching (30 seconds)
- Per-IP rate limiting (5 req/sec)
- Styled request logging in console
- Robust MOTD to HTML conversion with Minecraft color codes and style accumulation
- Memory safety: Background cleanup task for cache and rate limiter state
- CI compatibility: Architecture-specific `target-cpu` optimization
Updated version to 1.0.1 in Cargo.toml.
Added the
servecommand to ZeroTick, allowing it to function as a Minecraft server status API provider. The API uses themcstatus.iov2 JSON format and is served at/v1/status/java/{address}. It includes caching, rate limiting, and styled console logging.PR created automatically by Jules for task 331247894461101888 started by @Hyphonical