Add repository commands

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent 6912ad6f05
commit d7a9a1450f

@ -13,6 +13,7 @@ async-trait = {version = "0.1.51", optional=true}
rmp-ipc = {version = "0.7.2", optional=true} rmp-ipc = {version = "0.7.2", optional=true}
parking_lot = {version="0.11.2", optional=true} parking_lot = {version="0.11.2", optional=true}
serde_json = {version="1.0.68", optional=true} serde_json = {version="1.0.68", optional=true}
directories = {version="4.0.1", optional=true}
[dependencies.serde] [dependencies.serde]
version = "1.0.130" version = "1.0.130"
@ -31,7 +32,11 @@ features = []
[dependencies.tokio] [dependencies.tokio]
version = "1.12.0" version = "1.12.0"
optional = true optional = true
features = ["sync"] features = ["sync", "fs"]
[dependencies.toml]
version = "0.5.8"
optional = true
[features] [features]
tauri-plugin = ["client-api","tauri", "rmp-ipc", "parking_lot", "serde_json"] tauri-plugin = ["client-api","tauri", "rmp-ipc", "parking_lot", "serde_json"]

@ -1,16 +1,26 @@
use tauri::State; use tauri::State;
pub use file::*; pub use file::*;
pub use repo::*;
pub use tag::*;
use crate::tauri_plugin::state::{ApiState, BufferState, OnceBuffer}; use crate::tauri_plugin::state::{ApiState, AppState, BufferState, OnceBuffer};
pub mod file; pub mod file;
pub mod repo;
pub mod tag;
pub type ApiAccess<'a> = State<'a, ApiState>; pub type ApiAccess<'a> = State<'a, ApiState>;
pub type BufferAccess<'a> = State<'a, BufferState>; pub type BufferAccess<'a> = State<'a, BufferState>;
pub type AppAccess<'a> = State<'a, AppState>;
/// Adds a once-buffer to the buffer store /// Adds a once-buffer to the buffer store
fn add_once_buffer(buffer_state: BufferAccess, key: String, mime: String, buf: Vec<u8>) -> String { fn add_once_buffer(
buffer_state: BufferAccess<'_>,
key: String,
mime: String,
buf: Vec<u8>,
) -> String {
let uri = format!("once://{}", key); let uri = format!("once://{}", key);
let once_buffer = OnceBuffer::new(mime, buf); let once_buffer = OnceBuffer::new(mime, buf);
let mut once_buffers = buffer_state.buffer.lock(); let mut once_buffers = buffer_state.buffer.lock();

@ -0,0 +1,82 @@
use crate::client_api::ApiClient;
use crate::tauri_plugin::commands::{ApiAccess, AppAccess};
use crate::tauri_plugin::error::{PluginError, PluginResult};
use crate::tauri_plugin::settings::{save_settings, Repository};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use tokio::fs;
static REPO_CONFIG_FILE: &str = "repo.toml";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RepoConfig {
pub listen_address: String,
pub database_path: String,
pub default_file_store: String,
}
#[tauri::command]
pub async fn get_repositories(app_state: AppAccess<'_>) -> PluginResult<Vec<Repository>> {
let settings = app_state.settings.read().await;
Ok(settings.repositories.values().cloned().collect())
}
#[tauri::command]
pub async fn get_active_repository(app_state: AppAccess<'_>) -> PluginResult<Option<Repository>> {
let repo = app_state.active_repo.read().await;
Ok(repo.clone())
}
#[tauri::command]
pub async fn add_repository(
name: String,
path: String,
app_state: AppAccess<'_>,
) -> PluginResult<Vec<Repository>> {
let repo_path = path.clone();
let path = PathBuf::from(path);
let RepoConfig { listen_address, .. } = read_repo_config(path.join(REPO_CONFIG_FILE)).await?;
let repo = Repository {
name,
path: Some(repo_path),
address: listen_address,
};
let mut repositories = Vec::new();
{
let mut settings = app_state.settings.write().await;
settings.repositories.insert(repo.name.clone(), repo);
save_settings(&settings)?;
repositories.append(&mut settings.repositories.values().cloned().collect());
}
Ok(repositories)
}
#[tauri::command]
pub async fn select_repository(
name: String,
app_state: AppAccess<'_>,
api_state: ApiAccess<'_>,
) -> PluginResult<()> {
let settings = app_state.settings.read().await;
let repo = settings.repositories.get(&name).ok_or(PluginError::from(
format!("Repository '{}' not found", name).as_str(),
))?;
let client = ApiClient::connect(&repo.address).await?;
api_state.set_api(client).await;
let mut active_repo = app_state.active_repo.write().await;
*active_repo = Some(repo.clone());
Ok(())
}
async fn read_repo_config(path: PathBuf) -> PluginResult<RepoConfig> {
let toml_str = fs::read_to_string(path).await?;
let config = toml::from_str(&toml_str)?;
Ok(config)
}

@ -0,0 +1,14 @@
use crate::tauri_plugin::commands::ApiAccess;
use crate::tauri_plugin::error::PluginResult;
use crate::types::tags::TagResponse;
#[tauri::command]
pub async fn get_tags_for_file(
hash: String,
api_state: ApiAccess<'_>,
) -> PluginResult<Vec<TagResponse>> {
let api = api_state.api().await?;
let tags = api.tag.get_tags_for_file(hash).await?;
Ok(tags)
}

@ -1,13 +1,22 @@
use crate::client_api::error::ApiError; use crate::client_api::error::ApiError;
use serde::Serialize; use serde::Serialize;
use std::fmt::{Display, Formatter};
pub type PluginResult<T> = Result<T, PluginError>; pub type PluginResult<T> = Result<T, PluginError>;
#[derive(Clone, Serialize)] #[derive(Clone, Debug, Serialize)]
pub struct PluginError { pub struct PluginError {
message: String, message: String,
} }
impl Display for PluginError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.message.fmt(f)
}
}
impl std::error::Error for PluginError {}
impl From<&str> for PluginError { impl From<&str> for PluginError {
fn from(s: &str) -> Self { fn from(s: &str) -> Self {
Self { Self {
@ -23,3 +32,27 @@ impl From<ApiError> for PluginError {
} }
} }
} }
impl From<std::io::Error> for PluginError {
fn from(e: std::io::Error) -> Self {
Self {
message: e.to_string(),
}
}
}
impl From<toml::de::Error> for PluginError {
fn from(e: toml::de::Error) -> Self {
Self {
message: format!("Deserialization failed: {:?}", e),
}
}
}
impl From<toml::ser::Error> for PluginError {
fn from(e: toml::ser::Error) -> Self {
Self {
message: format!("Serialization failed: {:?}", e),
}
}
}

@ -3,11 +3,12 @@ use tauri::{AppHandle, Builder, Invoke, Manager, Runtime};
use state::ApiState; use state::ApiState;
use crate::tauri_plugin::state::BufferState; use crate::tauri_plugin::state::{AppState, BufferState};
mod commands; pub(crate) mod commands;
pub mod custom_schemes; pub mod custom_schemes;
pub mod error; pub mod error;
mod settings;
mod state; mod state;
use commands::*; use commands::*;
@ -30,7 +31,12 @@ impl<R: Runtime> MediarepoPlugin<R> {
find_files, find_files,
read_file_by_hash, read_file_by_hash,
get_file_thumbnails, get_file_thumbnails,
read_thumbnail read_thumbnail,
get_repositories,
get_tags_for_file,
get_active_repository,
add_repository,
select_repository
]), ]),
} }
} }
@ -52,6 +58,9 @@ impl<R: Runtime> Plugin<R> for MediarepoPlugin<R> {
let buffer_state = BufferState::default(); let buffer_state = BufferState::default();
app.manage(buffer_state); app.manage(buffer_state);
let repo_state = AppState::load()?;
app.manage(repo_state);
Ok(()) Ok(())
} }

@ -0,0 +1,54 @@
use crate::tauri_plugin::error::PluginResult;
use directories::ProjectDirs;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
static SETTINGS_FILE: &str = "settings.toml";
#[derive(Serialize, Deserialize, Clone)]
pub struct Repository {
pub(crate) name: String,
pub(crate) path: Option<String>,
pub(crate) address: String,
}
#[derive(Default, Serialize, Deserialize)]
pub struct Settings {
pub repositories: HashMap<String, Repository>,
}
fn get_settings_path() -> PathBuf {
let dirs = ProjectDirs::from("com", "trivernis", "mediarepo").unwrap();
let config_path = dirs.config_dir().to_path_buf();
config_path.join(SETTINGS_FILE)
}
/// Writes the settings to the file
pub fn save_settings(settings: &Settings) -> PluginResult<()> {
let settings_path = get_settings_path();
let settings_string = toml::to_string(&settings)?;
fs::write(&settings_path, &settings_string.into_bytes())?;
Ok(())
}
/// Loads the settings from the file
pub fn load_settings() -> PluginResult<Settings> {
let dirs = ProjectDirs::from("com", "trivernis", "mediarepo").unwrap();
let config_path = dirs.config_dir().to_path_buf();
if !config_path.exists() {
fs::create_dir_all(&config_path)?;
}
let settings_path = config_path.join(SETTINGS_FILE);
if !settings_path.exists() {
let settings = Settings::default();
save_settings(&settings)?;
}
let config_str = fs::read_to_string(settings_path)?;
let settings = toml::from_str(&config_str)?;
Ok(settings)
}

@ -7,6 +7,7 @@ use tauri::async_runtime::RwLock;
use crate::client_api::ApiClient; use crate::client_api::ApiClient;
use crate::tauri_plugin::error::{PluginError, PluginResult}; use crate::tauri_plugin::error::{PluginError, PluginResult};
use crate::tauri_plugin::settings::{load_settings, Repository, Settings};
pub struct ApiState { pub struct ApiState {
inner: Arc<RwLock<Option<ApiClient>>>, inner: Arc<RwLock<Option<ApiClient>>>,
@ -51,3 +52,21 @@ impl OnceBuffer {
pub struct BufferState { pub struct BufferState {
pub buffer: Arc<Mutex<HashMap<String, OnceBuffer>>>, pub buffer: Arc<Mutex<HashMap<String, OnceBuffer>>>,
} }
pub struct AppState {
pub active_repo: Arc<RwLock<Option<Repository>>>,
pub settings: Arc<RwLock<Settings>>,
}
impl AppState {
pub fn load() -> PluginResult<Self> {
let settings = load_settings()?;
let state = Self {
active_repo: Arc::new(RwLock::new(None)),
settings: Arc::new(RwLock::new(settings)),
};
Ok(state)
}
}

Loading…
Cancel
Save