Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,6 @@ pub struct UpdateProjectArgs {
pub struct UpdateTaskArgs {
pub content: Option<String>,
pub description: Option<String>,
pub project_remote_id: Option<String>,
pub section_remote_id: Option<String>,
pub parent_remote_id: Option<String>,
pub priority: Option<i32>,
pub due_date: Option<String>,
pub due_datetime: Option<String>,
Expand All @@ -145,9 +142,6 @@ pub struct UpdateLabelArgs {
/// task management services (Todoist, TickTick, GitHub, etc.).
#[async_trait]
pub trait Backend: Send + Sync {
/// Returns the backend type identifier (e.g., "todoist", "ticktick").
fn backend_type(&self) -> &str;

// Sync operations - fetch all data
async fn fetch_projects(&self) -> Result<Vec<BackendProject>, BackendError>;
async fn fetch_tasks(&self) -> Result<Vec<BackendTask>, BackendError>;
Expand Down
4 changes: 0 additions & 4 deletions src/backend/todoist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ impl TodoistBackend {

#[async_trait]
impl Backend for TodoistBackend {
fn backend_type(&self) -> &str {
"todoist"
}

async fn fetch_projects(&self) -> Result<Vec<BackendProject>, BackendError> {
let mut all_projects = Vec::new();
let mut cursor: Option<String> = None;
Expand Down
145 changes: 6 additions & 139 deletions src/backend_registry.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Backend registry for managing multiple backend instances.
//! Backend registry for managing backend instances.
//!
//! This module provides the `BackendRegistry` which manages the lifecycle of
//! backend instances, including loading from database, creating instances,
//! and coordinating sync operations across multiple backends.
//! This module provides the `BackendRegistry`, which holds the app's configured
//! backends: it persists their configuration in the database and keeps the
//! in-memory backend instance the sync service operates on.

use anyhow::Result;
use log::{error, info};
use log::info;
use sea_orm::{ActiveValue, IntoActiveModel};
use std::collections::HashMap;
use std::sync::Arc;
Expand All @@ -23,10 +23,8 @@ type BackendMap = HashMap<Uuid, Arc<Box<dyn Backend>>>;
/// Registry for managing backend instances and their configurations.
///
/// The `BackendRegistry` is responsible for:
/// - Loading backend configurations from the database
/// - Creating and caching backend instances
/// - Managing backend lifecycle (add/remove/enable/disable)
/// - Coordinating sync operations across multiple backends
/// - Persisting backend configuration to the database
pub struct BackendRegistry {
storage: Arc<Mutex<LocalStorage>>,
backends: Arc<Mutex<BackendMap>>,
Expand All @@ -47,43 +45,6 @@ impl BackendRegistry {
}
}

/// Load all backends from the database and create their instances.
///
/// This should be called once during application initialization.
///
/// # Errors
/// Returns error if database access fails or backend creation fails
pub async fn load_backends(&self) -> Result<()> {
let storage = self.storage.lock().await;
let backend_models = BackendRepository::get_all(&storage.conn).await?;

info!("Loading {} backend(s) from database", backend_models.len());

let mut backends = self.backends.lock().await;

for backend_model in backend_models {
match Self::create_backend_instance(&backend_model) {
Ok(backend_instance) => {
info!(
"✅ Loaded backend: {} ({})",
backend_model.name, backend_model.backend_type
);
backends.insert(backend_model.uuid, Arc::new(backend_instance));
}
Err(e) => {
error!(
"❌ Failed to load backend {} ({}): {}",
backend_model.name, backend_model.backend_type, e
);
// Continue loading other backends
}
}
}

info!("Loaded {} backend instance(s)", backends.len());
Ok(())
}

/// Get a backend instance by UUID.
///
/// # Arguments
Expand All @@ -102,15 +63,6 @@ impl BackendRegistry {
.ok_or_else(|| anyhow::anyhow!("Backend not found: {}", uuid))
}

/// Get all backend instances.
///
/// # Returns
/// Vector of all backend instances
pub async fn get_all_backends(&self) -> Vec<Arc<Box<dyn Backend>>> {
let backends = self.backends.lock().await;
backends.values().cloned().collect()
}

/// List all backend configurations from the database.
///
/// # Returns
Expand All @@ -123,18 +75,6 @@ impl BackendRegistry {
BackendRepository::get_all(&storage.conn).await
}

/// List all enabled backend configurations from the database.
///
/// # Returns
/// Vector of enabled backend models
///
/// # Errors
/// Returns error if database access fails
pub async fn list_enabled_backends(&self) -> Result<Vec<backend::Model>> {
let storage = self.storage.lock().await;
BackendRepository::get_enabled(&storage.conn).await
}

/// Add a new backend.
///
/// # Arguments
Expand Down Expand Up @@ -230,79 +170,6 @@ impl BackendRegistry {
Ok(())
}

/// Remove a backend.
///
/// # Arguments
/// * `uuid` - Backend UUID
///
/// # Errors
/// Returns error if deletion fails
pub async fn remove_backend(&self, uuid: &Uuid) -> Result<()> {
let storage = self.storage.lock().await;
BackendRepository::delete(&storage.conn, uuid).await?;

// Remove from in-memory cache
let mut backends = self.backends.lock().await;
backends.remove(uuid);

info!("✅ Removed backend: {}", uuid);
Ok(())
}

/// Enable a backend.
///
/// # Arguments
/// * `uuid` - Backend UUID
///
/// # Errors
/// Returns error if backend not found or update fails
pub async fn enable_backend(&self, uuid: &Uuid) -> Result<()> {
self.set_enabled_status(uuid, true).await
}

/// Disable a backend.
///
/// # Arguments
/// * `uuid` - Backend UUID
///
/// # Errors
/// Returns error if backend not found or update fails
pub async fn disable_backend(&self, uuid: &Uuid) -> Result<()> {
self.set_enabled_status(uuid, false).await
}

/// Helper to set enabled status.
async fn set_enabled_status(&self, uuid: &Uuid, enabled: bool) -> Result<()> {
let storage = self.storage.lock().await;

let backend_model = BackendRepository::get_by_uuid(&storage.conn, uuid)
.await?
.ok_or_else(|| anyhow::anyhow!("Backend not found: {}", uuid))?;

let mut active_model = backend_model.into_active_model();
active_model.is_enabled = ActiveValue::Set(enabled);

BackendRepository::update(&storage.conn, active_model).await?;

let status = if enabled { "enabled" } else { "disabled" };
info!("✅ Backend {} {}", uuid, status);
Ok(())
}

/// Create a backend instance from a backend model.
///
/// # Arguments
/// * `model` - Backend model from database
///
/// # Returns
/// Boxed backend instance
///
/// # Errors
/// Returns error if backend creation fails
fn create_backend_instance(model: &backend::Model) -> Result<Box<dyn Backend>> {
factory::create_backend(&model.backend_type, &model.credentials)
}

/// Get the storage instance (for creating SyncService instances).
pub fn storage(&self) -> Arc<Mutex<LocalStorage>> {
self.storage.clone()
Expand Down
7 changes: 0 additions & 7 deletions src/entities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,3 @@ pub mod project;
pub mod section;
pub mod task;
pub(crate) mod task_label;

pub use backend::Entity as Backend;
pub use label::Entity as Label;
pub use project::Entity as Project;
pub use section::Entity as Section;
pub use task::Entity as Task;
pub use task_label::Entity as TaskLabel;
Loading