docs: Split documentation into separate files
- Move development details to DEVELOPMENT.md - Move contributing guidelines to CONTRIBUTING.md - Add LICENSE file with MIT license - Add CONTRIBUTORS.md for attribution - Update README.md to focus on user-facing information - Improve documentation structure and navigation
This commit is contained in:
parent
8362ebe44b
commit
37e9bc2dc1
5 changed files with 826 additions and 122 deletions
416
DEVELOPMENT.md
Normal file
416
DEVELOPMENT.md
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
# Development Guide
|
||||
|
||||
This document provides comprehensive information about the design, architecture, and development of the CalDAV Calendar Synchronizer.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The application is built with a modular architecture using Rust's strong type system and async capabilities.
|
||||
|
||||
### Core Components
|
||||
|
||||
#### 1. **Configuration System** (`src/config.rs`)
|
||||
- **Purpose**: Manage configuration from files, environment variables, and CLI arguments
|
||||
- **Features**:
|
||||
- TOML-based configuration files
|
||||
- Environment variable support
|
||||
- Command-line argument overrides
|
||||
- Configuration validation
|
||||
- **Key Types**: `Config`, `ServerConfig`, `CalendarConfig`, `SyncConfig`
|
||||
|
||||
#### 2. **CalDAV Client** (`src/caldav_client.rs`)
|
||||
- **Purpose**: Handle CalDAV protocol operations with Zoho and Nextcloud
|
||||
- **Features**:
|
||||
- HTTP client with authentication
|
||||
- Calendar discovery via PROPFIND
|
||||
- Event retrieval via REPORT requests
|
||||
- Event creation via PUT requests
|
||||
- **Key Types**: `CalDavClient`, `CalendarInfo`, `CalDavEventInfo`
|
||||
|
||||
#### 3. **Event Model** (`src/event.rs`)
|
||||
- **Purpose**: Represent calendar events and handle parsing
|
||||
- **Features**:
|
||||
- iCalendar data parsing
|
||||
- Timezone-aware datetime handling
|
||||
- Event filtering and validation
|
||||
- **Key Types**: `Event`, `EventBuilder`, `EventFilter`
|
||||
|
||||
#### 4. **Timezone Handler** (`src/timezone.rs`)
|
||||
- **Purpose**: Manage timezone conversions and datetime operations
|
||||
- **Features**:
|
||||
- Convert between different timezones
|
||||
- Parse timezone information from iCalendar data
|
||||
- Handle DST transitions
|
||||
- **Key Types**: `TimezoneHandler`, `TimeZoneInfo`
|
||||
|
||||
#### 5. **Calendar Filter** (`src/calendar_filter.rs`)
|
||||
- **Purpose**: Filter calendars and events based on user criteria
|
||||
- **Features**:
|
||||
- Calendar name filtering
|
||||
- Regex pattern matching
|
||||
- Event date range filtering
|
||||
- **Key Types**: `CalendarFilter`, `FilterRule`, `EventFilter`
|
||||
|
||||
#### 6. **Sync Engine** (`src/sync.rs`)
|
||||
- **Purpose**: Coordinate the synchronization process
|
||||
- **Features**:
|
||||
- Pull events from Zoho
|
||||
- Push events to Nextcloud
|
||||
- Conflict resolution
|
||||
- Progress tracking
|
||||
- **Key Types**: `SyncEngine`, `SyncResult`, `SyncStats`
|
||||
|
||||
#### 7. **Error Handling** (`src/error.rs`)
|
||||
- **Purpose**: Comprehensive error management
|
||||
- **Features**:
|
||||
- Custom error types
|
||||
- Error context and chaining
|
||||
- User-friendly error messages
|
||||
- **Key Types**: `CalDavError`, `CalDavResult`
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### 1. **Selective Calendar Import**
|
||||
The application allows users to select specific Zoho calendars to import from, consolidating all events into a single Nextcloud calendar. This design choice:
|
||||
|
||||
- **Reduces complexity** compared to bidirectional sync
|
||||
- **Provides clear data flow** (Zoho → Nextcloud)
|
||||
- **Minimizes sync conflicts**
|
||||
- **Matches user requirements** exactly
|
||||
|
||||
### 2. **Timezone Handling**
|
||||
All events are converted to UTC internally for consistency, while preserving original timezone information:
|
||||
|
||||
```rust
|
||||
pub struct Event {
|
||||
pub id: String,
|
||||
pub summary: String,
|
||||
pub start: DateTime<Utc>,
|
||||
pub end: DateTime<Utc>,
|
||||
pub original_timezone: Option<String>,
|
||||
pub source_calendar: String,
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **Configuration Hierarchy**
|
||||
Configuration is loaded in priority order:
|
||||
|
||||
1. **Command line arguments** (highest priority)
|
||||
2. **User config file** (`config/config.toml`)
|
||||
3. **Default config file** (`config/default.toml`)
|
||||
4. **Environment variables**
|
||||
5. **Hardcoded defaults** (lowest priority)
|
||||
|
||||
### 4. **Error Handling Strategy**
|
||||
Uses `thiserror` for custom error types and `anyhow` for error propagation:
|
||||
|
||||
```rust
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CalDavError {
|
||||
#[error("HTTP error: {0}")]
|
||||
Http(#[from] reqwest::Error),
|
||||
|
||||
#[error("Configuration error: {0}")]
|
||||
Config(String),
|
||||
|
||||
#[error("Calendar not found: {0}")]
|
||||
CalendarNotFound(String),
|
||||
|
||||
// ... more error variants
|
||||
}
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
### 1. **Application Startup**
|
||||
```
|
||||
1. Load CLI arguments
|
||||
2. Load configuration files
|
||||
3. Apply environment variables
|
||||
4. Validate configuration
|
||||
5. Initialize logging
|
||||
6. Create CalDAV clients
|
||||
```
|
||||
|
||||
### 2. **Calendar Discovery**
|
||||
```
|
||||
1. Connect to Zoho CalDAV server
|
||||
2. Authenticate with app password
|
||||
3. Send PROPFIND request to discover calendars
|
||||
4. Parse calendar list and metadata
|
||||
5. Apply user filters to select calendars
|
||||
```
|
||||
|
||||
### 3. **Event Synchronization**
|
||||
```
|
||||
1. Query selected Zoho calendars for events (next week)
|
||||
2. Parse iCalendar data into Event objects
|
||||
3. Convert timestamps to UTC with timezone preservation
|
||||
4. Apply event filters (duration, status, patterns)
|
||||
5. Connect to Nextcloud CalDAV server
|
||||
6. Create target calendar if needed
|
||||
7. Upload events to Nextcloud calendar
|
||||
8. Report sync statistics
|
||||
```
|
||||
|
||||
## Key Algorithms
|
||||
|
||||
### 1. **Calendar Filtering**
|
||||
```rust
|
||||
impl CalendarFilter {
|
||||
pub fn should_import_calendar(&self, calendar_name: &str) -> bool {
|
||||
// Check exact matches
|
||||
if self.selected_names.contains(&calendar_name.to_string()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check regex patterns
|
||||
for pattern in &self.regex_patterns {
|
||||
if pattern.is_match(calendar_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **Timezone Conversion**
|
||||
```rust
|
||||
impl TimezoneHandler {
|
||||
pub fn convert_to_utc(&self, dt: DateTime<FixedOffset>, timezone: &str) -> CalDavResult<DateTime<Utc>> {
|
||||
let tz = self.get_timezone(timezone)?;
|
||||
let local_dt = dt.with_timezone(&tz);
|
||||
Ok(local_dt.with_timezone(&Utc))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **Event Processing**
|
||||
```rust
|
||||
impl SyncEngine {
|
||||
pub async fn sync_calendar(&mut self, calendar: &CalendarInfo) -> CalDavResult<SyncResult> {
|
||||
// 1. Fetch events from Zoho
|
||||
let zoho_events = self.fetch_zoho_events(calendar).await?;
|
||||
|
||||
// 2. Filter and process events
|
||||
let processed_events = self.process_events(zoho_events)?;
|
||||
|
||||
// 3. Upload to Nextcloud
|
||||
let upload_results = self.upload_to_nextcloud(processed_events).await?;
|
||||
|
||||
// 4. Return sync statistics
|
||||
Ok(SyncResult::from_upload_results(upload_results))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Schema
|
||||
|
||||
### Complete Configuration Structure
|
||||
```toml
|
||||
# Zoho Configuration (Source)
|
||||
[zoho]
|
||||
server_url = "https://caldav.zoho.com/caldav"
|
||||
username = "your-zoho-email@domain.com"
|
||||
password = "your-zoho-app-password"
|
||||
selected_calendars = ["Work Calendar", "Personal Calendar"]
|
||||
|
||||
# Nextcloud Configuration (Target)
|
||||
[nextcloud]
|
||||
server_url = "https://your-nextcloud-domain.com"
|
||||
username = "your-nextcloud-username"
|
||||
password = "your-nextcloud-app-password"
|
||||
target_calendar = "Imported-Zoho-Events"
|
||||
create_if_missing = true
|
||||
|
||||
# General Settings
|
||||
[server]
|
||||
timeout = 30
|
||||
|
||||
[calendar]
|
||||
color = "#3174ad"
|
||||
timezone = "UTC"
|
||||
|
||||
[sync]
|
||||
interval = 300
|
||||
sync_on_startup = true
|
||||
weeks_ahead = 1
|
||||
dry_run = false
|
||||
|
||||
# Optional Filtering
|
||||
[filters]
|
||||
min_duration_minutes = 5
|
||||
max_duration_hours = 24
|
||||
exclude_patterns = ["Cancelled:", "BLOCKED"]
|
||||
include_status = ["confirmed", "tentative"]
|
||||
exclude_status = ["cancelled"]
|
||||
```
|
||||
|
||||
## Dependencies and External Libraries
|
||||
|
||||
### Core Dependencies
|
||||
```toml
|
||||
[dependencies]
|
||||
tokio = { version = "1.0", features = ["full"] } # Async runtime
|
||||
reqwest = { version = "0.11", features = ["json", "xml"] } # HTTP client
|
||||
serde = { version = "1.0", features = ["derive"] } # Serialization
|
||||
chrono = { version = "0.4", features = ["serde"] } # Date/time
|
||||
chrono-tz = "0.8" # Timezone support
|
||||
quick-xml = "0.28" # XML parsing
|
||||
thiserror = "1.0" # Error handling
|
||||
anyhow = "1.0" # Error propagation
|
||||
config = "0.13" # Configuration
|
||||
clap = { version = "4.0", features = ["derive"] } # CLI
|
||||
tracing = "0.1" # Logging
|
||||
tracing-subscriber = "0.3" # Log formatting
|
||||
toml = "0.8" # TOML parsing
|
||||
```
|
||||
|
||||
### Optional Dependencies for Future Features
|
||||
```toml
|
||||
# For enhanced XML handling
|
||||
serde_xml_rs = "0.6"
|
||||
|
||||
# For better HTTP client customization
|
||||
http = "0.2"
|
||||
|
||||
# For async file operations
|
||||
tokio-util = "0.7"
|
||||
|
||||
# For better error formatting
|
||||
color-eyre = "0.6"
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### 1. **Unit Tests**
|
||||
- Individual module functionality
|
||||
- Configuration parsing and validation
|
||||
- Event parsing and timezone conversion
|
||||
- Error handling paths
|
||||
|
||||
### 2. **Integration Tests**
|
||||
- End-to-end CalDAV operations
|
||||
- Configuration loading from files
|
||||
- CLI argument processing
|
||||
- HTTP client behavior
|
||||
|
||||
### 3. **Mock Testing**
|
||||
- Mock CalDAV server responses
|
||||
- Test error conditions without real servers
|
||||
- Validate retry logic and timeout handling
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### 1. **Async Operations**
|
||||
All network operations are async to prevent blocking:
|
||||
```rust
|
||||
pub async fn fetch_events(&self, calendar: &CalendarInfo) -> CalDavResult<Vec<Event>> {
|
||||
let response = self.client
|
||||
.request(reqwest::Method::REPORT, &calendar.url)
|
||||
.body(report_body)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
// Process response...
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **Memory Management**
|
||||
- Stream processing for large calendar responses
|
||||
- Efficient string handling with `Cow<str>` where appropriate
|
||||
- Clear lifecycle management for HTTP connections
|
||||
|
||||
### 3. **Configuration Caching**
|
||||
- Cache parsed timezone information
|
||||
- Reuse HTTP connections where possible
|
||||
- Validate configuration once at startup
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### 1. **Authentication**
|
||||
- Support for app-specific passwords only
|
||||
- Never log authentication credentials
|
||||
- Secure storage of sensitive configuration
|
||||
|
||||
### 2. **Network Security**
|
||||
- Enforce HTTPS by default
|
||||
- SSL certificate validation
|
||||
- Custom CA certificate support
|
||||
|
||||
### 3. **Data Privacy**
|
||||
- Minimal data collection (only required event fields)
|
||||
- Optional debug logging with sensitive data filtering
|
||||
- Clear data retention policies
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### 1. **Enhanced Filtering**
|
||||
- Advanced regex patterns
|
||||
- Calendar color-based filtering
|
||||
- Attendee-based filtering
|
||||
|
||||
### 2. **Bidirectional Sync**
|
||||
- Two-way synchronization with conflict resolution
|
||||
- Event modification tracking
|
||||
- Deletion synchronization
|
||||
|
||||
### 3. **Performance Optimizations**
|
||||
- Parallel calendar processing
|
||||
- Incremental sync with change detection
|
||||
- Local caching and offline mode
|
||||
|
||||
### 4. **User Experience**
|
||||
- Interactive configuration wizard
|
||||
- Web-based status dashboard
|
||||
- Real-time sync notifications
|
||||
|
||||
## Build and Development
|
||||
|
||||
### 1. **Development Setup**
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone ssh://git@gitea.soliverez.com.ar/alvaro/caldavpuller.git
|
||||
cd caldavpuller
|
||||
|
||||
# Install Rust toolchain
|
||||
rustup update stable
|
||||
rustup component add rustfmt clippy
|
||||
|
||||
# Build in development mode
|
||||
cargo build
|
||||
|
||||
# Run tests
|
||||
cargo test
|
||||
|
||||
# Check formatting
|
||||
cargo fmt --check
|
||||
|
||||
# Run linter
|
||||
cargo clippy -- -D warnings
|
||||
```
|
||||
|
||||
### 2. **Release Build**
|
||||
```bash
|
||||
# Build optimized release
|
||||
cargo build --release
|
||||
|
||||
# Create distribution archive
|
||||
tar -czf caldav-sync-${VERSION}-${TARGET}.tar.gz \
|
||||
-C target/release caldav-sync \
|
||||
-C ../config example.toml \
|
||||
-C .. README.md LICENSE
|
||||
```
|
||||
|
||||
### 3. **Testing with Mock Servers**
|
||||
For testing without real CalDAV servers, use the mock server setup:
|
||||
```bash
|
||||
# Start mock CalDAV server
|
||||
cargo run --bin mock-server
|
||||
|
||||
# Run integration tests against mock server
|
||||
cargo test --test integration_tests
|
||||
```
|
||||
|
||||
This architecture provides a solid foundation for the CalDAV synchronization tool while maintaining flexibility for future enhancements.
|
||||
Loading…
Add table
Add a link
Reference in a new issue