diff --git a/src/app.rs b/src/app.rs index caa657d..876dd0e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -339,6 +339,7 @@ impl AppaService { }) } + #[cfg(test)] pub async fn sync_once(&self, folder_path: &Path) -> AppResult { let folder = self.require_folder(folder_path)?; let node = self.load_node().await?; diff --git a/src/app/sync.rs b/src/app/sync.rs index 5334956..478eda3 100644 --- a/src/app/sync.rs +++ b/src/app/sync.rs @@ -11,6 +11,7 @@ use crate::{ use futures_util::{StreamExt, stream}; impl AppaService { + #[cfg(test)] pub(super) async fn sync_with_node( &self, folder: &FolderConfig, diff --git a/src/domain.rs b/src/domain.rs index 21618b2..666033a 100644 --- a/src/domain.rs +++ b/src/domain.rs @@ -8,14 +8,11 @@ mod merkle; mod reconciliation; mod roster; -pub use merkle::{ - ManifestMerkleIndex, ManifestMerkleNode, manifest_merkle_node, manifest_root_hash, -}; -pub use reconciliation::{ - CONFLICT_ARTIFACT_MARKER, ClockOrder, ReconciliationAction, compare_version_clocks, - conflict_path, is_conflict_artifact, reconcile_manifests, -}; -pub use roster::{FolderRoster, MemberRole, RosterMember}; +pub(crate) use merkle::{ManifestMerkleIndex, ManifestMerkleNode, manifest_root_hash}; +#[cfg(test)] +pub(crate) use reconciliation::{ClockOrder, compare_version_clocks}; +pub(crate) use reconciliation::{ReconciliationAction, is_conflict_artifact, reconcile_manifests}; +pub(crate) use roster::{FolderRoster, MemberRole, RosterMember}; pub type DeviceId = String; pub type FolderId = Uuid; diff --git a/src/domain/merkle.rs b/src/domain/merkle.rs index c2b70ba..dd9b1c4 100644 --- a/src/domain/merkle.rs +++ b/src/domain/merkle.rs @@ -68,7 +68,8 @@ pub fn manifest_root_hash(manifest: &Manifest) -> anyhow::Result { Ok(ManifestMerkleIndex::build(manifest)?.root_hash().to_owned()) } -pub fn manifest_merkle_node( +#[cfg(test)] +pub(super) fn manifest_merkle_node( manifest: &Manifest, prefix: &str, ) -> anyhow::Result { diff --git a/src/iroh.rs b/src/iroh.rs index 86c30bd..fd0d2cf 100644 --- a/src/iroh.rs +++ b/src/iroh.rs @@ -261,7 +261,7 @@ impl NodeHost { let connection = self.endpoint.connect(peer, APPA_ALPN).await?; let response = request_control_message( &connection, - &ControlMessage::ManifestAnnouncement { + &ControlMessage::Announcement { folder_id, capability, root_hash, @@ -269,7 +269,7 @@ impl NodeHost { }, ) .await?; - if response != ControlMessage::ManifestAnnouncementAccepted { + if response != ControlMessage::AnnouncementAccepted { anyhow::bail!("peer rejected manifest announcement"); } Ok(()) @@ -285,7 +285,7 @@ impl NodeHost { let connection = self.connect_to_peer(peer_address).await?; let response = request_control_message( &connection, - &ControlMessage::ManifestRequest { + &ControlMessage::Request { folder_id, capability, invite: invite.map(Box::new), @@ -294,7 +294,7 @@ impl NodeHost { }, ) .await?; - let ControlMessage::ManifestSummary { + let ControlMessage::Summary { summary, roster, peer_endpoints, @@ -374,7 +374,7 @@ impl NodeHost { ) -> anyhow::Result { let response = request_control_message( connection, - &ControlMessage::ManifestRequest { + &ControlMessage::Request { folder_id, capability, invite: invite.map(Box::new), @@ -383,7 +383,7 @@ impl NodeHost { }, ) .await?; - let ControlMessage::ManifestMerkleNode { node } = response else { + let ControlMessage::MerkleNode { node } = response else { anyhow::bail!("peer returned an unexpected control message"); }; Ok(node) diff --git a/src/iroh/handler.rs b/src/iroh/handler.rs index d90ac75..0b70797 100644 --- a/src/iroh/handler.rs +++ b/src/iroh/handler.rs @@ -51,7 +51,7 @@ impl AppaProtocol { .await .map_err(|_| protocol_error("Appa control request timed out"))??; let response = match request { - ControlMessage::ManifestRequest { + ControlMessage::Request { folder_id, capability, invite, @@ -84,7 +84,7 @@ impl AppaProtocol { ); response } - ControlMessage::ManifestAnnouncement { + ControlMessage::Announcement { folder_id, capability, root_hash, @@ -102,7 +102,7 @@ impl AppaProtocol { .unwrap_or_else(std::sync::PoisonError::into_inner) .insert(folder_id, root_hash); tracing::debug!(peer = %connection.remote_id(), folder = %folder_id, "Received folder change announcement"); - ControlMessage::ManifestAnnouncementAccepted + ControlMessage::AnnouncementAccepted } _ => return Err(protocol_error("unsupported Appa control message")), }; @@ -161,7 +161,7 @@ impl AppaProtocol { return Err(protocol_error("requester lacks a valid Appa invitation")); } match request_kind { - ManifestRequestKind::Summary => Ok(ControlMessage::ManifestSummary { + ManifestRequestKind::Summary => Ok(ControlMessage::Summary { summary: ManifestSummary { folder_id, root_hash: folder.merkle_index.root_hash().to_owned(), @@ -170,7 +170,7 @@ impl AppaProtocol { peer_endpoints: folder.peer_endpoints.clone(), capability: folder.capability.clone(), }), - ManifestRequestKind::MerkleNode { prefix } => Ok(ControlMessage::ManifestMerkleNode { + ManifestRequestKind::MerkleNode { prefix } => Ok(ControlMessage::MerkleNode { node: folder .merkle_index .node(&prefix) diff --git a/src/lib.rs b/src/lib.rs index e60b7b0..13994ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,17 @@ -pub mod app; -pub mod cli; -pub mod config; -pub mod domain; -pub mod filesystem; -pub mod iroh; -pub mod protocol; -pub mod service; -pub mod storage; +//! Appa's command-line application. +//! +//! The stable Rust interface is intentionally limited to [`run`]. Internal +//! modules remain private while the library API is still being designed. + +mod app; +mod cli; +mod config; +mod domain; +mod filesystem; +mod iroh; +mod protocol; +mod service; +mod storage; + +/// Runs Appa's command-line interface. +pub use cli::run; diff --git a/src/main.rs b/src/main.rs index 53b387c..e471fbb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ #[tokio::main] async fn main() -> anyhow::Result<()> { - appa::cli::run().await + appa::run().await } diff --git a/src/protocol.rs b/src/protocol.rs index e65fa36..b6d8b28 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -1,8 +1,8 @@ use anyhow::Context; -use crate::domain::{ - DeviceId, FolderId, FolderRoster, Manifest, ManifestMerkleNode, manifest_root_hash, -}; +use crate::domain::{DeviceId, FolderId, FolderRoster, ManifestMerkleNode}; +#[cfg(test)] +use crate::domain::{Manifest, manifest_root_hash}; use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD}; use iroh::{EndpointAddr, EndpointId, SecretKey, Signature}; use serde::{Deserialize, Serialize}; @@ -18,6 +18,7 @@ pub struct ManifestSummary { } impl ManifestSummary { + #[cfg(test)] pub fn from_manifest(manifest: &Manifest) -> anyhow::Result { Ok(Self { folder_id: manifest.folder_id, @@ -74,29 +75,29 @@ impl Invite { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ControlMessage { - ManifestRequest { + Request { folder_id: FolderId, capability: String, invite: Option>, requester_endpoint: EndpointAddr, request: ManifestRequestKind, }, - ManifestSummary { + Summary { summary: ManifestSummary, roster: FolderRoster, peer_endpoints: Vec, capability: String, }, - ManifestMerkleNode { + MerkleNode { node: ManifestMerkleNode, }, - ManifestAnnouncement { + Announcement { folder_id: FolderId, capability: String, root_hash: String, sender_endpoint: EndpointAddr, }, - ManifestAnnouncementAccepted, + AnnouncementAccepted, } pub fn encode_invite(invite: &Invite) -> anyhow::Result {