-
Notifications
You must be signed in to change notification settings - Fork 4
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.
-
Install Rust and Cargo
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Follow the on-screen instructions to complete the installation.
-
Add WebAssembly Target
rustup target add wasm32-unknown-unknown
-
Install Trunk (for Yew)
cargo install trunk
-
Install Tauri CLI
cargo install tauri-cli
-
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
-
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
-
Fork the Repository First, fork the QuietDrop repository on GitHub.
-
Clone Your Fork
git clone https://github.com/YOUR_USERNAME/QuietDrop.git cd QuietDrop
-
Add Upstream Remote
git remote add upstream https://github.com/chizy7/QuietDrop.git
-
Build the Core Library and CLI
cargo build -p quietdrop-core -p quietdrop-cli
-
Build the Tauri Application
cd quietdrop-tauri cargo tauri build
-
Run Tests
cargo test --workspace
-
Sync with upstream
git fetch upstream git checkout master git merge upstream/master
-
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
-
-
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
-
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
- Add tests for new functionality in the same file (unit tests) or in the
-
Documentation
- Add code documentation using Rust doc comments (
///
) - Update relevant documentation files in the
docs/
directory
- Add code documentation using Rust doc comments (
-
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
-
Updating the Yew Frontend
Modify the Yew components in
quietdrop-tauri/src/
directory. When runningcargo tauri dev
, changes will be automatically rebuilt and reflected in the development application. -
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"); }
-
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 } } }); }
-
Building for Different Platforms
# Desktop (current platform) cargo tauri build # Android cargo tauri android build # iOS cargo tauri ios build
-
Make small, focused commits
git add specific_file.rs git commit -m "feat: add feature X to component Y"
-
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.
-
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
-
- Use a prefix to indicate the type of change:
-
Push your branch
git push origin feature/your-feature-name
- Go to GitHub and create a new pull request from your feature branch
- Fill out the PR template with details about your changes
- Link any related issues with "Fixes #123" or "Relates to #456"
- Request reviews from maintainers
- Ensure CI workflows pass successfully
- 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.
- Make requested changes in your feature branch
- Push additional commits to address feedback
- Engage in discussion on the PR if needed
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
# 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
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
}
}
-
Print debugging
println!("Debug value: {:?}", some_variable);
-
Tauri Console Logging
// In Yew component web_sys::console::log_1(&format!("Debug: {:?}", value).into()); // In Tauri backend println!("Tauri backend: {:?}", value);
-
Using a debugger
- VS Code with the Rust extension provides debugging support
- Use
rust-lldb
orrust-gdb
from the command line
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);
}
# 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
cargo update -p crate_name
# CLI
RUST_LOG=debug cargo run -p quietdrop-cli -- server
# Tauri
cd quietdrop-tauri
RUST_LOG=debug cargo tauri dev
# 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
-
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(()) }
-
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) // ... }
-
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> }
-
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 }
-
Mobile Permissions
Configure in Tauri:
{ "permissions": [ "camera", "microphone", "photos" ] }
- 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
- 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)
- 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
If you need assistance:
- Check existing issues
- Ask questions in Discussions
- Consult the Architecture documentation
- Review the API documentation
- Read the Tauri documentation
- Check the Yew documentation
Ready to contribute? Check out the open issues labeled with good first issue
to find a good starting point!
QuietDrop Wiki | Home | Getting Started | FAQ | Security Model | Architecture | Development Guide
Main Repository | Report Issues | Contributing
© 2023-2025 QuietDrop Contributors | MIT License
Last updated: April 2025