use serde_derive::*;
use std::sync::Arc;
use tokio::sync::mpsc::*;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Update {
Change {
repo: uuid::Uuid,
hash: libpijul::pristine::Hash,
length: u64,
is_tag: bool,
},
Apply {
repo: uuid::Uuid,
channel: String,
hash: libpijul::pristine::Hash,
},
Unrecord {
repo: uuid::Uuid,
channel: String,
hash: libpijul::pristine::Hash,
deps: (),
},
NewChannel {
repo: uuid::Uuid,
channel: String,
},
Fork {
repo: uuid::Uuid,
channel: String,
new: String,
},
Prune {
repo: uuid::Uuid,
channel: String,
},
Rename {
repo: uuid::Uuid,
channel: String,
new: String,
},
}
pub trait Handler: Send + Sync {
type Error: std::fmt::Debug + Send + Sync + 'static;
type F: futures::Future<Output = Result<Option<Self::Error>, Self::Error>> + Send + 'static;
fn update(&self, is_init: bool, update: Update) -> Self::F;
}
#[derive(Clone)]
pub struct Worker<H: Handler> {
pub config: Arc<Config>,
pub handler: Arc<H>,
}
pub struct Config {
pub repositories: PathBuf,
}
impl Config {
pub fn changes_path(&self, id: uuid::Uuid) -> std::path::PathBuf {
let mut p = std::path::Path::new(&self.repositories).join(&format!("{}", id));
p.push(libpijul::DOT_DIR);
p.push("changes");
p
}
pub fn tags_path(&self, id: uuid::Uuid) -> std::path::PathBuf {
self.changes_path(id)
}
}
impl<H: Handler> Worker<H> {
pub fn new(config: Arc<Config>, handler: H) -> Self {
Worker {
config,
handler: Arc::new(handler),
}
}
pub async fn deps(&self, _id: uuid::Uuid) -> Result<(), Error<H::Error>> {
Ok(())
}
pub async fn worker(self, _: UnboundedReceiver<()>) {
futures::future::pending().await
}
pub async fn handle_update(
&self,
_: Option<()>,
_: Option<()>,
_: Option<()>,
update: Update,
) -> Result<(), Error<H::Error>> {
self.handler.update(true, update).await?;
Ok(())
}
pub async fn send_change(
&self,
repo: uuid::Uuid,
hash: libpijul::Hash,
is_tag: bool,
) -> Result<(), Error<H::Error>> {
let mut path = if is_tag {
self.config.tags_path(repo)
} else {
self.config.changes_path(repo)
};
libpijul::changestore::filesystem::push_filename(&mut path, &hash);
if let Ok(m) = std::fs::metadata(&path) {
self.handle_update(
None,
None,
None,
Update::Change {
repo,
hash,
length: m.len(),
is_tag,
},
)
.await?;
Ok(())
} else {
Err(Error::ChangeNotFound { repo, hash })
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ConfigFile {
repositories_path: PathBuf,
}
impl ConfigFile {
pub async fn to_config(self, _blsend: UnboundedSender<()>) -> Config {
Config {
repositories: self.repositories_path,
}
}
}
use thiserror::*;
#[derive(Debug, Error)]
pub enum Error<E> {
#[error(transparent)]
E(#[from]E),
#[error("Change not found")]
ChangeNotFound { repo: uuid::Uuid, hash: libpijul::Hash },
}