Compare commits
2 commits
12ecc308d5
...
2850fb9887
Author | SHA1 | Date | |
---|---|---|---|
2850fb9887 | |||
a5b016b527 |
23 changed files with 156 additions and 199 deletions
|
@ -13,11 +13,9 @@ categories = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
git-next-core = { workspace = true }
|
git-next-core = { workspace = true }
|
||||||
git-next-file-watcher-actor = { workspace = true }
|
|
||||||
git-next-server-actor = { workspace = true }
|
git-next-server-actor = { workspace = true }
|
||||||
git-next-forge = { workspace = true }
|
git-next-forge = { workspace = true }
|
||||||
git-next-repo-actor = { workspace = true }
|
git-next-repo-actor = { workspace = true }
|
||||||
git-next-webhook-actor = { workspace = true }
|
|
||||||
|
|
||||||
# CLI parsing
|
# CLI parsing
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
|
@ -37,6 +35,7 @@ actix-rt = { workspace = true }
|
||||||
# boilerplate
|
# boilerplate
|
||||||
derive_more = { workspace = true }
|
derive_more = { workspace = true }
|
||||||
derive-with = { workspace = true }
|
derive-with = { workspace = true }
|
||||||
|
thiserror = { workspace = true }
|
||||||
|
|
||||||
# Webhooks
|
# Webhooks
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
@ -45,6 +44,11 @@ ulid = { workspace = true }
|
||||||
time = { workspace = true }
|
time = { workspace = true }
|
||||||
secrecy = { workspace = true }
|
secrecy = { workspace = true }
|
||||||
standardwebhooks = { workspace = true }
|
standardwebhooks = { workspace = true }
|
||||||
|
bytes = { workspace = true }
|
||||||
|
warp = { workspace = true }
|
||||||
|
|
||||||
|
# file watcher (linux)
|
||||||
|
inotify = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# Testing
|
# Testing
|
||||||
|
|
|
@ -522,8 +522,6 @@ stateDiagram-v2
|
||||||
cli --> core
|
cli --> core
|
||||||
cli --> forge
|
cli --> forge
|
||||||
cli --> repo_actor
|
cli --> repo_actor
|
||||||
cli --> webhook_actor
|
|
||||||
cli --> file_watcher_actor
|
|
||||||
|
|
||||||
forge --> core
|
forge --> core
|
||||||
forge --> forge_forgejo
|
forge --> forge_forgejo
|
||||||
|
@ -535,9 +533,6 @@ stateDiagram-v2
|
||||||
|
|
||||||
repo_actor --> core
|
repo_actor --> core
|
||||||
repo_actor --> forge
|
repo_actor --> forge
|
||||||
|
|
||||||
webhook_actor --> core
|
|
||||||
webhook_actor --> repo_actor
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
70
crates/cli/src/file_watcher.rs
Normal file
70
crates/cli/src/file_watcher.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
//
|
||||||
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
use actix::Recipient;
|
||||||
|
use inotify::{EventMask, Inotify, WatchMask};
|
||||||
|
|
||||||
|
use std::{path::PathBuf, time::Duration};
|
||||||
|
|
||||||
|
const CHECK_INTERVAL: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct WatchFile;
|
||||||
|
|
||||||
|
#[derive(Debug, Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct FileUpdated;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("io")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FileWatcher {
|
||||||
|
inotify: Inotify,
|
||||||
|
recipient: Recipient<FileUpdated>,
|
||||||
|
run_interval: Option<SpawnHandle>,
|
||||||
|
}
|
||||||
|
impl FileWatcher {
|
||||||
|
pub fn new(path: PathBuf, recipient: Recipient<FileUpdated>) -> Result<Self, Error> {
|
||||||
|
let inotify = Inotify::init()?;
|
||||||
|
inotify.watches().add(
|
||||||
|
path,
|
||||||
|
WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE | WatchMask::ATTRIB,
|
||||||
|
)?;
|
||||||
|
Ok(Self {
|
||||||
|
inotify,
|
||||||
|
recipient,
|
||||||
|
run_interval: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Actor for FileWatcher {
|
||||||
|
type Context = Context<Self>;
|
||||||
|
|
||||||
|
fn started(&mut self, ctx: &mut Self::Context) {
|
||||||
|
tracing::info!("Starting file watcher actor");
|
||||||
|
self.run_interval
|
||||||
|
.replace(ctx.run_interval(CHECK_INTERVAL, |_act, ctx| {
|
||||||
|
ctx.notify(WatchFile);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<WatchFile> for FileWatcher {
|
||||||
|
type Result = ();
|
||||||
|
|
||||||
|
fn handle(&mut self, _msg: WatchFile, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
let mut buffer = [0u8; 4096];
|
||||||
|
if let Ok(mut events) = self.inotify.read_events(&mut buffer) {
|
||||||
|
if events.any(|event| {
|
||||||
|
event.mask.contains(EventMask::MODIFY) || event.mask.contains(EventMask::ATTRIB)
|
||||||
|
}) {
|
||||||
|
tracing::info!("File modified");
|
||||||
|
self.recipient.do_send(FileUpdated);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
//
|
//
|
||||||
|
mod file_watcher;
|
||||||
mod init;
|
mod init;
|
||||||
mod server;
|
mod server;
|
||||||
|
mod webhook;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
//-
|
//
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
use git_next_core::server::ServerConfig;
|
use git_next_core::server::ServerConfig;
|
||||||
use git_next_file_watcher_actor::FileUpdated;
|
|
||||||
|
|
||||||
use crate::server::actor::{messages::ReceiveServerConfig, ServerActor};
|
use crate::{
|
||||||
|
file_watcher::FileUpdated,
|
||||||
|
server::actor::{messages::ReceiveServerConfig, ServerActor},
|
||||||
|
};
|
||||||
|
|
||||||
impl Handler<FileUpdated> for ServerActor {
|
impl Handler<FileUpdated> for ServerActor {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
|
//
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use git_next_webhook_actor::{AddWebhookRecipient, ShutdownWebhook, WebhookActor, WebhookRouter};
|
|
||||||
|
|
||||||
use crate::server::actor::{
|
use crate::{
|
||||||
|
server::actor::{
|
||||||
messages::{ReceiveValidServerConfig, ValidServerConfig},
|
messages::{ReceiveValidServerConfig, ValidServerConfig},
|
||||||
ServerActor,
|
ServerActor,
|
||||||
|
},
|
||||||
|
webhook::{
|
||||||
|
messages::ShutdownWebhook,
|
||||||
|
router::{AddWebhookRecipient, WebhookRouter},
|
||||||
|
WebhookActor,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Handler<ReceiveValidServerConfig> for ServerActor {
|
impl Handler<ReceiveValidServerConfig> for ServerActor {
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
//-
|
//-
|
||||||
use actix::prelude::*;
|
|
||||||
use git_next_webhook_actor::ShutdownWebhook;
|
|
||||||
|
|
||||||
use crate::server::actor::{messages::Shutdown, ServerActor};
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
server::actor::{messages::Shutdown, ServerActor},
|
||||||
|
webhook::messages::ShutdownWebhook,
|
||||||
|
};
|
||||||
|
|
||||||
impl Handler<Shutdown> for ServerActor {
|
impl Handler<Shutdown> for ServerActor {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
|
|
|
@ -7,14 +7,16 @@ mod tests;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
|
|
||||||
|
use crate::webhook::WebhookActor;
|
||||||
use git_next_core::{
|
use git_next_core::{
|
||||||
git::{repository::factory::RepositoryFactory, Generation, RepoDetails},
|
git::{repository::factory::RepositoryFactory, Generation, RepoDetails},
|
||||||
server::{self, InboundWebhook, ServerConfig, ServerStorage},
|
server::{self, InboundWebhook, ServerConfig, ServerStorage},
|
||||||
ForgeAlias, ForgeConfig, GitDir, RepoAlias, ServerRepoConfig, StoragePathType,
|
ForgeAlias, ForgeConfig, GitDir, RepoAlias, ServerRepoConfig, StoragePathType,
|
||||||
};
|
};
|
||||||
use git_next_repo_actor::messages::NotifyUser;
|
use git_next_repo_actor::{
|
||||||
use git_next_repo_actor::{messages::CloneRepo, RepoActor};
|
messages::{CloneRepo, NotifyUser},
|
||||||
use git_next_webhook_actor::WebhookActor;
|
RepoActor,
|
||||||
|
};
|
||||||
|
|
||||||
use kxio::{fs::FileSystem, network::Network};
|
use kxio::{fs::FileSystem, network::Network};
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,9 @@ mod tests;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
use crate::file_watcher::{FileUpdated, FileWatcher};
|
||||||
use actor::ServerActor;
|
use actor::ServerActor;
|
||||||
use git_next_core::git::RepositoryFactory;
|
use git_next_core::git::RepositoryFactory;
|
||||||
use git_next_file_watcher_actor::{FileUpdated, FileWatcher};
|
|
||||||
|
|
||||||
use kxio::{fs::FileSystem, network::Network};
|
use kxio::{fs::FileSystem, network::Network};
|
||||||
use tracing::{error, info, level_filters::LevelFilter};
|
use tracing::{error, info, level_filters::LevelFilter};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
use crate::{ShutdownWebhook, WebhookActor};
|
use crate::webhook::{messages::ShutdownWebhook, WebhookActor};
|
||||||
|
|
||||||
impl Handler<ShutdownWebhook> for WebhookActor {
|
impl Handler<ShutdownWebhook> for WebhookActor {
|
||||||
type Result = ();
|
type Result = ();
|
42
crates/cli/src/webhook/mod.rs
Normal file
42
crates/cli/src/webhook/mod.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
mod handlers;
|
||||||
|
pub mod messages;
|
||||||
|
pub mod router;
|
||||||
|
mod server;
|
||||||
|
|
||||||
|
use git_next_repo_actor::messages::WebhookNotification;
|
||||||
|
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
use tracing::Instrument;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WebhookActor {
|
||||||
|
socket_addr: SocketAddr,
|
||||||
|
span: tracing::Span,
|
||||||
|
spawn_handle: Option<actix::SpawnHandle>,
|
||||||
|
message_receiver: Recipient<WebhookNotification>,
|
||||||
|
}
|
||||||
|
impl WebhookActor {
|
||||||
|
pub fn new(socket_addr: SocketAddr, message_receiver: Recipient<WebhookNotification>) -> Self {
|
||||||
|
let span = tracing::info_span!("WebhookActor");
|
||||||
|
Self {
|
||||||
|
socket_addr,
|
||||||
|
span,
|
||||||
|
message_receiver,
|
||||||
|
spawn_handle: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Actor for WebhookActor {
|
||||||
|
type Context = actix::Context<Self>;
|
||||||
|
fn started(&mut self, ctx: &mut Self::Context) {
|
||||||
|
let _gaurd = self.span.enter();
|
||||||
|
let address: Recipient<WebhookNotification> = self.message_receiver.clone();
|
||||||
|
let server = server::start(self.socket_addr, address);
|
||||||
|
let spawn_handle = ctx.spawn(server.in_current_span().into_actor(self));
|
||||||
|
self.spawn_handle.replace(spawn_handle);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,31 +5,3 @@ edition = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
description = "Config file watcher for git-next, the trunk-based development manager"
|
description = "Config file watcher for git-next, the trunk-based development manager"
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
# logging
|
|
||||||
tracing = { workspace = true }
|
|
||||||
|
|
||||||
# file watcher
|
|
||||||
inotify = { workspace = true }
|
|
||||||
|
|
||||||
# Webhooks
|
|
||||||
# bytes = { workspace = true }
|
|
||||||
# warp = { workspace = true }
|
|
||||||
|
|
||||||
# boilerplate
|
|
||||||
# derive_more = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
||||||
|
|
||||||
# Actors
|
|
||||||
actix = { workspace = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
# Testing
|
|
||||||
# assert2 = { workspace = true }
|
|
||||||
|
|
||||||
[lints.clippy]
|
|
||||||
nursery = { level = "warn", priority = -1 }
|
|
||||||
# pedantic = "warn"
|
|
||||||
unwrap_used = "warn"
|
|
||||||
expect_used = "warn"
|
|
||||||
|
|
|
@ -7,3 +7,5 @@ development workflows where each commit must pass CI before being included in
|
||||||
the main branch.
|
the main branch.
|
||||||
|
|
||||||
See [git-next](https://crates.io/crates/git-next) for more information.
|
See [git-next](https://crates.io/crates/git-next) for more information.
|
||||||
|
|
||||||
|
N.B. this crate has been merged into [git-next](https://crates.io/git-next).
|
||||||
|
|
|
@ -1,68 +1 @@
|
||||||
use actix::prelude::*;
|
// moved to /crates/cli/src/file_watcher
|
||||||
|
|
||||||
use actix::Recipient;
|
|
||||||
use inotify::{EventMask, Inotify, WatchMask};
|
|
||||||
use std::{path::PathBuf, time::Duration};
|
|
||||||
|
|
||||||
const CHECK_INTERVAL: Duration = Duration::from_secs(1);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct WatchFile;
|
|
||||||
|
|
||||||
#[derive(Debug, Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct FileUpdated;
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("io")]
|
|
||||||
Io(#[from] std::io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FileWatcher {
|
|
||||||
inotify: Inotify,
|
|
||||||
recipient: Recipient<FileUpdated>,
|
|
||||||
run_interval: Option<SpawnHandle>,
|
|
||||||
}
|
|
||||||
impl FileWatcher {
|
|
||||||
pub fn new(path: PathBuf, recipient: Recipient<FileUpdated>) -> Result<Self, Error> {
|
|
||||||
let inotify = Inotify::init()?;
|
|
||||||
inotify.watches().add(
|
|
||||||
path,
|
|
||||||
WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE | WatchMask::ATTRIB,
|
|
||||||
)?;
|
|
||||||
Ok(Self {
|
|
||||||
inotify,
|
|
||||||
recipient,
|
|
||||||
run_interval: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Actor for FileWatcher {
|
|
||||||
type Context = Context<Self>;
|
|
||||||
|
|
||||||
fn started(&mut self, ctx: &mut Self::Context) {
|
|
||||||
tracing::info!("Starting file watcher actor");
|
|
||||||
self.run_interval
|
|
||||||
.replace(ctx.run_interval(CHECK_INTERVAL, |_act, ctx| {
|
|
||||||
ctx.notify(WatchFile);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Handler<WatchFile> for FileWatcher {
|
|
||||||
type Result = ();
|
|
||||||
|
|
||||||
fn handle(&mut self, _msg: WatchFile, _ctx: &mut Self::Context) -> Self::Result {
|
|
||||||
let mut buffer = [0u8; 4096];
|
|
||||||
if let Ok(mut events) = self.inotify.read_events(&mut buffer) {
|
|
||||||
if events.any(|event| {
|
|
||||||
event.mask.contains(EventMask::MODIFY) || event.mask.contains(EventMask::ATTRIB)
|
|
||||||
}) {
|
|
||||||
tracing::info!("File modified");
|
|
||||||
self.recipient.do_send(FileUpdated);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,11 +5,3 @@ edition = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
description = "[deprecated crate] server for git-next, the trunk-based development manager"
|
description = "[deprecated crate] server for git-next, the trunk-based development manager"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[lints.clippy]
|
|
||||||
nursery = { level = "warn", priority = -1 }
|
|
||||||
# pedantic = "warn"
|
|
||||||
unwrap_used = "warn"
|
|
||||||
expect_used = "warn"
|
|
||||||
|
|
|
@ -4,31 +4,4 @@ version = { workspace = true }
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
description = "webhook actor for git-next, the trunk-based development manager"
|
description = "[deprecated crate] webhook actor for git-next, the trunk-based development manager"
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
git-next-core = { workspace = true }
|
|
||||||
git-next-repo-actor = { workspace = true }
|
|
||||||
|
|
||||||
# logging
|
|
||||||
tracing = { workspace = true }
|
|
||||||
|
|
||||||
# Webhooks
|
|
||||||
bytes = { workspace = true }
|
|
||||||
warp = { workspace = true }
|
|
||||||
|
|
||||||
# boilerplate
|
|
||||||
derive_more = { workspace = true }
|
|
||||||
|
|
||||||
# Actors
|
|
||||||
actix = { workspace = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
# Testing
|
|
||||||
# assert2 = { workspace = true }
|
|
||||||
|
|
||||||
[lints.clippy]
|
|
||||||
nursery = { level = "warn", priority = -1 }
|
|
||||||
# pedantic = "warn"
|
|
||||||
unwrap_used = "warn"
|
|
||||||
expect_used = "warn"
|
|
||||||
|
|
|
@ -7,3 +7,5 @@ development workflows where each commit must pass CI before being included in
|
||||||
the main branch.
|
the main branch.
|
||||||
|
|
||||||
See [git-next](https://crates.io/crates/git-next) for more information.
|
See [git-next](https://crates.io/crates/git-next) for more information.
|
||||||
|
|
||||||
|
N.B. this crate has been merged into [git-next](https://crates.io/git-next).
|
||||||
|
|
|
@ -1,45 +1 @@
|
||||||
//
|
// moved to /crates/cli/src/webhook
|
||||||
use actix::prelude::*;
|
|
||||||
|
|
||||||
mod handlers;
|
|
||||||
pub mod messages;
|
|
||||||
mod router;
|
|
||||||
mod server;
|
|
||||||
|
|
||||||
use git_next_repo_actor::messages::WebhookNotification;
|
|
||||||
pub use messages::ShutdownWebhook;
|
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
|
|
||||||
pub use router::AddWebhookRecipient;
|
|
||||||
pub use router::WebhookRouter;
|
|
||||||
use tracing::Instrument;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct WebhookActor {
|
|
||||||
socket_addr: SocketAddr,
|
|
||||||
span: tracing::Span,
|
|
||||||
spawn_handle: Option<actix::SpawnHandle>,
|
|
||||||
message_receiver: Recipient<WebhookNotification>,
|
|
||||||
}
|
|
||||||
impl WebhookActor {
|
|
||||||
pub fn new(socket_addr: SocketAddr, message_receiver: Recipient<WebhookNotification>) -> Self {
|
|
||||||
let span = tracing::info_span!("WebhookActor");
|
|
||||||
Self {
|
|
||||||
socket_addr,
|
|
||||||
span,
|
|
||||||
message_receiver,
|
|
||||||
spawn_handle: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Actor for WebhookActor {
|
|
||||||
type Context = actix::Context<Self>;
|
|
||||||
fn started(&mut self, ctx: &mut Self::Context) {
|
|
||||||
let _gaurd = self.span.enter();
|
|
||||||
let address: Recipient<WebhookNotification> = self.message_receiver.clone();
|
|
||||||
let server = server::start(self.socket_addr, address);
|
|
||||||
let spawn_handle = ctx.spawn(server.in_current_span().into_actor(self));
|
|
||||||
self.spawn_handle.replace(spawn_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue