- 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
11 KiB
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:
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:
- Command line arguments (highest priority)
- User config file (
config/config.toml) - Default config file (
config/default.toml) - Environment variables
- Hardcoded defaults (lowest priority)
4. Error Handling Strategy
Uses thiserror for custom error types and anyhow for error propagation:
#[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
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
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
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
# 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
[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
# 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:
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
# 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
# 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:
# 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.