96 lines
3.6 KiB
Markdown
96 lines
3.6 KiB
Markdown
# Overview
|
|
This project is a very simple gemini server which only serves static files,
|
|
nothing else. It is meant to be generic so other people can use it.
|
|
|
|
# Build/Test/Lint Commands
|
|
|
|
## Core Commands
|
|
- `cargo build` - Build the project
|
|
- `cargo build --release` - Build optimized release version
|
|
- `cargo run` - Run the server with default config
|
|
- `cargo test` - Run all unit tests
|
|
- `cargo test <test_name>` - Run a specific test
|
|
- `cargo test <module>::tests` - Run tests in a specific module
|
|
- `cargo clippy` - Run linter checks
|
|
- `cargo fmt` - Format code according to Rust standards
|
|
- `cargo check` - Quick compile check without building
|
|
|
|
## Common Test Patterns
|
|
- `cargo test config::tests` - Run config module tests
|
|
- `cargo test request::tests` - Run request handling tests
|
|
- `cargo test -- --nocapture` - Show println output in tests
|
|
|
|
# Code Style Guidelines
|
|
|
|
## Imports
|
|
- Group imports: std libs first, then external crates, then local modules
|
|
- Use `use crate::module::function` for internal imports
|
|
- Prefer specific imports over `use std::prelude::*`
|
|
- Keep imports at module level, not inside functions
|
|
|
|
## Code Structure
|
|
- Use `#[tokio::main]` for async main function
|
|
- Keep functions small and focused (single responsibility)
|
|
- Use `const` for configuration values that don't change
|
|
- Error handling with `Result<T, E>` and `?` operator
|
|
- Use `tracing` for logging, not `println!` in production code
|
|
|
|
## Naming Conventions
|
|
- `PascalCase` for types, structs, enums
|
|
- `snake_case` for functions, variables, modules
|
|
- `SCREAMING_SNAKE_CASE` for constants
|
|
- Use descriptive names that indicate purpose
|
|
|
|
## Error Handling
|
|
- Use `io::Result<()>` for I/O operations
|
|
- Convert errors to appropriate types with `map_err` when needed
|
|
- Use `unwrap()` only in tests and main() for unrecoverable errors
|
|
- Use `expect()` with meaningful messages for debugging
|
|
- Return early with `Err()` for validation failures
|
|
|
|
## Security Requirements
|
|
- **Critical**: Always validate file paths with `path_security::validate_path`
|
|
- Never construct paths from user input without validation
|
|
- Use timeouts for network operations (`tokio::time::timeout`)
|
|
- Limit request sizes (see `MAX_REQUEST_SIZE` constant)
|
|
- Validate TLS certificates properly
|
|
- Never expose directory listings
|
|
|
|
## Testing Guidelines
|
|
- Use `tempfile::TempDir` for temporary directories in tests
|
|
- Test both success and error paths
|
|
- Use `#[cfg(test)]` for test modules
|
|
- Create temporary test files in `tmp/` directory
|
|
- Test security boundaries (path traversal, invalid inputs)
|
|
- Use `assert_eq!` and `assert!` for validations
|
|
|
|
## Async Patterns
|
|
- Use `.await` on async calls
|
|
- Prefer `tokio::fs` over `std::fs` in async contexts
|
|
- Handle timeouts for network operations
|
|
- Use `Arc<Clone>` for shared data across tasks
|
|
|
|
## Gemini Protocol Specific
|
|
- Response format: "STATUS META\r\n"
|
|
- Status 20: Success (follow with MIME type)
|
|
- Status 51: Not found
|
|
- Status 59: Bad request
|
|
- Default MIME: "text/gemini" for .gmi files
|
|
- Default file: "index.gmi" for directory requests
|
|
|
|
## Configuration
|
|
- TOML config files with `serde::Deserialize`
|
|
- CLI args override config file values
|
|
- Required fields: root, cert, key, host
|
|
- Optional: port, log_level
|
|
|
|
# Development Notes
|
|
- Generate self-signed certificates for local testing in `tmp/` directory
|
|
- Use CN=localhost for development
|
|
- Fix every compiler warning before committing any code
|
|
- Create temporary files in the tmp/ directory for your tests like .gem files
|
|
or images, etc., so they are gitignored
|
|
- Use `path-security` crate for path validation
|
|
- Default port: 1965 (standard Gemini port)
|
|
- Default host: 0.0.0.0 for listening
|
|
- Log level defaults to "info"
|