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("{0}")]
25 Other(#[from] anyhow::Error),
26}
27
28pub mod download_pins;
29pub mod ping_peer;
30pub mod sync_bucket;
31
32// Re-export job types, helpers, and errors
33pub use download_pins::DownloadPinsJob;
34pub use ping_peer::PingPeerJob;
35pub use sync_bucket::{SyncBucketJob, SyncTarget};
36
37/// Background sync job types
38///
39/// These represent the different kinds of background work that can be dispatched.
40#[derive(Debug, Clone)]
41pub enum SyncJob {
42 /// Sync a bucket from a remote peer
43 SyncBucket(SyncBucketJob),
44 /// Download pins from remote peers
45 DownloadPins(DownloadPinsJob),
46 /// Ping a peer to check bucket sync status
47 PingPeer(PingPeerJob),
48}
49
50/// Execute a sync job by calling the appropriate module's execute function
51///
52/// This is a helper function that dispatches to the per-job-type execution logic.
53/// Both synchronous and queued providers can use this.
54pub async fn execute_job<L>(peer: &crate::peer::Peer<L>, job: SyncJob) -> Result<()>
55where
56 L: BucketLogProvider + Clone + Send + Sync + 'static,
57 L::Error: std::error::Error + Send + Sync + 'static,
58{
59 match job {
60 SyncJob::DownloadPins(job) => download_pins::execute(peer, job).await,
61 SyncJob::SyncBucket(job) => sync_bucket::execute(peer, job).await,
62 SyncJob::PingPeer(job) => ping_peer::execute(peer, job).await,
63 }
64}
65
66/// Trait for sync provider implementations
67///
68/// This trait abstracts WHEN and WHERE sync jobs are executed. The actual sync
69/// logic lives in the per-job modules. Implementations decide the execution
70/// context:
71///
72/// - **Synchronous**: Execute immediately by calling execute_job directly
73/// - **Queued**: Send to a channel for background worker processing
74/// - **Actor-based**: Send to an actor mailbox for processing
75///
76/// This allows minimal peers to use simple synchronous execution, while complex
77/// applications can decouple sync jobs from protocol handlers using queues.
78#[async_trait]
79pub trait SyncProvider<L>: Send + Sync + std::fmt::Debug
80where
81 L: BucketLogProvider + Clone + Send + Sync + 'static,
82 L::Error: std::error::Error + Send + Sync + 'static,
83{
84 /// Execute a sync job with the given peer
85 ///
86 /// Implementations decide when and where this runs. The job execution logic
87 /// is provided by the execute_job helper and per-job modules.
88 async fn execute(&self, peer: &crate::peer::Peer<L>, job: SyncJob) -> Result<()>;
89}