Skip to content

Development Guide

Chizy edited this page May 9, 2025 · 2 revisions

Development Guide

This guide provides instructions for setting up a development environment for QuietDrop and explains the development workflow for both the core library and the cross-platform Tauri application.

Setting Up Your Development Environment

Prerequisites

  1. Install Rust and Cargo

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

    Follow the on-screen instructions to complete the installation.

  2. Add WebAssembly Target

    rustup target add wasm32-unknown-unknown
  3. Install Trunk (for Yew)

    cargo install trunk
  4. Install Tauri CLI

    cargo install tauri-cli
  5. Install Development Tools

    # Add rustfmt and clippy components
    rustup component add rustfmt clippy
    
    # (Optional) Install cargo-edit for easier dependency management
    cargo install cargo-edit
  6. Platform-Specific Dependencies

    Core Dependencies (all platforms)

    • Make sure you have the necessary system libraries for cryptography:

    Ubuntu/Debian:

    sudo apt-get install libsodium-dev

    macOS:

    brew install libsodium

    Windows: Use the pre-compiled binaries or build using MSVC.

    Tauri Desktop Dependencies

    Ubuntu/Debian:

    sudo apt update
    sudo apt install libwebkit2gtk-4.0-dev \
      build-essential \
      curl \
      wget \
      file \
      libssl-dev \
      libgtk-3-dev \
      libayatana-appindicator3-dev \
      librsvg2-dev

    macOS:

    xcode-select --install

    Windows:

    • Visual Studio C++ Build Tools
    • WebView2

    Tauri Android Dependencies

    • Android SDK
    • Android NDK
    • Java Development Kit (JDK 11+)

    Tauri iOS Dependencies

    • Xcode
    • iOS development certificate
    • Cocoapods

Cloning and Building

  1. Fork the Repository First, fork the QuietDrop repository on GitHub.

  2. Clone Your Fork

    git clone https://github.com/YOUR_USERNAME/QuietDrop.git
    cd QuietDrop
  3. Add Upstream Remote

    git remote add upstream https://github.com/chizy7/QuietDrop.git
  4. Build the Core Library and CLI

    cargo build -p quietdrop-core -p quietdrop-cli
  5. Build the Tauri Application

    cd quietdrop-tauri
    cargo tauri build
  6. Run Tests

    cargo test --workspace

Development Workflow

Creating a Feature Branch

  1. Sync with upstream

    git fetch upstream
    git checkout master
    git merge upstream/master
  2. Create a feature branch

    git checkout -b feature/your-feature-name

    Use prefixes to categorize your branch:

    • feature/ for new features
    • fix/ for bug fixes
    • docs/ for documentation
    • refactor/ for code refactoring
    • tauri/ for Tauri-specific features
    • mobile/ for mobile-specific features

Making Changes

  1. Code Style

    • Follow Rust's coding conventions
    • Run cargo fmt before committing to ensure consistent formatting
    • Use cargo clippy to check for common mistakes and non-idiomatic code
  2. Writing Tests

    • Add tests for new functionality in the same file (unit tests) or in the tests/ directory (integration tests)
    • Ensure all tests pass with cargo test
  3. Documentation

    • Add code documentation using Rust doc comments (///)
    • Update relevant documentation files in the docs/ directory

Working with Tauri and Yew

  1. Running the Tauri Development Server

    # For desktop
    cd quietdrop-tauri
    cargo tauri dev
    
    # For Android
    cd quietdrop-tauri
    cargo tauri android dev
    
    # For iOS
    cd quietdrop-tauri
    cargo tauri ios dev
  2. Updating the Yew Frontend

    Modify the Yew components in quietdrop-tauri/src/ directory. When running cargo tauri dev, changes will be automatically rebuilt and reflected in the development application.

  3. Adding Tauri Commands

    Add new commands in quietdrop-tauri/src-tauri/src/main.rs:

    #[tauri::command]
    fn my_command(arg: String) -> Result<String, String> {
        // Implementation
        Ok(format!("Processed: {}", arg))
    }
    
    fn main() {
        tauri::Builder::default()
            // Register your command
            .invoke_handler(tauri::generate_handler![my_command])
            .run(tauri::generate_context!())
            .expect("Error while running Tauri application");
    }
  4. Calling Tauri Commands from Frontend

    In Yew components:

    use wasm_bindgen::prelude::*;
    use wasm_bindgen_futures::spawn_local;
    
    fn call_tauri_command() {
        spawn_local(async {
            let result = tauri::invoke::<_, String>("my_command", &JsValue::from_serde(&serde_json::json!({
                "arg": "test input"
            })).unwrap()).await;
            
            match result {
                Ok(response) => {
                    // Handle success
                },
                Err(e) => {
                    // Handle error
                }
            }
        });
    }
  5. Building for Different Platforms

    # Desktop (current platform)
    cargo tauri build
    
    # Android
    cargo tauri android build
    
    # iOS
    cargo tauri ios build

Committing Changes

  1. Make small, focused commits

    git add specific_file.rs
    git commit -m "feat: add feature X to component Y"
  2. Sign your commits All commits to the master branch must be cryptographically signed. Set up signing once:

    # Configure GPG signing
    git config --global user.signingkey YOUR_GPG_KEY_ID
    git config --global commit.gpgsign true
    
    # Or configure SSH signing
    git config --global gpg.format ssh
    git config --global user.signingkey ~/.ssh/id_ed25519.pub
    git config --global commit.gpgsign true

    If needed, manually sign a commit:

    git commit -S -m "feat: add signed feature"

    See our CONTRIBUTING.md for complete setup instructions.

  3. Follow commit message conventions

    • Use a prefix to indicate the type of change:
      • feat: for new features
      • fix: for bug fixes
      • docs: for documentation changes
      • test: for adding or modifying tests
      • refactor: for code refactoring
      • perf: for performance improvements
      • chore: for other changes
      • tauri: for Tauri-specific changes
      • mobile: for mobile-specific changes
  4. Push your branch

    git push origin feature/your-feature-name

Creating a Pull Request

  1. Go to GitHub and create a new pull request from your feature branch
  2. Fill out the PR template with details about your changes
  3. Link any related issues with "Fixes #123" or "Relates to #456"
  4. Request reviews from maintainers
  5. Ensure CI workflows pass successfully
  6. Note: When your PR is merged to master, all commits must be signed. If you haven't set up commit signing, your PR may need to be squashed and signed by a maintainer.

Addressing Review Feedback

  1. Make requested changes in your feature branch
  2. Push additional commits to address feedback
  3. Engage in discussion on the PR if needed

Project Structure

Understanding the project organization:

QuietDrop/
├── Cargo.toml                # Workspace manifest
├── quietdrop-core/           # Core library with shared functionality
│   ├── src/                  # Source files
│   │   ├── authentication.rs # User authentication
│   │   ├── client.rs         # Client implementation
│   │   ├── encryption.rs     # Cryptographic operations
│   │   ├── lib.rs            # Library exports
│   │   ├── message.rs        # Message handling
│   │   └── server.rs         # Server implementation
│   └── Cargo.toml            # Core library manifest
├── quietdrop-cli/            # Command-line interface
│   ├── src/
│   │   └── main.rs           # CLI entry point
│   └── Cargo.toml            # CLI manifest
├── quietdrop-tauri/          # Tauri application
│   ├── index.html            # HTML entry point
│   ├── styles.css            # Global styles
│   ├── src/                  # Yew frontend
│   │   ├── main.rs           # Frontend entry point
│   │   ├── app.rs            # Main application component
│   │   ├── components/       # UI components
│   │   ├── models/           # Data models
│   │   └── services/         # Service interfaces
│   ├── src-tauri/            # Tauri backend
│   │   ├── src/              # Backend source code
│   │   │   └── main.rs       # Tauri command handlers
│   │   ├── Cargo.toml        # Backend manifest
│   │   └── tauri.conf.json   # Tauri configuration
│   └── Cargo.toml            # Frontend manifest
├── tests/                    # Integration tests
├── docs/                     # Documentation
│   ├── API.md                # API documentation
│   ├── ENCRYPTION.md         # Encryption details
│   ├── TAURI_ARCHITECTURE.md # Tauri architecture details
│   └── ...                   # Other documentation
└── .github/                  # GitHub configuration
    ├── ISSUE_TEMPLATE/       # Issue templates
    └── workflows/            # CI/CD workflows

Testing

Running Tests

# Run all tests in the workspace
cargo test --workspace

# Run tests for a specific crate
cargo test -p quietdrop-core

# Run specific tests
cargo test test_name

# Run tests with output
cargo test -- --nocapture

Writing Tests

Example of a unit test for the core library:

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_encryption_decryption() {
        let (alice_pk, alice_sk) = generate_keypair();
        let (bob_pk, bob_sk) = generate_keypair();
        
        let original_msg = "Hello, this is a secret message!";
        let encrypted = encrypt_message(original_msg, &bob_pk, &alice_sk);
        let decrypted = decrypt_message(&encrypted, &alice_pk, &bob_sk).unwrap();
        
        assert_eq!(original_msg, decrypted);
    }
}

Example of a test for Yew components:

#[cfg(test)]
mod tests {
    use super::*;
    use wasm_bindgen_test::*;
    
    wasm_bindgen_test_configure!(run_in_browser);
    
    #[wasm_bindgen_test]
    fn test_component_rendering() {
        // Test component rendering logic
    }
}

Debugging

Local Debugging

  1. Print debugging

    println!("Debug value: {:?}", some_variable);
  2. Tauri Console Logging

    // In Yew component
    web_sys::console::log_1(&format!("Debug: {:?}", value).into());
    
    // In Tauri backend
    println!("Tauri backend: {:?}", value);
  3. Using a debugger

    • VS Code with the Rust extension provides debugging support
    • Use rust-lldb or rust-gdb from the command line

Logging

Consider using the log crate with a logger:

use log::{info, warn, error, debug};

fn some_function() {
    debug!("Debug information");
    info!("Something happened: {}", value);
    warn!("Warning: something might be wrong");
    error!("Error occurred: {}", err);
}

Common Development Tasks

Adding a New Dependency

# For core library
cd quietdrop-core
cargo add dependency_name

# For CLI
cd quietdrop-cli
cargo add dependency_name

# For Tauri backend
cd quietdrop-tauri/src-tauri
cargo add dependency_name

# For Yew frontend
cd quietdrop-tauri
cargo add dependency_name --features web-sys

Updating Dependencies

cargo update -p crate_name

Running with Debug Information

# CLI
RUST_LOG=debug cargo run -p quietdrop-cli -- server

# Tauri
cd quietdrop-tauri
RUST_LOG=debug cargo tauri dev

Building for Release

# Core and CLI
cargo build --release -p quietdrop-core -p quietdrop-cli

# Tauri desktop app
cd quietdrop-tauri
cargo tauri build

# Android app
cd quietdrop-tauri
cargo tauri android build --release

# iOS app
cd quietdrop-tauri
cargo tauri ios build --release

Platform-Specific Development

Desktop Development

  1. Multiple Windows

    #[tauri::command]
    fn open_new_window(window: tauri::Window) -> Result<(), String> {
        tauri::WindowBuilder::new(
            &window.app_handle(),
            "new-window",
            tauri::WindowUrl::App("new.html".into())
        )
        .build()
        .map_err(|e| e.to_string())?;
        
        Ok(())
    }
  2. System Tray

    use tauri::{CustomMenuItem, SystemTray, SystemTrayMenu};
    
    fn main() {
        let quit = CustomMenuItem::new("quit".to_string(), "Quit");
        let tray_menu = SystemTrayMenu::new().add_item(quit);
        let tray = SystemTray::new().with_menu(tray_menu);
        
        tauri::Builder::default()
            .system_tray(tray)
            // ...
    }

Mobile Development

  1. Responsive Design

    In Yew components, use platform detection:

    fn is_mobile() -> bool {
        web_sys::window()
            .and_then(|win| win.navigator().user_agent().ok())
            .map(|ua| ua.contains("Android") || ua.contains("iPhone"))
            .unwrap_or(false)
    }
    
    html! {
        <div class={if is_mobile() { "mobile-container" } else { "desktop-container" }}>
            // Content
        </div>
    }
  2. Platform-Specific APIs

    #[tauri::command]
    fn get_platform_features() -> Vec<String> {
        let mut features = Vec::new();
        
        #[cfg(desktop)]
        features.push("system_tray".into());
        
        #[cfg(target_os = "android")]
        features.push("camera".into());
        
        #[cfg(target_os = "ios")]
        features.push("face_id".into());
        
        features
    }
  3. Mobile Permissions

    Configure in Tauri:

    {
      "permissions": [
        "camera",
        "microphone",
        "photos"
      ]
    }

Advanced Topics

Working with Cryptography

  • Always use the provided cryptographic functions rather than implementing your own
  • Be cautious about side-channel attacks when working with sensitive data
  • Ensure secrets are properly zeroed in memory after use

Cross-Platform Considerations

  • Test on all target platforms regularly
  • Be mindful of platform-specific limitations and permissions
  • Design responsive UIs that work well on both desktop and mobile
  • Handle different input methods (touch vs. mouse/keyboard)

Performance Considerations

  • Use async Rust appropriately for I/O-bound operations
  • Be mindful of WebAssembly performance for frontend code
  • Optimize UI rendering for mobile devices
  • Consider message batching for high-volume scenarios

Getting Help

If you need assistance:

Next Steps

Ready to contribute? Check out the open issues labeled with good first issue to find a good starting point!

Clone this wiki locally