use async_trait::async_trait;
use http::HeaderMap;
use crate::bootstrap::{BootstrapStep, StepOutcome, VgiConfig};
use crate::error::{ForgeError, Result};
use crate::event::{Drift, ForgeEvent, default_diff};
use crate::model::{
ApplyReport, BindCallback, BindRequest, BindStep, Capabilities, ForgeAccount, ForgeKind,
IndirectAccess, LinkCallback, LinkStep, Namespace, NamespaceBinding, Projection, RepoSpec,
RepoState, RoleAssignment, Unlisted,
};
use crate::resource::Resource;
use crate::rights::{EffectiveRights, ForgeRole, RoleMap, collapse_to_ladder};
#[async_trait]
pub trait Forge: Send + Sync {
fn kind(&self) -> ForgeKind;
fn host(&self) -> &str;
fn capabilities(&self, ns: &Namespace) -> Capabilities;
async fn begin_bind(&self, req: BindRequest) -> Result<BindStep>;
async fn complete_bind(&self, cb: BindCallback) -> Result<NamespaceBinding>;
async fn begin_account_link(&self, member: &str) -> Result<LinkStep>;
async fn complete_account_link(&self, cb: LinkCallback) -> Result<ForgeAccount>;
fn normalize(&self, raw: &str) -> Result<Resource> {
let resource = Resource::parse_owner_repo(raw)?;
if resource.host() != self.host() {
return Err(ForgeError::WrongResource {
resource: resource.to_string(),
expected: format!("a resource on `{}`", self.host()),
});
}
Ok(resource)
}
async fn inspect(&self, repo: &Resource) -> Result<RepoState>;
async fn create_repo(&self, spec: &RepoSpec) -> Result<RepoState>;
async fn archive_repo(&self, repo: &Resource) -> Result<()>;
fn map_role(&self, ns: &Namespace, rights: EffectiveRights, map: &RoleMap) -> ForgeRole {
collapse_to_ladder(map.requested(rights), &self.capabilities(ns).role_levels)
}
async fn apply_roles(
&self,
repo: &Resource,
desired: &[RoleAssignment],
unlisted: Unlisted,
) -> Result<ApplyReport>;
fn is_protected_account(&self, ns: &Namespace, account: u64) -> bool {
ns.owner_id == Some(account)
}
async fn indirect_access(
&self,
repo: &Resource,
account: &ForgeAccount,
) -> Result<Option<IndirectAccess>> {
let _ = (repo, account);
Ok(None)
}
fn bootstrap_plan(&self, repo: &RepoSpec, cfg: &VgiConfig) -> Result<Vec<BootstrapStep>>;
async fn run_step(&self, repo: &Resource, step: &BootstrapStep) -> Result<StepOutcome>;
fn parse_event(&self, headers: &HeaderMap, body: &[u8]) -> Result<Option<ForgeEvent>>;
fn diff(&self, observed: &RepoState, desired: &Projection) -> Vec<Drift> {
default_diff(observed, desired)
}
}