pub mod config; pub mod store; use std::fmt; use std::str::FromStr; use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::prelude::RepoId; pub use super::{Alias, NodeId}; /// Repository seeding policy. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct SeedPolicy { pub rid: RepoId, pub scope: Scope, pub policy: Policy, } /// Node following policy. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct FollowPolicy { pub nid: NodeId, pub alias: Option, pub policy: Policy, } /// Resource policy. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum Policy { /// The resource is allowed. Allow, /// The resource is blocked. #[default] Block, } impl fmt::Display for Policy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Allow => write!(f, "allow"), Self::Block => write!(f, "block"), } } } impl FromStr for Policy { type Err = String; fn from_str(s: &str) -> Result { match s { "allow" => Ok(Self::Allow), "block" => Ok(Self::Block), _ => Err(s.to_owned()), } } } impl sqlite::BindableWithIndex for Policy { fn bind( self, stmt: &mut sqlite::Statement<'_>, i: I, ) -> sqlite::Result<()> { match self { Self::Allow => "allow", Self::Block => "block", } .bind(stmt, i) } } impl TryFrom<&sqlite::Value> for Policy { type Error = sqlite::Error; fn try_from(value: &sqlite::Value) -> Result { let message = Some("sql: invalid policy".to_owned()); match value { sqlite::Value::String(s) if s == "allow" => Ok(Policy::Allow), sqlite::Value::String(s) if s == "block" => Ok(Policy::Block), _ => Err(sqlite::Error { code: None, message, }), } } } /// Follow scope of a seeded repository. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum Scope { /// Seed remotes that are explicitly followed. Followed, /// Seed all remotes. #[default] All, } impl fmt::Display for Scope { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scope::Followed => f.write_str("followed"), Scope::All => f.write_str("all"), } } } #[derive(Debug, Error)] #[error("invalid seeding scope: {0:?}")] pub struct ParseScopeError(String); impl FromStr for Scope { type Err = ParseScopeError; fn from_str(s: &str) -> Result { match s { "followed" => Ok(Self::Followed), "all" => Ok(Self::All), _ => Err(ParseScopeError(s.to_string())), } } } impl sqlite::BindableWithIndex for Scope { fn bind( self, stmt: &mut sqlite::Statement<'_>, i: I, ) -> sqlite::Result<()> { let s = match self { Self::Followed => "followed", Self::All => "all", }; s.bind(stmt, i) } } impl TryFrom<&sqlite::Value> for Scope { type Error = sqlite::Error; fn try_from(value: &sqlite::Value) -> Result { let message = Some("invalid remote scope".to_owned()); match value { sqlite::Value::String(scope) => Scope::from_str(scope).map_err(|_| sqlite::Error { code: None, message, }), _ => Err(sqlite::Error { code: None, message, }), } } }