From 216120ca1d9866d7a57862ef1a9bb4c02a2b457a Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 9 Oct 2021 20:45:25 +0200 Subject: [PATCH] Add more functions to repo type Signed-off-by: trivernis --- mediarepo-daemon/Cargo.lock | 4 +- mediarepo-daemon/mediarepo-core/src/error.rs | 21 +++++++ mediarepo-daemon/mediarepo-model/src/file.rs | 17 ++++++ mediarepo-daemon/mediarepo-model/src/repo.rs | 61 ++++++++++++++++++- .../mediarepo-model/src/storage.rs | 12 ++++ mediarepo-daemon/mediarepo-socket/Cargo.toml | 2 +- mediarepo-daemon/mediarepo-socket/src/lib.rs | 3 +- .../mediarepo-socket/src/namespaces/files.rs | 5 ++ .../mediarepo-socket/src/namespaces/mod.rs | 9 +++ .../mediarepo-socket/src/types/mod.rs | 0 mediarepo-daemon/src/main.rs | 3 +- 11 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs create mode 100644 mediarepo-daemon/mediarepo-socket/src/types/mod.rs diff --git a/mediarepo-daemon/Cargo.lock b/mediarepo-daemon/Cargo.lock index 933ae3f..37f9c7d 100644 --- a/mediarepo-daemon/Cargo.lock +++ b/mediarepo-daemon/Cargo.lock @@ -1140,9 +1140,9 @@ dependencies = [ [[package]] name = "rmp-ipc" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af495ca346adde10163eb920b52b5a3992fb209b31df58ece4ed0f855661978c" +checksum = "6b83ee65fefc258a2f3a2cb0b144c07f3d9bb877fda93bf29595a7ade6f99513" dependencies = [ "lazy_static", "log", diff --git a/mediarepo-daemon/mediarepo-core/src/error.rs b/mediarepo-daemon/mediarepo-core/src/error.rs index 10f5a5a..128e810 100644 --- a/mediarepo-daemon/mediarepo-core/src/error.rs +++ b/mediarepo-daemon/mediarepo-core/src/error.rs @@ -1,4 +1,5 @@ use sea_orm::DbErr; +use std::fmt::{Display, Formatter}; use thiserror::Error; pub type RepoResult = Result; @@ -23,6 +24,9 @@ pub enum RepoError { #[error(transparent)] IPC(#[from] rmp_ipc::error::Error), + + #[error(transparent)] + Raw(StringError), } #[derive(Error, Debug)] @@ -40,8 +44,25 @@ pub enum RepoDatabaseError { SqlxMigrateError(#[from] sqlx::migrate::MigrateError), } +#[derive(Debug)] +pub struct StringError(String); + +impl Display for StringError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl std::error::Error for StringError {} + impl From for RepoError { fn from(other: DbErr) -> Self { Self::Db(RepoDatabaseError::from(other)) } } + +impl From<&str> for RepoError { + fn from(s: &str) -> Self { + Self::Raw(StringError(s.to_string())) + } +} diff --git a/mediarepo-daemon/mediarepo-model/src/file.rs b/mediarepo-daemon/mediarepo-model/src/file.rs index a5eb9e4..0d07fcd 100644 --- a/mediarepo-daemon/mediarepo-model/src/file.rs +++ b/mediarepo-daemon/mediarepo-model/src/file.rs @@ -22,6 +22,23 @@ impl File { Self { db, model, hash } } + /// Returns a list of all known stored files + pub async fn all(db: DatabaseConnection) -> RepoResult> { + let files: Vec<(file::Model, Option)> = file::Entity::find() + .find_also_related(hash::Entity) + .all(&db) + .await?; + let files = files + .into_iter() + .filter_map(|(f, h)| { + let h = h?; + Some(Self::new(db.clone(), f, h)) + }) + .collect(); + + Ok(files) + } + /// Fetches the file by id pub async fn by_id(db: DatabaseConnection, id: i64) -> RepoResult> { if let Some((model, Some(hash))) = file::Entity::find_by_id(id) diff --git a/mediarepo-daemon/mediarepo-model/src/repo.rs b/mediarepo-daemon/mediarepo-model/src/repo.rs index 7505124..d356214 100644 --- a/mediarepo-daemon/mediarepo-model/src/repo.rs +++ b/mediarepo-daemon/mediarepo-model/src/repo.rs @@ -1,15 +1,23 @@ +use crate::file::File; use crate::storage::Storage; -use mediarepo_core::error::RepoResult; +use mediarepo_core::error::{RepoError, RepoResult}; use mediarepo_database::get_database; use sea_orm::DatabaseConnection; +use std::path::PathBuf; +use tokio::fs::OpenOptions; +use tokio::io::BufReader; pub struct Repo { db: DatabaseConnection, + main_storage: Option, } impl Repo { pub(crate) fn new(db: DatabaseConnection) -> Self { - Self { db } + Self { + db, + main_storage: None, + } } /// Connects to the database with the given uri @@ -18,6 +26,22 @@ impl Repo { Ok(Self::new(db)) } + /// Returns all available storages + pub async fn storages(&self) -> RepoResult> { + Storage::all(self.db.clone()).await + } + + /// Returns a storage by path + pub async fn storage_by_path(&self, path: S) -> RepoResult> { + Storage::by_path(self.db.clone(), path).await + } + + /// Sets the main storage + pub async fn set_main_storage(&mut self, path: S) -> RepoResult<()> { + self.main_storage = Storage::by_path(self.db.clone(), path).await?; + Ok(()) + } + /// Adds a storage to the repository pub async fn add_storage( &self, @@ -26,4 +50,37 @@ impl Repo { ) -> RepoResult { Storage::create(self.db.clone(), name, path).await } + + /// Returns a file by its mapped hash + pub async fn file_by_hash>(&self, hash: S) -> RepoResult> { + File::by_hash(self.db.clone(), hash).await + } + + /// Returns a list of all stored files + pub async fn files(&self) -> RepoResult> { + File::all(self.db.clone()).await + } + + /// Adds a file to the database by its readable path in the file system + pub async fn add_file_by_path(&self, path: PathBuf) -> RepoResult { + let os_file = OpenOptions::new().read(true).open(&path).await?; + let reader = BufReader::new(os_file); + + let storage = self.get_main_storage()?; + let hash = storage.add_file(reader).await?; + let file = self + .file_by_hash(hash) + .await? + .expect("Invalid database state."); + + Ok(file) + } + + fn get_main_storage(&self) -> RepoResult<&Storage> { + if let Some(storage) = &self.main_storage { + Ok(storage) + } else { + Err(RepoError::from("No main storage configured.")) + } + } } diff --git a/mediarepo-daemon/mediarepo-model/src/storage.rs b/mediarepo-daemon/mediarepo-model/src/storage.rs index eaacb47..6b40b31 100644 --- a/mediarepo-daemon/mediarepo-model/src/storage.rs +++ b/mediarepo-daemon/mediarepo-model/src/storage.rs @@ -9,6 +9,7 @@ use std::path::PathBuf; use tokio::fs; use tokio::io::{AsyncRead, BufReader}; +#[derive(Clone)] pub struct Storage { db: DatabaseConnection, model: StorageModel, @@ -25,6 +26,17 @@ impl Storage { } } + /// Returns all available storages + pub async fn all(db: DatabaseConnection) -> RepoResult> { + let storages: Vec = storage::Entity::find().all(&db).await?; + let storages = storages + .into_iter() + .map(|s| Self::new(db.clone(), s)) + .collect(); + + Ok(storages) + } + /// Returns the storage by id pub async fn by_id(db: DatabaseConnection, id: i64) -> RepoResult> { if let Some(model) = storage::Entity::find_by_id(id).one(&db).await? { diff --git a/mediarepo-daemon/mediarepo-socket/Cargo.toml b/mediarepo-daemon/mediarepo-socket/Cargo.toml index 96c909d..14203c1 100644 --- a/mediarepo-daemon/mediarepo-socket/Cargo.toml +++ b/mediarepo-daemon/mediarepo-socket/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rmp-ipc = "0.4.0" +rmp-ipc = "0.4.1" [dependencies.tokio] version = "1.12.0" diff --git a/mediarepo-daemon/mediarepo-socket/src/lib.rs b/mediarepo-daemon/mediarepo-socket/src/lib.rs index 58ac1c3..ad9665f 100644 --- a/mediarepo-daemon/mediarepo-socket/src/lib.rs +++ b/mediarepo-daemon/mediarepo-socket/src/lib.rs @@ -1,7 +1,8 @@ use rmp_ipc::IPCBuilder; mod namespaces; +pub mod types; pub fn get_builder(address: &str) -> IPCBuilder { - IPCBuilder::new().address(address) + namespaces::build_namespaces(IPCBuilder::new().address(address)) } diff --git a/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs b/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs new file mode 100644 index 0000000..dd0215c --- /dev/null +++ b/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs @@ -0,0 +1,5 @@ +use rmp_ipc::NamespaceBuilder; + +pub fn build(builder: NamespaceBuilder) -> NamespaceBuilder { + builder +} diff --git a/mediarepo-daemon/mediarepo-socket/src/namespaces/mod.rs b/mediarepo-daemon/mediarepo-socket/src/namespaces/mod.rs index e69de29..5b00c71 100644 --- a/mediarepo-daemon/mediarepo-socket/src/namespaces/mod.rs +++ b/mediarepo-daemon/mediarepo-socket/src/namespaces/mod.rs @@ -0,0 +1,9 @@ +use rmp_ipc::IPCBuilder; + +pub mod files; + +pub fn build_namespaces(builder: IPCBuilder) -> IPCBuilder { + let builder = files::build(builder.namespace("files")).build(); + + builder +} diff --git a/mediarepo-daemon/mediarepo-socket/src/types/mod.rs b/mediarepo-daemon/mediarepo-socket/src/types/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/mediarepo-daemon/src/main.rs b/mediarepo-daemon/src/main.rs index 5c5f6a9..4fd28c7 100644 --- a/mediarepo-daemon/src/main.rs +++ b/mediarepo-daemon/src/main.rs @@ -52,7 +52,8 @@ async fn main() -> RepoResult<()> { /// Starts the server async fn start_server(opt: Opt) -> RepoResult<()> { let settings = load_settings(&opt.repo.join(SETTINGS_PATH)).await?; - let repo = get_repo(&opt.repo.join(&settings.database_path).to_str().unwrap()).await?; + let mut repo = get_repo(&opt.repo.join(&settings.database_path).to_str().unwrap()).await?; + repo.set_main_storage(&settings.default_file_store).await?; get_builder(&settings.listen_address) .insert::(settings)