2024-07-28 08:58:32 +01:00
|
|
|
//
|
|
|
|
use actix::prelude::*;
|
|
|
|
|
2024-08-12 21:25:24 +01:00
|
|
|
use crate::{
|
|
|
|
alerts::messages::NotifyUser,
|
|
|
|
server::{
|
|
|
|
actor::messages::{RepoUpdate, ServerUpdate},
|
|
|
|
ServerActor,
|
|
|
|
},
|
|
|
|
};
|
2024-07-28 08:58:32 +01:00
|
|
|
use derive_more::Deref;
|
|
|
|
use kxio::network::Network;
|
|
|
|
use std::time::Duration;
|
2024-08-12 21:25:24 +01:00
|
|
|
use tracing::{info, instrument, warn, Instrument};
|
2024-07-28 08:58:32 +01:00
|
|
|
|
|
|
|
use git_next_core::{
|
|
|
|
git::{
|
|
|
|
self,
|
|
|
|
repository::{factory::RepositoryFactory, open::OpenRepositoryLike},
|
|
|
|
UserNotification,
|
|
|
|
},
|
2024-07-31 07:20:42 +01:00
|
|
|
server::ListenUrl,
|
|
|
|
WebhookAuth, WebhookId,
|
2024-07-28 08:58:32 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
mod branch;
|
|
|
|
pub mod handlers;
|
|
|
|
mod load;
|
|
|
|
pub mod messages;
|
|
|
|
mod notifications;
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2024-08-03 22:31:17 +01:00
|
|
|
pub mod tests;
|
2024-07-28 08:58:32 +01:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, Default)]
|
2024-08-05 07:39:38 +01:00
|
|
|
pub struct ActorLog(std::sync::Arc<std::sync::RwLock<Vec<String>>>);
|
|
|
|
impl Deref for ActorLog {
|
2024-07-28 08:58:32 +01:00
|
|
|
type Target = std::sync::Arc<std::sync::RwLock<Vec<String>>>;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An actor that represents a Git Repository.
|
|
|
|
///
|
2024-08-05 07:39:38 +01:00
|
|
|
/// When this actor is started it is sent the `CloneRepo` message.
|
|
|
|
#[allow(clippy::module_name_repetitions)]
|
2024-07-28 08:58:32 +01:00
|
|
|
#[derive(Debug, derive_more::Display, derive_with::With)]
|
|
|
|
#[display("{}:{}:{}", generation, repo_details.forge.forge_alias(), repo_details.repo_alias)]
|
|
|
|
pub struct RepoActor {
|
|
|
|
sleep_duration: std::time::Duration,
|
|
|
|
generation: git::Generation,
|
|
|
|
message_token: messages::MessageToken,
|
|
|
|
repo_details: git::RepoDetails,
|
2024-07-31 07:20:42 +01:00
|
|
|
listen_url: ListenUrl,
|
2024-07-28 08:58:32 +01:00
|
|
|
webhook_id: Option<WebhookId>, // INFO: if [None] then no webhook is configured
|
|
|
|
webhook_auth: Option<WebhookAuth>, // INFO: if [None] then no webhook is configured
|
|
|
|
last_main_commit: Option<git::Commit>,
|
|
|
|
last_next_commit: Option<git::Commit>,
|
|
|
|
last_dev_commit: Option<git::Commit>,
|
|
|
|
repository_factory: Box<dyn RepositoryFactory>,
|
|
|
|
open_repository: Option<Box<dyn OpenRepositoryLike>>,
|
|
|
|
net: Network,
|
|
|
|
forge: Box<dyn git::ForgeLike>,
|
2024-08-05 07:39:38 +01:00
|
|
|
log: Option<ActorLog>,
|
2024-07-28 08:58:32 +01:00
|
|
|
notify_user_recipient: Option<Recipient<NotifyUser>>,
|
2024-08-12 21:25:24 +01:00
|
|
|
server_addr: Option<Addr<ServerActor>>,
|
2024-07-28 08:58:32 +01:00
|
|
|
}
|
|
|
|
impl RepoActor {
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
pub fn new(
|
|
|
|
repo_details: git::RepoDetails,
|
|
|
|
forge: Box<dyn git::ForgeLike>,
|
2024-07-31 07:20:42 +01:00
|
|
|
listen_url: ListenUrl,
|
2024-07-28 08:58:32 +01:00
|
|
|
generation: git::Generation,
|
|
|
|
net: Network,
|
|
|
|
repository_factory: Box<dyn RepositoryFactory>,
|
|
|
|
sleep_duration: std::time::Duration,
|
|
|
|
notify_user_recipient: Option<Recipient<NotifyUser>>,
|
2024-08-12 21:25:24 +01:00
|
|
|
server_addr: Option<Addr<ServerActor>>,
|
2024-07-28 08:58:32 +01:00
|
|
|
) -> Self {
|
|
|
|
let message_token = messages::MessageToken::default();
|
|
|
|
Self {
|
|
|
|
generation,
|
|
|
|
message_token,
|
|
|
|
repo_details,
|
2024-07-31 07:20:42 +01:00
|
|
|
listen_url,
|
2024-07-28 08:58:32 +01:00
|
|
|
webhook_id: None,
|
|
|
|
webhook_auth: None,
|
|
|
|
last_main_commit: None,
|
|
|
|
last_next_commit: None,
|
|
|
|
last_dev_commit: None,
|
|
|
|
repository_factory,
|
|
|
|
open_repository: None,
|
|
|
|
forge,
|
|
|
|
net,
|
|
|
|
sleep_duration,
|
|
|
|
log: None,
|
|
|
|
notify_user_recipient,
|
2024-08-12 21:25:24 +01:00
|
|
|
server_addr,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update_tui_branches(&self) {
|
|
|
|
#[cfg(feature = "tui")]
|
|
|
|
{
|
|
|
|
use crate::server::actor::messages::RepoUpdate;
|
|
|
|
let Some(repo_config) = &self.repo_details.repo_config else {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
let branches = repo_config.branches().clone();
|
|
|
|
self.update_tui(RepoUpdate::Branches { branches });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[instrument]
|
|
|
|
fn update_tui_log(&self, log: git::graph::Log) {
|
|
|
|
info!("ready to send log");
|
|
|
|
#[cfg(feature = "tui")]
|
|
|
|
{
|
|
|
|
info!("sending...");
|
|
|
|
self.update_tui(RepoUpdate::Log { log });
|
|
|
|
info!("sent");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alert_tui(&self, alert: impl Into<String>) {
|
|
|
|
#[cfg(feature = "tui")]
|
|
|
|
{
|
|
|
|
self.update_tui(RepoUpdate::Alert {
|
|
|
|
alert: alert.into(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update_tui(&self, repo_update: RepoUpdate) {
|
|
|
|
#[cfg(feature = "tui")]
|
|
|
|
{
|
|
|
|
let Some(server_addr) = &self.server_addr else {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
let update = ServerUpdate::RepoUpdate {
|
|
|
|
forge_alias: self.repo_details.forge.forge_alias().clone(),
|
|
|
|
repo_alias: self.repo_details.repo_alias.clone(),
|
|
|
|
repo_update,
|
|
|
|
};
|
|
|
|
server_addr.do_send(update);
|
2024-07-28 08:58:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Actor for RepoActor {
|
|
|
|
type Context = Context<Self>;
|
|
|
|
#[tracing::instrument(name = "RepoActor::stopping", skip_all, fields(repo = %self.repo_details))]
|
|
|
|
fn stopping(&mut self, ctx: &mut Self::Context) -> Running {
|
|
|
|
tracing::debug!("stopping");
|
|
|
|
info!("Checking webhook");
|
|
|
|
match self.webhook_id.take() {
|
|
|
|
Some(webhook_id) => {
|
|
|
|
tracing::warn!("stopping - unregistering webhook");
|
|
|
|
info!(%webhook_id, "Unregistring webhook");
|
|
|
|
let forge = self.forge.duplicate();
|
|
|
|
async move {
|
|
|
|
if let Err(err) = forge.unregister_webhook(&webhook_id).await {
|
|
|
|
warn!("unregistering webhook: {err}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.in_current_span()
|
|
|
|
.into_actor(self)
|
|
|
|
.wait(ctx);
|
|
|
|
Running::Continue
|
|
|
|
}
|
|
|
|
None => Running::Stop,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-05 07:39:38 +01:00
|
|
|
pub fn delay_send<M>(addr: &Addr<RepoActor>, delay: Duration, msg: M, log: Option<&ActorLog>)
|
2024-07-28 08:58:32 +01:00
|
|
|
where
|
|
|
|
M: actix::Message + Send + 'static + std::fmt::Debug,
|
|
|
|
RepoActor: actix::Handler<M>,
|
|
|
|
<M as actix::Message>::Result: Send,
|
|
|
|
{
|
2024-08-05 07:39:38 +01:00
|
|
|
let log_message = format!("send-after-delay: {msg:?}");
|
2024-07-28 08:58:32 +01:00
|
|
|
tracing::debug!(log_message);
|
|
|
|
logger(log, log_message);
|
|
|
|
std::thread::sleep(delay);
|
2024-08-05 07:39:38 +01:00
|
|
|
do_send(addr, msg, log);
|
2024-07-28 08:58:32 +01:00
|
|
|
}
|
|
|
|
|
2024-08-05 07:39:38 +01:00
|
|
|
pub fn do_send<M>(addr: &Addr<RepoActor>, msg: M, log: Option<&ActorLog>)
|
2024-07-28 08:58:32 +01:00
|
|
|
where
|
|
|
|
M: actix::Message + Send + 'static + std::fmt::Debug,
|
|
|
|
RepoActor: actix::Handler<M>,
|
|
|
|
<M as actix::Message>::Result: Send,
|
|
|
|
{
|
2024-08-05 07:39:38 +01:00
|
|
|
let log_message = format!("send: {msg:?}");
|
2024-07-28 08:58:32 +01:00
|
|
|
tracing::debug!(log_message);
|
|
|
|
logger(log, log_message);
|
2024-08-05 07:39:38 +01:00
|
|
|
if cfg!(not(test)) {
|
|
|
|
// #[cfg(not(test))]
|
|
|
|
addr.do_send(msg);
|
|
|
|
}
|
2024-07-28 08:58:32 +01:00
|
|
|
}
|
|
|
|
|
2024-08-05 07:39:38 +01:00
|
|
|
pub fn logger(log: Option<&ActorLog>, message: impl Into<String>) {
|
2024-07-28 08:58:32 +01:00
|
|
|
if let Some(log) = log {
|
|
|
|
let message: String = message.into();
|
|
|
|
tracing::debug!(message);
|
|
|
|
let _ = log.write().map(|mut l| l.push(message));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn notify_user(
|
|
|
|
recipient: Option<&Recipient<NotifyUser>>,
|
|
|
|
user_notification: UserNotification,
|
2024-08-05 07:39:38 +01:00
|
|
|
log: Option<&ActorLog>,
|
2024-07-28 08:58:32 +01:00
|
|
|
) {
|
|
|
|
let msg = NotifyUser::from(user_notification);
|
2024-08-05 07:39:38 +01:00
|
|
|
let log_message = format!("send: {msg:?}");
|
2024-07-28 08:58:32 +01:00
|
|
|
tracing::debug!(log_message);
|
|
|
|
logger(log, log_message);
|
|
|
|
if let Some(recipient) = &recipient {
|
|
|
|
recipient.do_send(msg);
|
|
|
|
}
|
|
|
|
}
|