Add more functions to repo type

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent f0709a2a4b
commit 216120ca1d

@ -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",

@ -1,4 +1,5 @@
use sea_orm::DbErr;
use std::fmt::{Display, Formatter};
use thiserror::Error;
pub type RepoResult<T> = Result<T, RepoError>;
@ -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<sea_orm::DbErr> 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()))
}
}

@ -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<Vec<File>> {
let files: Vec<(file::Model, Option<hash::Model>)> = 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<Option<Self>> {
if let Some((model, Some(hash))) = file::Entity::find_by_id(id)

@ -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<Storage>,
}
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<Vec<Storage>> {
Storage::all(self.db.clone()).await
}
/// Returns a storage by path
pub async fn storage_by_path<S: ToString>(&self, path: S) -> RepoResult<Option<Storage>> {
Storage::by_path(self.db.clone(), path).await
}
/// Sets the main storage
pub async fn set_main_storage<S: ToString>(&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<S1: ToString, S2: ToString>(
&self,
@ -26,4 +50,37 @@ impl Repo {
) -> RepoResult<Storage> {
Storage::create(self.db.clone(), name, path).await
}
/// Returns a file by its mapped hash
pub async fn file_by_hash<S: AsRef<str>>(&self, hash: S) -> RepoResult<Option<File>> {
File::by_hash(self.db.clone(), hash).await
}
/// Returns a list of all stored files
pub async fn files(&self) -> RepoResult<Vec<File>> {
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<File> {
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."))
}
}
}

@ -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<Vec<Self>> {
let storages: Vec<storage::Model> = 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<Option<Self>> {
if let Some(model) = storage::Entity::find_by_id(id).one(&db).await? {

@ -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"

@ -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))
}

@ -0,0 +1,5 @@
use rmp_ipc::NamespaceBuilder;
pub fn build(builder: NamespaceBuilder) -> NamespaceBuilder {
builder
}

@ -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
}

@ -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::<SettingsKey>(settings)

Loading…
Cancel
Save