Get updates for everywhere with a modular, scalable architecture.
Getter has been refactored into a multi-package workspace structure for better modularity, testing, and multi-person collaboration:
packages/
βββ getter-utils/ # Core utilities (HTTP, versioning, time)
βββ getter-cache/ # Caching system with pluggable backends
βββ getter-provider/ # Update providers (GitHub, GitLab, F-Droid)
βββ getter-config/ # Configuration and app tracking
βββ getter-appmanager/ # Application management logic
βββ getter-rpc/ # RPC server and client
βββ getter-core/ # Core integration module
βββ getter-cli/ # Command-line interface (RPC-based)
- Modular Design: Each package has a single responsibility
- RPC Architecture: CLI communicates purely via RPC (ready for GUI)
- Concurrent/Single-threaded: Configurable via feature flags
- Provider System: Extensible support for multiple update sources
- Caching: Pluggable cache backends for performance
- Backward Compatible: Legacy APIs preserved during transition
- Rust 1.70+ with Cargo
- Tokio async runtime
Build the entire workspace:
cargo build --workspace
Build individual packages:
cargo build --package getter-core
cargo build --package getter-cli
Build with specific features:
# Build with concurrent cache backend
cargo build --package getter-cache --features concurrent
# Build with single-threaded backend
cargo build --package getter-cache --features single-threaded
Run all tests:
cargo test --workspace
Run comprehensive test script:
./tests/script/cargo_test.sh
Run integration tests only:
cargo test --test integration_tests
use getter_core::Core;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let core = Core::new();
// Add an app to track
let app_data = std::collections::HashMap::from([
("owner".to_string(), "rust-lang".to_string()),
("repo".to_string(), "rust".to_string()),
]);
core.add_app(
"rust".to_string(),
"github".to_string(),
app_data,
std::collections::HashMap::new()
).await?;
// List all tracked apps
let apps = core.list_apps().await?;
println!("Tracked apps: {:?}", apps);
// Get outdated apps
let outdated = core.get_outdated_apps().await?;
println!("Apps with updates: {:?}", outdated);
Ok(())
}
use getter_rpc::GetterRpcServer;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = GetterRpcServer::new("127.0.0.1:8080").await?;
server.serve().await?;
Ok(())
}
use getter_rpc::GetterRpcClient;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = GetterRpcClient::new("http://localhost:8080")?;
let app_data = json!({
"app_id": "rust",
"hub_uuid": "github",
"app_data": {"owner": "rust-lang", "repo": "rust"},
"hub_data": {}
});
let result = client.add_app(app_data).await?;
println!("Added app: {:?}", result);
Ok(())
}
The packages have the following dependency relationships:
getter-cli -> getter-rpc -> getter-core -> {getter-appmanager, getter-config}
getter-appmanager -> {getter-provider, getter-config, getter-cache}
getter-provider -> getter-utils
getter-config -> getter-utils
- Implement the
BaseProvider
trait ingetter-provider
- Register the provider in the
ProviderManager
- Add provider-specific configuration to
getter-config
concurrent
: Enable concurrent cache backend (default)single-threaded
: Enable single-threaded cache backendrustls-platform-verifier-android
: Android-specific TLS verifier
The new architecture provides:
- Request Deduplication: Multiple identical requests are automatically deduplicated
- Memory Efficiency: Background processing with automatic cleanup
- Async Processing: Non-blocking operations throughout
- Caching: Configurable caching strategies for API responses
- Each package has its own tests - run them individually during development
- Integration tests ensure packages work together correctly
- Use the provided test script for comprehensive validation
- Follow the existing error handling patterns (Result types)
MIT License - see LICENSE file for details.