mod branch; mod config; pub mod status; mod webhook; use actix::prelude::*; use kxio::network::Network; use tracing::{info, warn}; use crate::server::{ config::{RepoConfig, RepoDetails}, forge, git::Git, }; use self::webhook::WebhookId; pub struct RepoActor { details: RepoDetails, config: Option, // INFO: if [None] then send [StartRepo] to populate it webhook_id: Option, // INFO: if [None] then no webhook is configured net: Network, git: Git, } impl RepoActor { pub(crate) const fn new(details: RepoDetails, net: Network, git: Git) -> Self { Self { details, config: None, webhook_id: None, net, git, } } } impl Actor for RepoActor { type Context = Context; fn stopping(&mut self, ctx: &mut Self::Context) -> Running { match self.webhook_id.take() { Some(webhook_id) => { let repo_details = self.details.clone(); let net = self.net.clone(); webhook::unregister(webhook_id, repo_details, net) .into_actor(self) .wait(ctx); Running::Continue } None => Running::Stop, } } } #[derive(Message)] #[rtype(result = "()")] pub struct StartRepo; impl Handler for RepoActor { type Result = (); fn handle(&mut self, _msg: StartRepo, ctx: &mut Self::Context) -> Self::Result { info!(%self.details, "Starting Repo"); let details = self.details.clone(); let addr = ctx.address(); let net = self.net.clone(); config::load(details, addr, net).into_actor(self).wait(ctx); } } #[derive(Message)] #[rtype(result = "()")] struct LoadedConfig(pub RepoConfig); impl Handler for RepoActor { type Result = (); fn handle(&mut self, msg: LoadedConfig, ctx: &mut Self::Context) -> Self::Result { let config = msg.0; info!(%self.details, %config, "Config loaded"); self.config.replace(config); ctx.address().do_send(ValidateRepo); } } #[derive(Message)] #[rtype(result = "()")] pub struct ValidateRepo; impl Handler for RepoActor { type Result = (); fn handle(&mut self, _msg: ValidateRepo, ctx: &mut Self::Context) -> Self::Result { if let Some(repo_config) = self.config.clone() { let repo_details = self.details.clone(); let addr = ctx.address(); let net = self.net.clone(); let git = self.git.clone(); branch::validate_positions(repo_details, repo_config, addr, git, net) .into_actor(self) .wait(ctx); } } } #[derive(Debug, Message)] #[rtype(result = "()")] pub struct StartMonitoring { pub main: forge::Commit, pub next: forge::Commit, pub dev: forge::Commit, pub dev_commit_history: Vec, } impl Handler for RepoActor { type Result = (); fn handle(&mut self, msg: StartMonitoring, ctx: &mut Self::Context) -> Self::Result { let Some(repo_config) = self.config.clone() else { warn!("No config loaded"); return; }; let next_ahead_of_main = msg.main != msg.next; let dev_ahead_of_next = msg.next != msg.dev; info!(%msg.main, %msg.next, %msg.dev, next_ahead_of_main, dev_ahead_of_next, "StartMonitoring"); let repo_details = self.details.clone(); let addr = ctx.address(); let net = self.net.clone(); let git = self.git.clone(); if next_ahead_of_main { status::check_next(msg.next, repo_details, addr, net) .into_actor(self) .wait(ctx); } else if dev_ahead_of_next { branch::advance_next( msg.next, msg.dev_commit_history, repo_details, repo_config, addr, git, ) .into_actor(self) .wait(ctx); } else if self.webhook_id.is_none() { webhook::register(repo_details, addr, net) .into_actor(self) .wait(ctx); } } } #[derive(Message)] #[rtype(result = "()")] pub struct WebhookRegistered(pub WebhookId); impl Handler for RepoActor { type Result = (); fn handle(&mut self, msg: WebhookRegistered, _ctx: &mut Self::Context) -> Self::Result { self.webhook_id.replace(msg.0); } } #[derive(Message)] #[rtype(result = "()")] pub struct AdvanceMainTo(pub forge::Commit); impl Handler for RepoActor { type Result = (); fn handle(&mut self, msg: AdvanceMainTo, ctx: &mut Self::Context) -> Self::Result { let repo_details = self.details.clone(); let Some(repo_config) = self.config.clone() else { warn!("No config loaded"); return; }; let git = self.git.clone(); branch::advance_main(msg.0, repo_details, repo_config, git) .into_actor(self) .wait(ctx); } }