Implement new settings format and remove storage table
TG-16 #done TG-67 #closed Signed-off-by: trivernis <trivernis@protonmail.com>pull/4/head
parent
796eb56a62
commit
f77a45e963
@ -1,38 +0,0 @@
|
|||||||
use crate::error::RepoResult;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::net::IpAddr;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
||||||
pub struct Settings {
|
|
||||||
pub listen_address: IpAddr,
|
|
||||||
pub port_range: (u16, u16),
|
|
||||||
pub database_path: String,
|
|
||||||
pub default_file_store: String,
|
|
||||||
pub thumbnail_store: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Settings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
listen_address: IpAddr::from([127, 0, 0, 1]),
|
|
||||||
port_range: (3400, 3500),
|
|
||||||
database_path: "./db/repo.db".to_string(),
|
|
||||||
default_file_store: "Main".to_string(),
|
|
||||||
thumbnail_store: "./thumbnails".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Settings {
|
|
||||||
/// Parses settings from a string
|
|
||||||
pub fn from_toml_string(s: &str) -> RepoResult<Self> {
|
|
||||||
let settings = toml::from_str(s)?;
|
|
||||||
Ok(settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the settings into a toml string
|
|
||||||
pub fn to_toml_string(&self) -> RepoResult<String> {
|
|
||||||
let string = toml::to_string(&self)?;
|
|
||||||
Ok(string)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,42 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tracing::Level;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct LoggingSettings {
|
||||||
|
pub level: LogLevel,
|
||||||
|
pub trace_sql: bool,
|
||||||
|
pub trace_api_calls: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LoggingSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
level: LogLevel::Info,
|
||||||
|
trace_sql: false,
|
||||||
|
trace_api_calls: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub enum LogLevel {
|
||||||
|
Off,
|
||||||
|
Error,
|
||||||
|
Warn,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
Trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Option<Level>> for LogLevel {
|
||||||
|
fn into(self) -> Option<Level> {
|
||||||
|
match self {
|
||||||
|
LogLevel::Off => None,
|
||||||
|
LogLevel::Error => Some(Level::ERROR),
|
||||||
|
LogLevel::Warn => Some(Level::WARN),
|
||||||
|
LogLevel::Info => Some(Level::INFO),
|
||||||
|
LogLevel::Debug => Some(Level::DEBUG),
|
||||||
|
LogLevel::Trace => Some(Level::TRACE),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
mod logging;
|
||||||
|
mod paths;
|
||||||
|
mod server;
|
||||||
|
pub mod v1;
|
||||||
|
|
||||||
|
use crate::error::RepoResult;
|
||||||
|
use crate::settings::v1::SettingsV1;
|
||||||
|
use config::{Config, FileFormat};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub use logging::*;
|
||||||
|
pub use paths::*;
|
||||||
|
pub use server::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
|
||||||
|
pub struct Settings {
|
||||||
|
pub server: ServerSettings,
|
||||||
|
pub paths: PathSettings,
|
||||||
|
pub logging: LoggingSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Settings {
|
||||||
|
pub fn read(root: &PathBuf) -> RepoResult<Self> {
|
||||||
|
let mut settings = Config::default();
|
||||||
|
settings
|
||||||
|
.merge(config::File::from_str(
|
||||||
|
&*Settings::default().to_toml_string()?,
|
||||||
|
FileFormat::Toml,
|
||||||
|
))?
|
||||||
|
.merge(config::File::from(root.join("repo")))?
|
||||||
|
.merge(config::Environment::with_prefix("MEDIAREPO"))?;
|
||||||
|
tracing::debug!("Settings are: {:#?}", settings);
|
||||||
|
|
||||||
|
Ok(settings.try_into::<Settings>()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses settings from a string
|
||||||
|
pub fn from_v1(settings_v1: SettingsV1) -> RepoResult<Self> {
|
||||||
|
let mut settings_main = Settings::default();
|
||||||
|
settings_main.server.tcp.enabled = true;
|
||||||
|
settings_main.server.tcp.port = PortSetting::Range(settings_v1.port_range);
|
||||||
|
settings_main.server.tcp.listen_address = settings_v1.listen_address;
|
||||||
|
settings_main.paths.thumbnail_directory = settings_v1.thumbnail_store.into();
|
||||||
|
settings_main.paths.database_directory = PathBuf::from(settings_v1.database_path)
|
||||||
|
.parent()
|
||||||
|
.map(|p| p.to_string_lossy().to_string())
|
||||||
|
.unwrap_or_else(|| String::from("./"));
|
||||||
|
|
||||||
|
let mut settings = Config::default();
|
||||||
|
settings
|
||||||
|
.merge(config::File::from_str(
|
||||||
|
&*settings_main.to_toml_string()?,
|
||||||
|
FileFormat::Toml,
|
||||||
|
))?
|
||||||
|
.merge(config::Environment::with_prefix("MEDIAREPO"))?;
|
||||||
|
tracing::debug!("Settings are: {:#?}", settings);
|
||||||
|
|
||||||
|
Ok(settings.try_into::<Settings>()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the settings into a toml string
|
||||||
|
pub fn to_toml_string(&self) -> RepoResult<String> {
|
||||||
|
let string = toml::to_string(&self)?;
|
||||||
|
|
||||||
|
Ok(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save(&self, root: &PathBuf) -> RepoResult<()> {
|
||||||
|
let string = toml::to_string_pretty(&self)?;
|
||||||
|
fs::write(root.join("repo.toml"), string.into_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct PathSettings {
|
||||||
|
pub(crate) database_directory: String,
|
||||||
|
pub(crate) files_directory: String,
|
||||||
|
pub(crate) thumbnail_directory: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PathSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
database_directory: String::from("db"),
|
||||||
|
files_directory: String::from("files"),
|
||||||
|
thumbnail_directory: String::from("thumbnails"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathSettings {
|
||||||
|
#[inline]
|
||||||
|
pub fn database_dir(&self, root: &PathBuf) -> PathBuf {
|
||||||
|
root.join(&self.database_directory)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn files_dir(&self, root: &PathBuf) -> PathBuf {
|
||||||
|
root.join(&self.files_directory)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn thumbs_dir(&self, root: &PathBuf) -> PathBuf {
|
||||||
|
root.join(&self.thumbnail_directory)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn db_file_path(&self, root: &PathBuf) -> PathBuf {
|
||||||
|
self.database_dir(root).join("repo.db")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn frontend_state_file_path(&self, root: &PathBuf) -> PathBuf {
|
||||||
|
self.database_dir(root).join("frontend-state.json")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
|
||||||
|
pub struct ServerSettings {
|
||||||
|
pub tcp: TcpServerSettings,
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub unix_socket: UnixSocketServerSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct TcpServerSettings {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub listen_address: IpAddr,
|
||||||
|
pub port: PortSetting,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum PortSetting {
|
||||||
|
Fixed(u16),
|
||||||
|
Range((u16, u16)),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TcpServerSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: cfg!(windows),
|
||||||
|
listen_address: IpAddr::from([127, 0, 0, 1]),
|
||||||
|
port: PortSetting::Range((13400, 13500)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct UnixSocketServerSettings {
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl Default for UnixSocketServerSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { enabled: true }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
use crate::error::RepoResult;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct SettingsV1 {
|
||||||
|
pub listen_address: IpAddr,
|
||||||
|
pub port_range: (u16, u16),
|
||||||
|
pub database_path: String,
|
||||||
|
pub default_file_store: String,
|
||||||
|
pub thumbnail_store: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SettingsV1 {
|
||||||
|
/// Parses settings from a string
|
||||||
|
pub fn from_toml_string(s: &str) -> RepoResult<Self> {
|
||||||
|
let settings = toml::from_str(s)?;
|
||||||
|
Ok(settings)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
-- Add migration script here
|
||||||
|
PRAGMA foreign_keys= off;
|
||||||
|
|
||||||
|
-- rename old files table
|
||||||
|
ALTER TABLE files
|
||||||
|
RENAME TO _files_old;
|
||||||
|
-- rename metadata value (because of foreign key constraints)
|
||||||
|
ALTER TABLE file_metadata
|
||||||
|
RENAME TO _file_metadata_old;
|
||||||
|
|
||||||
|
-- create new files table
|
||||||
|
CREATE TABLE files
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
status INTEGER NOT NULL DEFAULT 10,
|
||||||
|
cd_id INTEGER NOT NULL REFERENCES content_descriptors (id),
|
||||||
|
mime_type VARCHAR(128) NOT NULL DEFAULT 'application/octet-stream'
|
||||||
|
);
|
||||||
|
-- add data from files table
|
||||||
|
INSERT INTO files
|
||||||
|
SELECT id, status, cd_id, mime_type
|
||||||
|
FROM _files_old;
|
||||||
|
|
||||||
|
-- create metadata table
|
||||||
|
CREATE TABLE file_metadata
|
||||||
|
(
|
||||||
|
file_id INTEGER PRIMARY KEY REFERENCES files (id),
|
||||||
|
size INTEGER NOT NULL,
|
||||||
|
name VARCHAR(128),
|
||||||
|
comment VARCHAR(1024),
|
||||||
|
import_time DATETIME NOT NULL,
|
||||||
|
creation_time DATETIME NOT NULL,
|
||||||
|
change_time DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- add back the old values
|
||||||
|
INSERT INTO file_metadata
|
||||||
|
SELECT *
|
||||||
|
FROM _file_metadata_old;
|
||||||
|
|
||||||
|
-- drop old tables
|
||||||
|
DROP TABLE _file_metadata_old;
|
||||||
|
DROP TABLE _files_old;
|
||||||
|
DROP TABLE storage_locations;
|
||||||
|
|
||||||
|
-- create indices on new tables
|
||||||
|
CREATE UNIQUE INDEX file_metadata_file_id_unique ON file_metadata (file_id);
|
||||||
|
CREATE INDEX files_content_descriptor ON files (cd_id);
|
||||||
|
|
||||||
|
PRAGMA foreign_keys= on;
|
@ -1,24 +0,0 @@
|
|||||||
use sea_orm::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
|
||||||
#[sea_orm(table_name = "storage_locations")]
|
|
||||||
pub struct Model {
|
|
||||||
#[sea_orm(primary_key)]
|
|
||||||
pub id: i64,
|
|
||||||
pub name: String,
|
|
||||||
pub path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
|
||||||
pub enum Relation {
|
|
||||||
#[sea_orm(has_many = "super::file::Entity")]
|
|
||||||
File,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::file::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::File.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -1,16 +0,0 @@
|
|||||||
pub mod tag_handle;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use mediarepo_core::error::RepoResult;
|
|
||||||
use sea_orm::DatabaseConnection;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait EntityHandle {
|
|
||||||
type Model;
|
|
||||||
|
|
||||||
/// Returns the ID that is stored in the handle
|
|
||||||
fn id(&self) -> i64;
|
|
||||||
|
|
||||||
/// Returns the model associated with the handle
|
|
||||||
async fn model(&self, db: DatabaseConnection) -> RepoResult<Self::Model>;
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
use crate::handles::EntityHandle;
|
|
||||||
use crate::tag::Tag;
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use mediarepo_core::error::{RepoDatabaseError, RepoResult};
|
|
||||||
use sea_orm::DatabaseConnection;
|
|
||||||
|
|
||||||
pub struct TagHandle(pub(crate) i64);
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl EntityHandle for TagHandle {
|
|
||||||
type Model = Tag;
|
|
||||||
|
|
||||||
fn id(&self) -> i64 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn model(&self, db: DatabaseConnection) -> RepoResult<Self::Model> {
|
|
||||||
let tag = Tag::by_id(db, self.0)
|
|
||||||
.await?
|
|
||||||
.ok_or_else(|| RepoDatabaseError::InvalidHandle(self.id()))?;
|
|
||||||
|
|
||||||
Ok(tag)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,8 @@
|
|||||||
pub mod content_descriptor;
|
pub mod content_descriptor;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod file_metadata;
|
pub mod file_metadata;
|
||||||
pub mod handles;
|
|
||||||
pub mod namespace;
|
pub mod namespace;
|
||||||
pub mod repo;
|
pub mod repo;
|
||||||
pub mod storage;
|
|
||||||
pub mod tag;
|
pub mod tag;
|
||||||
pub mod thumbnail;
|
pub mod thumbnail;
|
||||||
pub mod type_keys;
|
pub mod type_keys;
|
||||||
|
@ -1,211 +0,0 @@
|
|||||||
use crate::content_descriptor::ContentDescriptor;
|
|
||||||
use mediarepo_core::error::RepoResult;
|
|
||||||
use mediarepo_core::fs::file_hash_store::FileHashStore;
|
|
||||||
use mediarepo_database::entities::storage;
|
|
||||||
use mediarepo_database::entities::storage::ActiveModel as ActiveStorage;
|
|
||||||
use mediarepo_database::entities::storage::Model as StorageModel;
|
|
||||||
use sea_orm::prelude::*;
|
|
||||||
use sea_orm::{DatabaseConnection, NotSet, Set};
|
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use tokio::fs;
|
|
||||||
use tokio::io::{AsyncRead, BufReader};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Storage {
|
|
||||||
db: DatabaseConnection,
|
|
||||||
model: StorageModel,
|
|
||||||
store: FileHashStore,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Storage {
|
|
||||||
#[tracing::instrument(level = "trace")]
|
|
||||||
fn new(db: DatabaseConnection, model: StorageModel) -> Self {
|
|
||||||
let path = PathBuf::from(&model.path);
|
|
||||||
Self {
|
|
||||||
store: FileHashStore::new(path),
|
|
||||||
db,
|
|
||||||
model,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns all available storages
|
|
||||||
#[tracing::instrument(level = "debug", skip(db))]
|
|
||||||
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
|
|
||||||
#[tracing::instrument(level = "debug", skip(db))]
|
|
||||||
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? {
|
|
||||||
let storage = Self::new(db, model);
|
|
||||||
Ok(Some(storage))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the storage by name
|
|
||||||
#[tracing::instrument(level = "debug", skip(db))]
|
|
||||||
pub async fn by_name<S: AsRef<str> + Debug>(
|
|
||||||
db: DatabaseConnection,
|
|
||||||
name: S,
|
|
||||||
) -> RepoResult<Option<Self>> {
|
|
||||||
if let Some(model) = storage::Entity::find()
|
|
||||||
.filter(storage::Column::Name.eq(name.as_ref()))
|
|
||||||
.one(&db)
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
let storage = Self::new(db, model);
|
|
||||||
Ok(Some(storage))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the storage by path
|
|
||||||
#[tracing::instrument(level = "debug", skip(db))]
|
|
||||||
pub async fn by_path<S: ToString + Debug>(
|
|
||||||
db: DatabaseConnection,
|
|
||||||
path: S,
|
|
||||||
) -> RepoResult<Option<Self>> {
|
|
||||||
if let Some(model) = storage::Entity::find()
|
|
||||||
.filter(storage::Column::Path.eq(path.to_string()))
|
|
||||||
.one(&db)
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
let storage = Self::new(db, model);
|
|
||||||
Ok(Some(storage))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new active storage and also creates the associated directory
|
|
||||||
/// if it doesn't exist yet.
|
|
||||||
#[tracing::instrument(level = "debug", skip(db))]
|
|
||||||
pub async fn create<S1: ToString + Debug, S2: ToString + Debug>(
|
|
||||||
db: DatabaseConnection,
|
|
||||||
name: S1,
|
|
||||||
path: S2,
|
|
||||||
) -> RepoResult<Self> {
|
|
||||||
let path = path.to_string();
|
|
||||||
let name = name.to_string();
|
|
||||||
let path_buf = PathBuf::from(&path);
|
|
||||||
|
|
||||||
if !path_buf.exists() {
|
|
||||||
fs::create_dir(path_buf).await?;
|
|
||||||
}
|
|
||||||
let storage = ActiveStorage {
|
|
||||||
id: NotSet,
|
|
||||||
name: Set(name),
|
|
||||||
path: Set(path),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let model = storage.insert(&db).await?;
|
|
||||||
|
|
||||||
Ok(Self::new(db, model))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the unique identifier of this storage
|
|
||||||
pub fn id(&self) -> i64 {
|
|
||||||
self.model.id
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the name of the storage
|
|
||||||
pub fn name(&self) -> &String {
|
|
||||||
&self.model.name
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the path of the storage
|
|
||||||
pub fn path(&self) -> &String {
|
|
||||||
&self.model.path
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets a new name for the storage
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
|
||||||
pub async fn set_name<S: ToString + Debug>(&self, name: S) -> RepoResult<()> {
|
|
||||||
let mut active_storage: ActiveStorage = self.get_active_model();
|
|
||||||
active_storage.name = Set(name.to_string());
|
|
||||||
active_storage.update(&self.db).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets a new path for the storage. This will only update the database record
|
|
||||||
/// so if the physical part of the storage is already created it needs to be migrated first
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
|
||||||
pub async fn set_path<S: ToString + Debug>(&mut self, path: S) -> RepoResult<()> {
|
|
||||||
let mut active_storage: ActiveStorage = self.get_active_model();
|
|
||||||
active_storage.path = Set(path.to_string());
|
|
||||||
let storage = active_storage.update(&self.db).await?;
|
|
||||||
|
|
||||||
self.model = storage;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if the storage exists on the harddrive
|
|
||||||
pub fn exists(&self) -> bool {
|
|
||||||
let path = PathBuf::from(&self.path());
|
|
||||||
|
|
||||||
path.exists()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a thumbnail
|
|
||||||
#[tracing::instrument(level = "debug", skip(self, reader))]
|
|
||||||
pub async fn store_entry<R: AsyncRead + Unpin>(
|
|
||||||
&self,
|
|
||||||
reader: R,
|
|
||||||
) -> RepoResult<ContentDescriptor> {
|
|
||||||
let descriptor = self.store.add_file(reader, None).await?;
|
|
||||||
if let Some(hash) = ContentDescriptor::by_value(self.db.clone(), &descriptor).await? {
|
|
||||||
Ok(hash)
|
|
||||||
} else {
|
|
||||||
ContentDescriptor::add(self.db.clone(), descriptor).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Renames an entry
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
|
||||||
pub async fn rename_entry(
|
|
||||||
&self,
|
|
||||||
src_descriptor: &[u8],
|
|
||||||
dst_descriptor: &[u8],
|
|
||||||
) -> RepoResult<()> {
|
|
||||||
self.store.rename_file(src_descriptor, dst_descriptor).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the buf reader to the given hash
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
|
||||||
pub async fn get_file_reader(
|
|
||||||
&self,
|
|
||||||
descriptor: &[u8],
|
|
||||||
) -> RepoResult<BufReader<tokio::fs::File>> {
|
|
||||||
let (_ext, reader) = self.store.get_file(descriptor).await?;
|
|
||||||
|
|
||||||
Ok(reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the size of the storage
|
|
||||||
#[inline]
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
|
||||||
pub async fn get_size(&self) -> RepoResult<u64> {
|
|
||||||
self.store.get_size().await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the active model with only the ID filled so saves always perform an update
|
|
||||||
fn get_active_model(&self) -> ActiveStorage {
|
|
||||||
ActiveStorage {
|
|
||||||
id: Set(self.model.id),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
pub static SETTINGS_PATH: &str = "./repo.toml";
|
|
||||||
pub static DEFAULT_STORAGE_NAME: &str = "Main";
|
|
||||||
pub static DEFAULT_STORAGE_PATH: &str = "files";
|
|
||||||
pub static THUMBNAIL_STORAGE_NAME: &str = "Thumbnails";
|
|
||||||
pub static THUMBNAIL_STORAGE_PATH: &str = "./thumbnails";
|
|
Loading…
Reference in New Issue