Add repository connections

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent 69c7ab7ac8
commit 68ffdc323b

@ -1,9 +1,11 @@
use std::path::PathBuf;
use rmp_ipc::IPCBuilder;
use serde::{Serialize, Deserialize};
use crate::context::Context;
use crate::error::AppResult;
use crate::error::{AppError, AppResult};
use tokio::fs;
use crate::settings::save_settings;
use rmp_ipc::context::Context as IPCContext;
static REPO_CONFIG_FILE: &str = "repo.toml";
@ -25,7 +27,7 @@ pub struct RepoConfig {
pub async fn get_repositories(context: tauri::State<'_, Context>) -> AppResult<Vec<Repository>> {
let settings = context.settings.read().await;
Ok(settings.repositories.clone())
Ok(settings.repositories.values().cloned().collect())
}
#[tauri::command]
@ -43,17 +45,35 @@ pub async fn add_repository(name: String, path: String, context: tauri::State<'_
let mut repositories = Vec::new();
{
let mut settings = context.settings.write().await;
settings.repositories.push(repo);
settings.repositories.insert(repo.name.clone(), repo);
save_settings(&settings)?;
repositories.append(&mut settings.repositories.clone());
repositories.append(&mut settings.repositories.values().cloned().collect());
}
Ok(repositories)
}
#[tauri::command]
pub async fn select_repository(name: String, context: tauri::State<'_, Context>) -> AppResult<()> {
let settings = context.settings.read().await;
let repo = settings.repositories.get(&name).ok_or(AppError::new(format!("Repository '{}' not found", name)))?;
let ipc = connect(&repo.address).await?;
let mut ipc_ctx = context.ipc.write().await;
*ipc_ctx = Some(ipc);
Ok(())
}
async fn read_repo_config(path: PathBuf) -> AppResult<RepoConfig> {
let toml_str = fs::read_to_string(path).await?;
let config = toml::from_str(&toml_str)?;
Ok(config)
}
/// Connects to the IPC Server
async fn connect(address: &str) -> AppResult<IPCContext> {
let ctx = IPCBuilder::new().address(address).build_client().await?;
Ok(ctx)
}

@ -1,20 +1,20 @@
use std::sync::Arc;
use rmp_ipc::client::IPCClient;
use tokio::sync::RwLock;
use rmp_ipc::context::Context as IPCContext;
use crate::commands::repo::Repository;
use crate::settings::Settings;
#[derive(Clone)]
pub struct Context {
pub active_repository: Option<Repository>,
pub client: Option<Arc<IPCClient>>,
pub ipc: Arc<RwLock<Option<IPCContext>>>,
pub settings: Arc<RwLock<Settings>>
}
impl Context {
pub fn new(settings: Settings) -> Self {
Self {
client: None,
ipc: Arc::new(RwLock::new(None)),
active_repository: None,
settings: Arc::new(RwLock::new(settings))
}

@ -1,27 +1,50 @@
use std::io::Error;
use std::error::Error;
use std::fmt::{Display, Formatter};
use serde::Serialize;
pub type AppResult<T> = Result<T, AppError>;
#[derive(Debug, Serialize)]
pub enum AppError {
Msg(String)
pub struct AppError {
message: String
}
impl AppError {
pub fn new<S: ToString>(msg: S) -> Self {
Self {
message: msg.to_string()
}
}
}
impl Display for AppError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.message.fmt(f)
}
}
impl Error for AppError {}
impl From<std::io::Error> for AppError {
fn from(e: Error) -> Self {
Self::Msg(e.to_string())
fn from(e: std::io::Error) -> Self {
Self::new(e)
}
}
impl From<toml::de::Error> for AppError {
fn from(e: toml::de::Error) -> Self {
Self::Msg(format!("Failed to deserialize toml: {:?}", e))
Self::new(format!("Failed to deserialize toml: {:?}", e))
}
}
impl From<toml::ser::Error> for AppError {
fn from(e: toml::ser::Error) -> Self {
Self::Msg(format!("Failed to serialize to toml: {:?}", e))
Self::new(format!("Failed to serialize to toml: {:?}", e))
}
}
impl From<rmp_ipc::error::Error> for AppError {
fn from(e: rmp_ipc::error::Error) -> Self {
Self::new(format!("Daemon Error: {:?}", e))
}
}

@ -3,7 +3,7 @@
windows_subsystem = "windows"
)]
use crate::commands::repo::{get_repositories, add_repository};
use crate::commands::repo::{get_repositories, add_repository, select_repository};
use crate::context::Context;
use crate::settings::load_settings;
@ -18,7 +18,7 @@ fn main() {
tauri::Builder::default()
.manage(context)
.invoke_handler(tauri::generate_handler![get_repositories, add_repository])
.invoke_handler(tauri::generate_handler![get_repositories, add_repository, select_repository])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

@ -1,3 +1,4 @@
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use crate::commands::repo::Repository;
use crate::error::AppResult;
@ -9,7 +10,7 @@ static SETTINGS_FILE: &str = "settings.toml";
#[derive(Default, Serialize, Deserialize)]
pub struct Settings {
pub repositories: Vec<Repository>,
pub repositories: HashMap<String, Repository>,
}
fn get_settings_path() -> PathBuf {

@ -12,7 +12,8 @@
}
.warn {
color: mat.get-color-from-palette($warn-palette);
background-color: mat.get-color-from-palette($warn-palette);
color: white
}
}

@ -1,34 +1,42 @@
import { Component } from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {Router} from "@angular/router";
import {RepositoryService} from "./services/repository/repository.service";
import {DataloaderService} from "./services/dataloader/dataloader.service";
import {MatSnackBar} from "@angular/material/snack-bar";
import {ErrorBrokerService} from "./services/error-broker/error-broker.service";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
export class AppComponent implements OnInit{
title = 'mediarepo-ui';
constructor(
private router: Router,
private snackBar: MatSnackBar,
private errorBroker: ErrorBrokerService,
private dataloaderService: DataloaderService,
private repoService: RepositoryService
private repoService: RepositoryService,
) {
}
async ngOnInit() {
this.dataloaderService.loaderError.subscribe({
error: (err) => {
this.snackBar.open(err, undefined, {panelClass: "warn"})
}
})
this.errorBroker.errorCb = (err: { message: string }) => {
console.error(err);
this.showError(err)
};
await this.dataloaderService.loadData();
if (this.repoService.selectedRepository.getValue() == undefined) {
await this.router.navigate(["repositories"])
}
}
private showError(err: { message: string }) {
this.snackBar.open(err.message, undefined, {
panelClass: "warn",
duration: 2000,
});
}
}

@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
import {FormControl, FormGroup, Validators} from "@angular/forms";
import {RepositoryService} from "../../../services/repository/repository.service";
import {MatSnackBar} from "@angular/material/snack-bar";
import {ErrorBrokerService} from "../../../services/error-broker/error-broker.service";
@Component({
selector: 'app-repo-form',
@ -16,7 +17,7 @@ export class RepoFormComponent implements OnInit {
})
constructor(private repoService: RepositoryService, private snackBar: MatSnackBar) { }
constructor(private repoService: RepositoryService, private errorBroker: ErrorBrokerService) { }
ngOnInit(): void {
}
@ -26,9 +27,7 @@ export class RepoFormComponent implements OnInit {
try {
await this.repoService.addRepository(name, path);
} catch(err) {
this.snackBar.open(err.Msg, undefined, {
panelClass: "warn"
})
this.errorBroker.showError(err);
}
}
}

@ -2,6 +2,8 @@ import {Component, Input, OnInit} from '@angular/core';
import {Repository} from "../../../models/Repository";
import {RepositoryService} from "../../../services/repository/repository.service";
import {Router} from "@angular/router";
import {MatSnackBar} from "@angular/material/snack-bar";
import {ErrorBrokerService} from "../../../services/error-broker/error-broker.service";
@Component({
selector: 'app-repository-card',
@ -12,15 +14,19 @@ export class RepositoryCardComponent implements OnInit {
@Input() repository?: Repository;
constructor(private repoService: RepositoryService, private router: Router) {}
constructor(private repoService: RepositoryService, private router: Router, private errorBroker: ErrorBrokerService) {}
ngOnInit(): void {
}
async selectRepository() {
if (this.repository) {
this.repoService.setRepository(this.repository);
await this.router.navigate([""]);
try {
await this.repoService.setRepository(this.repository);
await this.router.navigate([""]);
} catch(err) {
this.errorBroker.showError(err);
}
}
}
}

@ -1,22 +1,20 @@
import { Injectable } from '@angular/core';
import {RepositoryService} from "../repository/repository.service";
import {BehaviorSubject} from "rxjs";
import {ErrorBrokerService} from "../error-broker/error-broker.service";
@Injectable({
providedIn: 'root'
})
export class DataloaderService {
loaderError = new BehaviorSubject(undefined);
constructor(private repositoryService: RepositoryService) { }
constructor(private erroBroker: ErrorBrokerService, private repositoryService: RepositoryService) { }
public async loadData() {
try {
await this.repositoryService.loadRepositories();
} catch (err) {
this.loaderError.error(err);
console.error(err);
this.erroBroker.showError(err);
}
}
}

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { ErrorBrokerService } from './error-broker.service';
describe('ErrorBrokerService', () => {
let service: ErrorBrokerService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ErrorBrokerService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

@ -0,0 +1,22 @@
import { Injectable } from '@angular/core';
import {BehaviorSubject} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class ErrorBrokerService {
errorCb: Function | undefined;
constructor() { }
showError(error: {message: String}) {
if (this.errorCb) {
if (!error.message) {
this.errorCb({message: error});
} else {
this.errorCb({...error});
}
}
}
}

@ -17,7 +17,8 @@ export class RepositoryService {
this.repositories.next(repos);
}
public setRepository(repo: Repository) {
public async setRepository(repo: Repository) {
await invoke("select_repository", {name: repo.name});
this.selectedRepository.next(repo);
}

Loading…
Cancel
Save