33## Project Overview
44
55** Candy** is a modern, lightweight web server written in Rust. It supports:
6- - Static file serving
7- - Reverse proxying
6+
7+ - Static file serving with directory listing support
8+ - Reverse proxying to backend servers
89- Lua scripting (optional feature)
9- - SSL/TLS encryption
10- - Configuration reload on file change
10+ - SSL/TLS encryption (HTTPS)
11+ - HTTP/2 support
12+ - Auto-reload config on file change
1113- Multiple virtual hosts
14+ - Single binary deployment
15+
16+ ## Project Structure
17+
18+ ```
19+ /home/xfy/Developer/candy/
20+ ├── src/
21+ │ ├── main.rs # Entry point with server initialization
22+ │ ├── config.rs # Configuration loading and validation
23+ │ ├── cli.rs # Command-line interface parsing
24+ │ ├── consts.rs # Constant definitions (version, arch, commit info)
25+ │ ├── error.rs # Custom error types and error handling
26+ │ ├── http/
27+ │ │ ├── mod.rs # HTTP server creation and shutdown
28+ │ │ ├── serve.rs # Static file serving handler
29+ │ │ ├── reverse_proxy.rs # Reverse proxy handler
30+ │ │ ├── lua/ # Lua scripting handler (optional)
31+ │ │ ├── redirect.rs # HTTP redirect handler
32+ │ │ └── error.rs # HTTP error handling
33+ │ ├── middlewares/ # HTTP middleware (version, headers, logging)
34+ │ ├── utils/
35+ │ │ ├── mod.rs # Utility functions
36+ │ │ ├── config_watcher.rs # Configuration file watcher with auto-reload
37+ │ │ └── logger.rs # Logging initialization
38+ │ └── lua_engine.rs # Lua engine integration (optional)
39+ ├── examples/
40+ │ ├── config.example.toml # Simple configuration example
41+ │ └── config.example_full.toml # Complete configuration example
42+ ├── docs/ # Documentation (Docusaurus site)
43+ ├── assets/ # Static assets (logo, etc.)
44+ ├── Cargo.toml # Cargo manifest with dependencies
45+ ├── Cargo.lock # Cargo lock file
46+ ├── Makefile # Build and development commands
47+ ├── Dockerfile # Docker container configuration
48+ ├── README.md # Chinese documentation
49+ ├── README_en.md # English documentation
50+ └── AGENTS.md # This handover document
51+ ```
52+
53+ ## Core Architecture
54+
55+ ### Main Entry Point (` src/main.rs ` )
56+
57+ The server starts by:
58+
59+ 1 . Parsing command-line arguments
60+ 2 . Loading and validating configuration
61+ 3 . Initializing logging
62+ 4 . Starting initial servers based on config
63+ 5 . Starting config file watcher for auto-reload
64+ 6 . Handling shutdown signals
65+
66+ Key features:
67+
68+ - Uses Tokio async runtime
69+ - Uses mimalloc as global allocator for better performance
70+ - Configuration watcher with auto-reload on file change
71+ - Graceful shutdown handling
72+
73+ ### Configuration System (` src/config.rs ` )
74+
75+ The configuration system uses TOML format and supports:
76+
77+ - Global settings: log level, log folder
78+ - Multiple virtual hosts with separate configurations
79+ - Per-host routes with:
80+ - Static file serving
81+ - Reverse proxying
82+ - Lua scripting
83+ - HTTP redirects
84+ - SSL/TLS configuration
85+ - Timeout settings
86+
87+ Key types:
88+
89+ - ` Settings ` : Root configuration struct
90+ - ` SettingHost ` : Virtual host configuration
91+ - ` SettingRoute ` : Individual route configuration (static/proxy/lua/redirect)
92+
93+ Validation:
94+
95+ - SSL certificate/key existence check
96+ - Route location format validation
97+ - Required fields validation
98+ - File path validation
99+
100+ ### HTTP Server (` src/http/mod.rs ` )
101+
102+ The HTTP server uses Axum framework and axum-server for:
103+
104+ - Route registration and matching
105+ - Virtual host support
106+ - HTTPS with Rustls
107+ - HTTP/2 support
108+ - Timeout handling
109+ - Compression
110+ - Middleware chain (version header, custom headers, logging)
111+
112+ Key features:
113+
114+ - Route matching with optional trailing slash support
115+ - Wildcard path handling for static files
116+ - Per-route body size limits
117+ - Host configuration stored in global ` HOSTS ` map (DashMap for concurrency)
118+
119+ ### Configuration Watcher (` src/utils/config_watcher.rs ` )
120+
121+ The config watcher uses the ` notify ` crate to monitor file changes with:
122+
123+ - Debounce mechanism to avoid frequent reloads
124+ - Retry logic for failed config reads
125+ - Re-watch logic for renamed/deleted files
126+ - Async channel communication
127+ - Graceful shutdown handling
128+
129+ Configuration options:
130+
131+ - ` debounce_ms ` : Debounce time for events (default: 500ms)
132+ - ` rewatch_delay_ms ` : Delay after rename/delete events (default: 800ms)
133+ - ` max_retries ` : Max retries for config read (default: 5)
134+ - ` retry_delay_ms ` : Delay between retries (default: 100ms)
12135
13136## Build and Test Commands
14137
@@ -78,6 +201,7 @@ make loongarch # LoongArch Linux
78201## Code Style Guidelines
79202
80203### General
204+
81205- ** File encoding** : UTF-8
82206- ** Line endings** : LF (Unix-style)
83207- ** Trailing whitespace** : Must be trimmed
@@ -87,9 +211,11 @@ make loongarch # LoongArch Linux
87211### Rust-specific
88212
89213#### Import Order
90- 1 . Standard library (std::* )
214+
215+ 1 . Standard library (std::\* )
912162 . External dependencies (alphabetical)
92- 3 . Internal modules (crate::* , super::* , self::* )
217+ 3 . Internal modules (crate::_ , super::_ , self::\* )
218+
93219``` rust
94220// Good import example
95221use std :: path :: Path ;
@@ -99,18 +225,21 @@ use crate::config::Settings;
99225```
100226
101227#### Naming Conventions
228+
102229- Variables/functions: ` snake_case `
103230- Types/traits/enums: ` PascalCase `
104231- Constants: ` SCREAMING_SNAKE_CASE `
105232- Modules: ` snake_case `
106233- Lifetimes: ` 'a ` , ` 'b ` (single lowercase)
107234
108235#### Type Annotations
236+
109237- Use inference for local variables
110238- Explicit types for:
111239 - Public API signatures
112240 - Complex type contexts
113241 - Where inference is ambiguous
242+
114243``` rust
115244// Good type annotation
116245pub fn load_config (path : & Path ) -> anyhow :: Result <Settings > {
@@ -120,17 +249,21 @@ pub fn load_config(path: &Path) -> anyhow::Result<Settings> {
120249```
121250
122251#### Error Handling
252+
123253- Use ` anyhow::Result ` for app errors
124254- Use ` thiserror::Error ` for structured errors
125255- Always use ` ? ` operator instead of ` unwrap() ` /` expect() `
126256- Add context with ` with_context() ` :
257+
127258``` rust
128259std :: fs :: read (path ). with_context (|| format! (" Failed to read {path:?}" ))? ;
129260```
130261
131262### Memory Safety
263+
132264- Prefer safe Rust constructs
133265- Document unsafe blocks:
266+
134267``` rust
135268// SAFETY: Buffer size verified before access
136269unsafe { * ptr = value ; }
@@ -139,12 +272,14 @@ unsafe { *ptr = value; }
139272## Documentation Guidelines
140273
141274### Code Comments
275+
142276- ` /// ` for public API documentation
143277- ` //! ` for module-level documentation
144278- ` // ` for implementation comments
145279
146280### Examples
147- ``` rust
281+
282+ ```` rust
148283/// Validates configuration settings
149284///
150285/// # Examples
@@ -156,13 +291,15 @@ unsafe { *ptr = value; }
156291pub fn validate (& self ) -> anyhow :: Result <()> {
157292 // ...
158293}
159- ```
294+ ````
160295
161296### Error Messages
297+
162298- Include actionable information
163299- Suggest solutions when possible
164300
165301## Security Best Practices
302+
166303- Never log secrets or credentials
167304- Validate all external inputs
168305- Use constant-time comparisons for sensitive data
@@ -188,15 +325,16 @@ cargo run -- --config path/to/config.toml
188325
189326## Key Modules
190327
191- - ` src/main.rs ` : Entry point
192- - ` src/config.rs ` : Configuration loading
193- - ` src/http/mod.rs ` : Axum server
194- - ` src/utils/config_watcher.rs ` : Config reloading
195- - ` src/lua_engine.rs ` : Lua integration
328+ - ` src/main.rs ` : Entry point and server lifecycle management
329+ - ` src/config.rs ` : Configuration loading, validation, and struct definitions
330+ - ` src/http/mod.rs ` : Axum server creation and route registration
331+ - ` src/utils/config_watcher.rs ` : Config reloading on file change
332+ - ` src/lua_engine.rs ` : Lua integration (optional feature)
196333
197334## Performance Optimization
198335
199336Release profile:
337+
200338``` toml
201339[profile .release ]
202340opt-level = 3
@@ -209,8 +347,121 @@ codegen-units = 1
209347## Git Integration
210348
211349- Branch: ` <type>/<short-description> ` (feat|fix|docs|refactor|test|chore)
212- - Commits:
350+ - Commits:
213351 - Imperative mood ("Add", "Fix", "Update")
214352 - First line ≤ 50 chars
215353 - Explain "why" in body
216- - Never commit: Secrets, credentials, ` .env ` files
354+ - Never commit: Secrets, credentials, ` .env ` files
355+
356+ ## Dependencies Overview
357+
358+ | Dependency | Version | Purpose |
359+ | ----------- | ------- | ----------------------------------- |
360+ | axum | 0.8.8 | Web framework |
361+ | axum-server | 0.8.0 | HTTP server implementation with TLS |
362+ | hyper | 1.8.1 | HTTP client/server core |
363+ | dashmap | 6.1.0 | Concurrent hash map |
364+ | notify | 8.2.0 | File system watching |
365+ | mlua | 0.11.5 | Lua integration (optional) |
366+ | mimalloc | 0.1.48 | Memory allocator |
367+ | tracing | 0.1.44 | Logging system |
368+ | toml | 0.9.11 | TOML parsing |
369+
370+ ## Configuration Example
371+
372+ ``` toml
373+ log_level = " debug"
374+ log_folder = " ./logs"
375+
376+ [[host ]]
377+ ip = " 127.0.0.1"
378+ port = 8080
379+ ssl = false
380+ timeout = 60
381+ server_name = " localhost"
382+
383+ [[host .route ]]
384+ location = " /"
385+ root = " ./public"
386+ index = [" index.html" , " index.htm" ]
387+ auto_index = true
388+
389+ [[host .route ]]
390+ location = " /api"
391+ proxy_pass = " http://localhost:3000"
392+ proxy_timeout = 30
393+ max_body_size = 1048576
394+
395+ [[host ]]
396+ ip = " 0.0.0.0"
397+ port = 443
398+ ssl = true
399+ certificate = " ./cert.pem"
400+ certificate_key = " ./key.pem"
401+ timeout = 30
402+
403+ [[host .route ]]
404+ location = " /"
405+ root = " ./ssl_public"
406+ error_page = { status = 404 , page = " /404.html" }
407+ ```
408+
409+ ## Common Tasks
410+
411+ ### Adding a New Feature
412+
413+ 1 . Create a new branch: ` git checkout -b feat/your-feature `
414+ 2 . Implement the feature
415+ 3 . Add tests in the appropriate module
416+ 4 . Run tests: ` cargo test `
417+ 5 . Run lint: ` cargo clippy `
418+ 6 . Format code: ` cargo fmt `
419+ 7 . Commit changes
420+ 8 . Create PR
421+
422+ ### Debugging
423+
424+ - Run in debug mode with logging: ` cargo run -- --config path/to/config.toml `
425+ - View detailed logs: Set ` log_level = "trace" ` in config
426+ - Use ` cargo test -- --nocapture ` to see stdout in tests
427+
428+ ### Performance Profiling
429+
430+ - Build with profiling: ` cargo build --release --features flame `
431+ - Use flamegraphs: ` cargo flamegraph `
432+ - Check memory usage with Valgrind: ` valgrind --tool=massif target/release/candy `
433+
434+ ## Troubleshooting
435+
436+ ### Common Issues
437+
438+ 1 . ** Configuration errors** : Check that all required fields are present and valid
439+ 2 . ** Port already in use** : Change port in config or kill existing process
440+ 3 . ** SSL certificate errors** : Verify certificate and key paths are correct
441+ 4 . ** Static file not found** : Check root path and file permissions
442+ 5 . ** Config reload not working** : Ensure watcher has read permissions on config file
443+
444+ ## Handover Notes
445+
446+ Key areas to focus on:
447+
448+ - Configuration validation logic in ` src/config.rs `
449+ - Route matching and host selection in ` src/http/mod.rs `
450+ - Config watcher implementation in ` src/utils/config_watcher.rs `
451+ - Lua integration in ` src/lua_engine.rs ` and ` src/http/lua/ `
452+ - Middleware chain in ` src/middlewares/ `
453+
454+ Current known limitations:
455+
456+ - No support for WebSocket proxying (planned)
457+ - Limited Lua API (can be extended)
458+ - No built-in caching mechanism
459+
460+ Future roadmap:
461+
462+ - WebSocket support
463+ - Advanced routing rules
464+ - Caching middleware
465+ - Prometheus metrics
466+ - Health check endpoints
467+
0 commit comments