Skip to main content

common/peer/sync/
mod.rs

1//! Sync provider abstraction and job execution
2//!
3//! This module defines the sync provider trait and job types. Each job type
4//! has its own module with execution logic that can be reused by peers.
5
6use anyhow::Result;
7use async_trait::async_trait;
8use thiserror::Error;
9
10use crate::bucket_log::BucketLogProvider;
11use crate::linked_data::Link;
12
13/// Errors that can occur during provenance verification.
14#[derive(Debug, Error)]
15pub enum ProvenanceError {
16    #[error("invalid signature on manifest")]
17    InvalidSignature,
18    #[error("author not in manifest shares")]
19    AuthorNotInShares,
20    #[error("author does not have write permission")]
21    AuthorNotWriter,
22    #[error("invalid manifest in chain at {link}: {reason}")]
23    InvalidManifestInChain { link: Link, reason: String },
24    #[error("unauthorized share removal: only owners can remove shares")]
25    UnauthorizedShareRemoval,
26    #[error("{0}")]
27    Other(#[from] anyhow::Error),
28}
29
30pub mod download_pins;
31pub mod ping_peer;
32pub mod sync_bucket;
33
34// Re-export job types, helpers, and errors
35pub use download_pins::DownloadPinsJob;
36pub use ping_peer::PingPeerJob;
37pub use sync_bucket::{SyncBucketJob, SyncTarget};
38
39/// Background sync job types
40///
41/// These represent the different kinds of background work that can be dispatched.
42#[derive(Debug, Clone)]
43pub enum SyncJob {
44    /// Sync a bucket from a remote peer
45    SyncBucket(SyncBucketJob),
46    /// Download pins from remote peers
47    DownloadPins(DownloadPinsJob),
48    /// Ping a peer to check bucket sync status
49    PingPeer(PingPeerJob),
50}
51
52/// Execute a sync job by calling the appropriate module's execute function
53///
54/// This is a helper function that dispatches to the per-job-type execution logic.
55/// Both synchronous and queued providers can use this.
56pub async fn execute_job<L>(peer: &crate::peer::Peer<L>, job: SyncJob) -> Result<()>
57where
58    L: BucketLogProvider + Clone + Send + Sync + 'static,
59    L::Error: std::error::Error + Send + Sync + 'static,
60{
61    match job {
62        SyncJob::DownloadPins(job) => download_pins::execute(peer, job).await,
63        SyncJob::SyncBucket(job) => sync_bucket::execute(peer, job).await,
64        SyncJob::PingPeer(job) => ping_peer::execute(peer, job).await,
65    }
66}
67
68/// Trait for sync provider implementations
69///
70/// This trait abstracts WHEN and WHERE sync jobs are executed. The actual sync
71/// logic lives in the per-job modules. Implementations decide the execution
72/// context:
73///
74/// - **Synchronous**: Execute immediately by calling execute_job directly
75/// - **Queued**: Send to a channel for background worker processing
76/// - **Actor-based**: Send to an actor mailbox for processing
77///
78/// This allows minimal peers to use simple synchronous execution, while complex
79/// applications can decouple sync jobs from protocol handlers using queues.
80#[async_trait]
81pub trait SyncProvider<L>: Send + Sync + std::fmt::Debug
82where
83    L: BucketLogProvider + Clone + Send + Sync + 'static,
84    L::Error: std::error::Error + Send + Sync + 'static,
85{
86    /// Execute a sync job with the given peer
87    ///
88    /// Implementations decide when and where this runs. The job execution logic
89    /// is provided by the execute_job helper and per-job modules.
90    async fn execute(&self, peer: &crate::peer::Peer<L>, job: SyncJob) -> Result<()>;
91}