mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
Split into multiple crates
This commit is contained in:
parent
d7fb996183
commit
5d06ec9faf
88 changed files with 501 additions and 528 deletions
52
Cargo.toml
52
Cargo.toml
|
|
@ -1,50 +1,2 @@
|
|||
[package]
|
||||
name = "musicus"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.33"
|
||||
async-trait = "0.1.42"
|
||||
diesel = { version = "1.4.5", features = ["sqlite"] }
|
||||
diesel_migrations = "1.4.0"
|
||||
discid = "0.4.4"
|
||||
fragile = "1.0.0"
|
||||
futures = "0.3.6"
|
||||
futures-channel = "0.3.5"
|
||||
gettext-rs = "0.5.0"
|
||||
gtk-macros = "0.2.0"
|
||||
gstreamer = "0.16.4"
|
||||
gstreamer-player = "0.16.3"
|
||||
isahc = "0.9.12"
|
||||
once_cell = "1.5.2"
|
||||
rand = "0.7.3"
|
||||
secret-service = "2.0.1"
|
||||
serde = { version = "1.0.117", features = ["derive"] }
|
||||
serde_json = "1.0.59"
|
||||
thiserror = "1.0.23"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
|
||||
[dependencies.gdk]
|
||||
git = "https://github.com/gtk-rs/gtk4-rs/"
|
||||
package = "gdk4"
|
||||
|
||||
[dependencies.gio]
|
||||
git = "https://github.com/gtk-rs/gtk-rs/"
|
||||
features = ["v2_64"]
|
||||
|
||||
[dependencies.glib]
|
||||
git = "https://github.com/gtk-rs/gtk-rs/"
|
||||
features = ["v2_64"]
|
||||
|
||||
[dependencies.gtk]
|
||||
git = "https://github.com/gtk-rs/gtk4-rs"
|
||||
package = "gtk4"
|
||||
|
||||
[dependencies.libadwaita]
|
||||
git = "https://gitlab.gnome.org/bilelmoussaoui/libadwaita-rs"
|
||||
package = "libadwaita"
|
||||
|
||||
[dependencies.pango]
|
||||
git = "https://github.com/gtk-rs/gtk-rs/"
|
||||
features = ["v1_44"]
|
||||
[workspace]
|
||||
members = ["crates/*"]
|
||||
|
|
|
|||
41
crates/musicus/Cargo.toml
Normal file
41
crates/musicus/Cargo.toml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
[package]
|
||||
name = "musicus"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.33"
|
||||
async-trait = "0.1.42"
|
||||
discid = "0.4.4"
|
||||
futures = "0.3.6"
|
||||
futures-channel = "0.3.5"
|
||||
gettext-rs = "0.5.0"
|
||||
gstreamer = "0.16.4"
|
||||
gtk-macros = "0.2.0"
|
||||
musicus_backend = { version = "0.1.0", path = "../musicus_backend" }
|
||||
once_cell = "1.5.2"
|
||||
rand = "0.7.3"
|
||||
|
||||
[dependencies.gdk]
|
||||
git = "https://github.com/gtk-rs/gtk4-rs/"
|
||||
package = "gdk4"
|
||||
|
||||
[dependencies.gio]
|
||||
git = "https://github.com/gtk-rs/gtk-rs/"
|
||||
features = ["v2_64"]
|
||||
|
||||
[dependencies.glib]
|
||||
git = "https://github.com/gtk-rs/gtk-rs/"
|
||||
features = ["v2_64"]
|
||||
|
||||
[dependencies.gtk]
|
||||
git = "https://github.com/gtk-rs/gtk4-rs"
|
||||
package = "gtk4"
|
||||
|
||||
[dependencies.libadwaita]
|
||||
git = "https://gitlab.gnome.org/bilelmoussaoui/libadwaita-rs"
|
||||
package = "libadwaita"
|
||||
|
||||
[dependencies.pango]
|
||||
git = "https://github.com/gtk-rs/gtk-rs/"
|
||||
features = ["v1_44"]
|
||||
2
crates/musicus/src/config.rs
Normal file
2
crates/musicus/src/config.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pub static VERSION: &str = "0.1.0";
|
||||
pub static LOCALEDIR: &str = "/app/share/locale";
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
use crate::backend::generate_id;
|
||||
use crate::backend::{Backend, Ensemble};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::{Editor, EntryRow, Section, UploadSection, Widget};
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::generate_id;
|
||||
use musicus_backend::Ensemble;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for creating or editing a ensemble.
|
||||
|
|
@ -92,7 +91,7 @@ impl EnsembleEditor {
|
|||
};
|
||||
|
||||
if self.upload.get_active() {
|
||||
self.handle.backend.post_ensemble(&ensemble).await?;
|
||||
self.handle.backend.cl().post_ensemble(&ensemble).await?;
|
||||
}
|
||||
|
||||
self.handle.backend.db().update_ensemble(ensemble.clone()).await?;
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
use crate::backend::generate_id;
|
||||
use crate::backend::{Backend, Instrument};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::{Editor, EntryRow, Section, UploadSection, Widget};
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::generate_id;
|
||||
use musicus_backend::Instrument;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for creating or editing a instrument.
|
||||
|
|
@ -92,7 +91,7 @@ impl InstrumentEditor {
|
|||
};
|
||||
|
||||
if self.upload.get_active() {
|
||||
self.handle.backend.post_instrument(&instrument).await?;
|
||||
self.handle.backend.cl().post_instrument(&instrument).await?;
|
||||
}
|
||||
|
||||
self.handle.backend.db().update_instrument(instrument.clone()).await?;
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::backend::{Backend, Performance, Person, Ensemble, Instrument};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::selectors::{EnsembleSelector, InstrumentSelector, PersonSelector};
|
||||
use crate::widgets::{Editor, Section, ButtonRow, Widget};
|
||||
|
|
@ -6,6 +5,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{Performance, Person, Ensemble, Instrument};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
use crate::backend::generate_id;
|
||||
use crate::backend::{Backend, Person};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::{Editor, EntryRow, Section, UploadSection, Widget};
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::generate_id;
|
||||
use musicus_backend::Person;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for creating or editing a person.
|
||||
|
|
@ -101,7 +100,7 @@ impl PersonEditor {
|
|||
};
|
||||
|
||||
if self.upload.get_active() {
|
||||
self.handle.backend.post_person(&person).await?;
|
||||
self.handle.backend.cl().post_person(&person).await?;
|
||||
}
|
||||
|
||||
self.handle.backend.db().update_person(person.clone()).await?;
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
use super::performance::PerformanceEditor;
|
||||
use crate::backend::generate_id;
|
||||
use crate::backend::{Backend, Performance, Person, Recording, Work};
|
||||
use crate::selectors::{PersonSelector, WorkSelector};
|
||||
use crate::selectors::WorkSelector;
|
||||
use crate::widgets::{List, Widget};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use anyhow::Result;
|
||||
|
|
@ -10,6 +8,8 @@ use glib::clone;
|
|||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::generate_id;
|
||||
use musicus_backend::{Performance, Recording, Work};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ impl RecordingEditor {
|
|||
|
||||
let upload = self.upload_switch.get_active();
|
||||
if upload {
|
||||
self.handle.backend.post_recording(&recording).await?;
|
||||
self.handle.backend.cl().post_recording(&recording).await?;
|
||||
}
|
||||
|
||||
self.handle.backend
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
use super::work_part::WorkPartEditor;
|
||||
use crate::backend::generate_id;
|
||||
use crate::backend::{Instrument, Person, Work, WorkPart, WorkSection};
|
||||
use super::work_section::WorkSectionEditor;
|
||||
use crate::selectors::{InstrumentSelector, PersonSelector};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
|
|
@ -11,6 +9,8 @@ use glib::clone;
|
|||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::generate_id;
|
||||
use musicus_backend::{Instrument, Person, Work, WorkPart, WorkSection};
|
||||
use std::cell::RefCell;
|
||||
use std::convert::TryInto;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -336,7 +336,7 @@ impl WorkEditor {
|
|||
|
||||
let upload = self.upload_switch.get_active();
|
||||
if upload {
|
||||
self.handle.backend.post_work(&work).await?;
|
||||
self.handle.backend.cl().post_work(&work).await?;
|
||||
}
|
||||
|
||||
self.handle.backend
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::backend::{Person, WorkPart};
|
||||
use crate::selectors::PersonSelector;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
|
|
@ -7,6 +6,7 @@ use glib::clone;
|
|||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{Person, WorkPart};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
use crate::backend::WorkSection;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::WorkSection;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for creating or editing a work section.
|
||||
|
|
@ -146,8 +146,8 @@ impl Source for DiscSource {
|
|||
|
||||
let (discid, tracks) = receiver.await??;
|
||||
|
||||
self.discid.set(discid);
|
||||
self.tracks.set(tracks);
|
||||
self.discid.set(discid).unwrap();
|
||||
self.tracks.set(tracks).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ impl Source for FolderSource {
|
|||
});
|
||||
|
||||
let tracks = receiver.await??;
|
||||
self.tracks.set(tracks);
|
||||
self.tracks.set(tracks).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
use super::source::Source;
|
||||
use super::track_set_editor::{TrackSetData, TrackSetEditor};
|
||||
use crate::backend::generate_id;
|
||||
use crate::backend::{Backend, Medium, Track, TrackSet};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::{List, Widget};
|
||||
use anyhow::{anyhow, Result};
|
||||
|
|
@ -10,6 +8,8 @@ use glib::prelude::*;
|
|||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::generate_id;
|
||||
use musicus_backend::{Medium, Track, TrackSet};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ impl MediumEditor {
|
|||
|
||||
let upload = self.publish_switch.get_active();
|
||||
if upload {
|
||||
self.handle.backend.post_medium(&medium).await?;
|
||||
self.handle.backend.cl().post_medium(&medium).await?;
|
||||
}
|
||||
|
||||
self.handle.backend
|
||||
|
|
@ -2,14 +2,12 @@ use super::medium_editor::MediumEditor;
|
|||
use super::disc_source::DiscSource;
|
||||
use super::folder_source::FolderSource;
|
||||
use super::source::Source;
|
||||
use crate::backend::Backend;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use std::cell::RefCell;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::backend::Recording;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::Recording;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
use super::source::Source;
|
||||
use super::track_editor::TrackEditor;
|
||||
use super::track_selector::TrackSelector;
|
||||
use crate::backend::{Backend, Recording};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::selectors::{PersonSelector, RecordingSelector};
|
||||
use crate::selectors::RecordingSelector;
|
||||
use crate::widgets::{List, Widget};
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::Recording;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,11 +1,3 @@
|
|||
// Required for database/schema.rs
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
|
||||
// Required for embed_migrations macro in database/database.rs
|
||||
#[macro_use]
|
||||
extern crate diesel_migrations;
|
||||
|
||||
use gio::prelude::*;
|
||||
use glib::clone;
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -14,7 +6,6 @@ use std::rc::Rc;
|
|||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod backend;
|
||||
mod config;
|
||||
mod editors;
|
||||
mod import;
|
||||
59
crates/musicus/src/meson.build
Normal file
59
crates/musicus/src/meson.build
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
prefix = get_option('prefix')
|
||||
localedir = join_paths(prefix, get_option('localedir'))
|
||||
|
||||
global_conf = configuration_data()
|
||||
global_conf.set_quoted('LOCALEDIR', localedir)
|
||||
global_conf.set_quoted('VERSION', meson.project_version())
|
||||
config_rs = configure_file(
|
||||
input: 'config.rs.in',
|
||||
output: 'config.rs',
|
||||
configuration: global_conf
|
||||
)
|
||||
|
||||
run_command(
|
||||
'cp',
|
||||
config_rs,
|
||||
meson.current_source_dir(),
|
||||
check: true
|
||||
)
|
||||
|
||||
resource_conf = configuration_data()
|
||||
resource_conf.set_quoted('RESOURCEFILE', resources.full_path())
|
||||
resource_rs = configure_file(
|
||||
input: 'resources.rs.in',
|
||||
output: 'resources.rs',
|
||||
configuration: resource_conf
|
||||
)
|
||||
|
||||
run_command(
|
||||
'cp',
|
||||
resource_rs,
|
||||
meson.current_source_dir(),
|
||||
check: true
|
||||
)
|
||||
|
||||
sources = files(
|
||||
'config.rs',
|
||||
'resources.rs',
|
||||
)
|
||||
|
||||
cargo_script = find_program(join_paths(meson.source_root(), 'build-aux/cargo.sh'))
|
||||
cargo_release = custom_target(
|
||||
'cargo-build',
|
||||
build_by_default: true,
|
||||
input: sources,
|
||||
build_always_stale: true,
|
||||
depends: resources,
|
||||
output: meson.project_name(),
|
||||
console: true,
|
||||
install: true,
|
||||
install_dir: get_option('bindir'),
|
||||
command: [
|
||||
cargo_script,
|
||||
meson.build_root(),
|
||||
meson.source_root(),
|
||||
'@OUTPUT@',
|
||||
get_option('buildtype'),
|
||||
meson.project_name(),
|
||||
]
|
||||
)
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::backend::Backend;
|
||||
use crate::widgets::Widget;
|
||||
use futures_channel::oneshot;
|
||||
use futures_channel::oneshot::{Receiver, Sender};
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use musicus_backend::Backend;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::backend::Backend;
|
||||
use super::{Navigator, Screen};
|
||||
use super::Navigator;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use musicus_backend::Backend;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A window hosting a navigator.
|
||||
|
|
@ -35,9 +35,4 @@ impl NavigatorWindow {
|
|||
self.window.set_modal(true);
|
||||
self.window.set_transient_for(Some(window));
|
||||
}
|
||||
|
||||
/// Show the navigator window.
|
||||
pub fn show(&self) {
|
||||
self.window.show();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
use super::register::RegisterDialog;
|
||||
use crate::push;
|
||||
use crate::backend::{Backend, LoginData};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::LoginData;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for entering login credentials.
|
||||
|
|
@ -55,7 +54,7 @@ impl Screen<(), LoginData> for LoginDialog {
|
|||
|
||||
spawn!(@clone this, async move {
|
||||
this.handle.backend.set_login_data(data.clone()).await.unwrap();
|
||||
if this.handle.backend.login().await.unwrap() {
|
||||
if this.handle.backend.cl().login().await.unwrap() {
|
||||
this.handle.pop(Some(data));
|
||||
} else {
|
||||
this.widget.set_visible_child_name("content");
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::backend::Backend;
|
||||
use crate::navigator::NavigatorWindow;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::Backend;
|
||||
use libadwaita::prelude::*;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::backend::{Backend, LoginData, UserRegistration};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{LoginData, UserRegistration};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ impl Screen<(), LoginData> for RegisterDialog {
|
|||
};
|
||||
|
||||
// TODO: Handle errors.
|
||||
if this.handle.backend.register(registration).await.unwrap() {
|
||||
if this.handle.backend.cl().register(registration).await.unwrap() {
|
||||
let data = LoginData {
|
||||
username,
|
||||
password,
|
||||
|
|
@ -102,7 +102,7 @@ impl Screen<(), LoginData> for RegisterDialog {
|
|||
// Initialize
|
||||
|
||||
spawn!(@clone this, async move {
|
||||
let captcha = this.handle.backend.get_captcha().await.unwrap();
|
||||
let captcha = this.handle.backend.cl().get_captcha().await.unwrap();
|
||||
this.captcha_row.set_title(Some(&captcha.question));
|
||||
this.captcha_id.replace(Some(captcha.id));
|
||||
this.widget.set_visible_child_name("content");
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::backend::Backend;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::Backend;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
9
crates/musicus/src/resources.rs
Normal file
9
crates/musicus/src/resources.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
use anyhow::Result;
|
||||
|
||||
pub fn init() -> Result<()> {
|
||||
let bytes = glib::Bytes::from(include_bytes!("/home/johrpan/.var/app/org.gnome.Builder/cache/gnome-builder/projects/musicus/builds/de.johrpan.musicus.json-flatpak-org.gnome.Platform-x86_64-master-error-handling/res/musicus.gresource").as_ref());
|
||||
let resource = gio::Resource::from_data(&bytes)?;
|
||||
gio::resources_register(&resource);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::RecordingScreen;
|
||||
use crate::backend::{Backend, Ensemble, Recording};
|
||||
use crate::editors::EnsembleEditor;
|
||||
use crate::navigator::{NavigatorWindow, NavigationHandle, Screen};
|
||||
use crate::widgets;
|
||||
|
|
@ -8,6 +7,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{Ensemble, Recording};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::{WorkScreen, RecordingScreen};
|
||||
use crate::backend::{Backend, Person, Recording, Work};
|
||||
use crate::editors::PersonEditor;
|
||||
use crate::navigator::{NavigatorWindow, NavigationHandle, Screen};
|
||||
use crate::widgets;
|
||||
|
|
@ -8,6 +7,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{Person, Recording, Work};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::backend::{Player, PlaylistItem};
|
||||
use crate::widgets::*;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{Player, PlaylistItem};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::backend::{Backend, PlaylistItem, Recording, TrackSet};
|
||||
use crate::editors::RecordingEditor;
|
||||
use crate::navigator::{NavigatorWindow, NavigationHandle, Screen};
|
||||
use crate::widgets;
|
||||
|
|
@ -7,6 +6,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{PlaylistItem, Recording, TrackSet};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::RecordingScreen;
|
||||
use crate::backend::{Backend, Work, Recording};
|
||||
use crate::editors::WorkEditor;
|
||||
use crate::navigator::{NavigatorWindow, NavigationHandle, Screen};
|
||||
use crate::widgets;
|
||||
|
|
@ -8,6 +7,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{Work, Recording};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::selector::Selector;
|
||||
use crate::backend::{Backend, Ensemble};
|
||||
use crate::editors::EnsembleEditor;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
|
|
@ -7,7 +6,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::Ensemble;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A screen for selecting a ensemble.
|
||||
|
|
@ -45,7 +44,7 @@ impl Screen<(), Ensemble> for EnsembleSelector {
|
|||
|
||||
this.selector.set_load_online(clone!(@weak this => move || {
|
||||
let clone = this.clone();
|
||||
async move { clone.handle.backend.get_ensembles().await }
|
||||
async move { Ok(clone.handle.backend.cl().get_ensembles().await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => move || {
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::selector::Selector;
|
||||
use crate::backend::{Backend, Instrument};
|
||||
use crate::editors::InstrumentEditor;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
|
|
@ -7,7 +6,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::Instrument;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A screen for selecting a instrument.
|
||||
|
|
@ -45,7 +44,7 @@ impl Screen<(), Instrument> for InstrumentSelector {
|
|||
|
||||
this.selector.set_load_online(clone!(@weak this => move || {
|
||||
let clone = this.clone();
|
||||
async move { clone.handle.backend.get_instruments().await }
|
||||
async move { Ok(clone.handle.backend.cl().get_instruments().await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => move || {
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::selector::Selector;
|
||||
use crate::backend::{Backend, Person};
|
||||
use crate::editors::PersonEditor;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
|
|
@ -7,7 +6,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::Person;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A screen for selecting a person.
|
||||
|
|
@ -45,7 +44,7 @@ impl Screen<(), Person> for PersonSelector {
|
|||
|
||||
this.selector.set_load_online(clone!(@weak this => move || {
|
||||
let clone = this.clone();
|
||||
async move { clone.handle.backend.get_persons().await }
|
||||
async move { Ok(clone.handle.backend.cl().get_persons().await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => move || {
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::selector::Selector;
|
||||
use crate::backend::{Backend, Person, Work, Recording};
|
||||
use crate::editors::{PersonEditor, WorkEditor, RecordingEditor};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
|
|
@ -7,7 +6,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::{Person, Work, Recording};
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A screen for selecting a recording.
|
||||
|
|
@ -56,7 +55,7 @@ impl Screen<(), Recording> for RecordingSelector {
|
|||
}));
|
||||
|
||||
this.selector.set_load_online(clone!(@weak this => move || {
|
||||
async move { this.handle.backend.get_persons().await }
|
||||
async move { Ok(this.handle.backend.cl().get_persons().await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => move || {
|
||||
|
|
@ -134,7 +133,7 @@ impl Screen<Person, Work> for RecordingSelectorWorkScreen {
|
|||
}));
|
||||
|
||||
this.selector.set_load_online(clone!(@weak this => move || {
|
||||
async move { this.handle.backend.get_works(&this.person.id).await }
|
||||
async move { Ok(this.handle.backend.cl().get_works(&this.person.id).await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => move || {
|
||||
|
|
@ -199,7 +198,7 @@ impl Screen<Work, Recording> for RecordingSelectorRecordingScreen {
|
|||
}));
|
||||
|
||||
this.selector.set_load_online(clone!(@weak this => move || {
|
||||
async move { this.handle.backend.get_recordings_for_work(&this.work.id).await }
|
||||
async move { Ok(this.handle.backend.cl().get_recordings_for_work(&this.work.id).await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => move || {
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use crate::backend::Result;
|
||||
use crate::widgets::List;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::Result;
|
||||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::selector::Selector;
|
||||
use crate::backend::{Backend, Person, Work};
|
||||
use crate::editors::{PersonEditor, WorkEditor};
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
|
|
@ -7,7 +6,7 @@ use gettextrs::gettext;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use musicus_backend::{Person, Work};
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A screen for selecting a work.
|
||||
|
|
@ -50,7 +49,7 @@ impl Screen<(), Work> for WorkSelector {
|
|||
}));
|
||||
|
||||
this.selector.set_load_online(clone!(@weak this => move || {
|
||||
async move { this.handle.backend.get_persons().await }
|
||||
async move { Ok(this.handle.backend.cl().get_persons().await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => move || {
|
||||
|
|
@ -124,7 +123,7 @@ impl Screen<Person, Work> for WorkSelectorWorkScreen {
|
|||
}));
|
||||
|
||||
this.selector.set_load_online(clone!(@weak this => move || {
|
||||
async move { this.handle.backend.get_works(&this.person.id).await }
|
||||
async move { Ok(this.handle.backend.cl().get_works(&this.person.id).await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => move || {
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use super::Widget;
|
||||
use gio::prelude::*;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
|
|
@ -68,7 +68,7 @@ mod indexed_list_model {
|
|||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
fn set_property(&self, _obj: &Self::Type, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.get_name() {
|
||||
"length" => {
|
||||
let length = value.get().unwrap().unwrap();
|
||||
|
|
@ -78,7 +78,7 @@ mod indexed_list_model {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_property(&self, _obj: &Self::Type, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.get_name() {
|
||||
"length" => self.length.get().to_value(),
|
||||
_ => unimplemented!(),
|
||||
|
|
@ -160,7 +160,7 @@ mod item_index {
|
|||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
fn set_property(&self, _obj: &Self::Type, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.get_name() {
|
||||
"value" => {
|
||||
let value = value.get().unwrap().unwrap();
|
||||
|
|
@ -170,7 +170,7 @@ mod item_index {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_property(&self, _obj: &Self::Type, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.get_name() {
|
||||
"value" => self.value.get().to_value(),
|
||||
_ => unimplemented!(),
|
||||
|
|
@ -119,14 +119,6 @@ impl List {
|
|||
self.widget.set_selection_mode(gtk::SelectionMode::Single);
|
||||
}
|
||||
|
||||
/// Select an item by its index. If the index is out of range, nothing will happen.
|
||||
pub fn select(&self, index: usize) {
|
||||
let row = self.widget.get_row_at_index(index as i32);
|
||||
if let Some(row) = row {
|
||||
self.widget.select_row(Some(&row));
|
||||
}
|
||||
}
|
||||
|
||||
/// Refilter the list based on the filter callback.
|
||||
pub fn invalidate_filter(&self) {
|
||||
self.filter.changed(gtk::FilterChange::Different);
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::backend::{Player, PlaylistItem};
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::{Player, PlaylistItem};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
use super::*;
|
||||
use crate::backend::{Backend, Person, Ensemble};
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use libadwaita::prelude::*;
|
||||
use musicus_backend::{Backend, Person, Ensemble};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
use super::Section;
|
||||
|
||||
use gettextrs::gettext;
|
||||
use gtk::prelude::*;
|
||||
use libadwaita::prelude::*;
|
||||
|
||||
/// A section showing a switch to enable uploading an item.
|
||||
|
|
@ -9,9 +8,6 @@ pub struct UploadSection {
|
|||
/// The GTK widget of the wrapped section.
|
||||
pub widget: gtk::Box,
|
||||
|
||||
/// The section itself.
|
||||
section: Section,
|
||||
|
||||
/// The upload switch.
|
||||
switch: gtk::Switch,
|
||||
}
|
||||
|
|
@ -41,7 +37,6 @@ impl UploadSection {
|
|||
|
||||
Self {
|
||||
widget: section.widget.clone(),
|
||||
section,
|
||||
switch,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::backend::*;
|
||||
use crate::config;
|
||||
use crate::import::SourceSelector;
|
||||
use crate::preferences::Preferences;
|
||||
|
|
@ -11,6 +10,7 @@ use gio::prelude::*;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::{action, get_widget};
|
||||
use musicus_backend::{Backend, BackendState};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Window {
|
||||
|
|
@ -202,12 +202,6 @@ impl Window {
|
|||
self.window.present();
|
||||
}
|
||||
|
||||
fn reload(&self) {
|
||||
self.poe_list.clone().reload();
|
||||
self.navigator.reset();
|
||||
self.leaflet.set_visible_child(&self.sidebar_box);
|
||||
}
|
||||
|
||||
fn show_about_dialog(&self) {
|
||||
let dialog = gtk::AboutDialogBuilder::new()
|
||||
.transient_for(&self.window)
|
||||
17
crates/musicus_backend/Cargo.toml
Normal file
17
crates/musicus_backend/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "musicus_backend"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
fragile = "1.0.0"
|
||||
futures-channel = "0.3.5"
|
||||
gio = "0.9.1"
|
||||
glib = "0.10.3"
|
||||
gstreamer = "0.16.4"
|
||||
gstreamer-player = "0.16.3"
|
||||
musicus_client = { version = "0.1.0", path = "../musicus_client" }
|
||||
musicus_database = { version = "0.1.0", path = "../musicus_database" }
|
||||
secret-service = "2.0.1"
|
||||
thiserror = "1.0.23"
|
||||
|
||||
28
crates/musicus_backend/src/error.rs
Normal file
28
crates/musicus_backend/src/error.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/// An error that can happened within the backend.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
ClientError(#[from] musicus_client::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
DatabaseError(#[from] musicus_database::Error),
|
||||
|
||||
#[error("An error happened using the SecretService.")]
|
||||
SecretServiceError(#[from] secret_service::Error),
|
||||
|
||||
#[error("An error happened in GLib.")]
|
||||
GlibError(#[from] glib::BoolError),
|
||||
|
||||
#[error("A channel was canceled.")]
|
||||
ChannelError(#[from] futures_channel::oneshot::Canceled),
|
||||
|
||||
#[error("An error happened while decoding to UTF-8.")]
|
||||
Utf8Error(#[from] std::str::Utf8Error),
|
||||
|
||||
#[error("An error happened: {0}")]
|
||||
Other(&'static str),
|
||||
}
|
||||
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
|
|
@ -1,17 +1,18 @@
|
|||
use futures_channel::mpsc;
|
||||
use gio::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub mod client;
|
||||
pub use client::*;
|
||||
|
||||
pub mod database;
|
||||
pub use database::*;
|
||||
pub use musicus_client::*;
|
||||
pub use musicus_database::*;
|
||||
|
||||
pub mod error;
|
||||
pub use error::*;
|
||||
|
||||
// Override the identically named types from the other crates.
|
||||
pub use error::{Error, Result};
|
||||
|
||||
pub mod library;
|
||||
pub use library::*;
|
||||
|
||||
|
|
@ -43,9 +44,7 @@ pub struct Backend {
|
|||
music_library_path: RefCell<Option<PathBuf>>,
|
||||
database: RefCell<Option<Rc<DbThread>>>,
|
||||
player: RefCell<Option<Rc<Player>>>,
|
||||
server_url: RefCell<Option<String>>,
|
||||
login_data: RefCell<Option<LoginData>>,
|
||||
token: RefCell<Option<String>>,
|
||||
client: Client,
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
|
|
@ -61,20 +60,55 @@ impl Backend {
|
|||
music_library_path: RefCell::new(None),
|
||||
database: RefCell::new(None),
|
||||
player: RefCell::new(None),
|
||||
server_url: RefCell::new(None),
|
||||
login_data: RefCell::new(None),
|
||||
token: RefCell::new(None),
|
||||
client: Client::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the backend updating the state accordingly.
|
||||
pub async fn init(self: Rc<Backend>) -> Result<()> {
|
||||
self.init_library().await?;
|
||||
self.init_client()?;
|
||||
|
||||
if let Some(url) = self.settings.get_string("server-url") {
|
||||
if !url.is_empty() {
|
||||
self.client.set_server_url(&url);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(data) = secure::load_login_data()? {
|
||||
self.client.set_login_data(data);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the URL of the Musicus server to connect to.
|
||||
pub fn set_server_url(&self, url: &str) -> Result<()> {
|
||||
self.settings.set_string("server-url", url)?;
|
||||
self.client.set_server_url(url);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the currently set server URL.
|
||||
pub fn get_server_url(&self) -> Option<String> {
|
||||
self.client.get_server_url()
|
||||
}
|
||||
|
||||
/// Set the user credentials to use.
|
||||
pub async fn set_login_data(&self, data: LoginData) -> Result<()> {
|
||||
secure::store_login_data(data.clone()).await?;
|
||||
self.client.set_login_data(data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cl(&self) -> &Client {
|
||||
&self.client
|
||||
}
|
||||
|
||||
/// Get the currently stored login credentials.
|
||||
pub fn get_login_data(&self) -> Option<LoginData> {
|
||||
self.client.get_login_data()
|
||||
}
|
||||
|
||||
/// Set the current state and notify the user interface.
|
||||
fn set_state(&self, state: BackendState) {
|
||||
self.state_sender.borrow_mut().try_send(state).unwrap();
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::backend::{Backend, BackendState, DbThread, Player, Result};
|
||||
use crate::{Backend, BackendState, Player, Result};
|
||||
use musicus_database::DbThread;
|
||||
use gio::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::backend::{Error, Result, TrackSet};
|
||||
use crate::{Error, Result};
|
||||
use musicus_database::TrackSet;
|
||||
use gstreamer_player::prelude::*;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::backend::{LoginData, Result};
|
||||
use crate::Result;
|
||||
use musicus_client::LoginData;
|
||||
use futures_channel::oneshot;
|
||||
use secret_service::{Collection, EncryptionType, SecretService};
|
||||
use std::collections::HashMap;
|
||||
11
crates/musicus_client/Cargo.toml
Normal file
11
crates/musicus_client/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "musicus_client"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
isahc = "0.9.12"
|
||||
musicus_database = { version = "0.1.0", path = "../musicus_database" }
|
||||
serde = { version = "1.0.117", features = ["derive"] }
|
||||
serde_json = "1.0.59"
|
||||
thiserror = "1.0.23"
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::backend::{Backend, Ensemble, Result};
|
||||
use crate::{Client, Result};
|
||||
use musicus_database::Ensemble;
|
||||
|
||||
impl Backend {
|
||||
impl Client {
|
||||
/// Get all available ensembles from the server.
|
||||
pub async fn get_ensembles(&self) -> Result<Vec<Ensemble>> {
|
||||
let body = self.get("ensembles").await?;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use isahc::http::StatusCode;
|
||||
|
||||
/// An error that can happen within the backend.
|
||||
/// An error within the client.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("The users login credentials were wrong.")]
|
||||
|
|
@ -21,33 +21,14 @@ pub enum Error {
|
|||
#[error("A networking error happened.")]
|
||||
HttpError(#[from] isahc::http::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
DatabaseError(#[from] crate::backend::DatabaseError),
|
||||
#[error("An error happened when serializing/deserializing.")]
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
|
||||
#[error("An IO error happened.")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("An error happened using the SecretService.")]
|
||||
SecretServiceError(#[from] secret_service::Error),
|
||||
|
||||
#[error("An error happened while serializing or deserializing.")]
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
|
||||
#[error("An error happened in GLib.")]
|
||||
GlibError(#[from] glib::BoolError),
|
||||
|
||||
#[error("A channel was canceled.")]
|
||||
ChannelError(#[from] futures_channel::oneshot::Canceled),
|
||||
|
||||
#[error("Error decoding to UTF8.")]
|
||||
Utf8Error(#[from] std::str::Utf8Error),
|
||||
|
||||
#[error("An error happened: {0}")]
|
||||
Other(&'static str),
|
||||
|
||||
// TODO: Remove this once anyhow has been dropped as a dependency.
|
||||
#[error("An unkown error happened.")]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::backend::{Backend, Instrument, Result};
|
||||
use crate::{Client, Result};
|
||||
use musicus_database::Instrument;
|
||||
|
||||
impl Backend {
|
||||
impl Client {
|
||||
/// Get all available instruments from the server.
|
||||
pub async fn get_instruments(&self) -> Result<Vec<Instrument>> {
|
||||
let body = self.get("instruments").await?;
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
use crate::backend::{Backend, Error, Result, secure};
|
||||
use gio::prelude::*;
|
||||
use isahc::http::StatusCode;
|
||||
use isahc::prelude::*;
|
||||
use serde::Serialize;
|
||||
use std::time::Duration;
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub mod ensembles;
|
||||
pub use ensembles::*;
|
||||
|
||||
pub mod error;
|
||||
pub use error::*;
|
||||
|
||||
pub mod instruments;
|
||||
pub use instruments::*;
|
||||
|
||||
|
|
@ -34,37 +36,26 @@ pub struct LoginData {
|
|||
pub password: String,
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
/// Initialize the client.
|
||||
pub(super) fn init_client(&self) -> Result<()> {
|
||||
if let Some(data) = secure::load_login_data()? {
|
||||
self.login_data.replace(Some(data));
|
||||
/// A client for accessing the Wolfgang API.
|
||||
pub struct Client {
|
||||
server_url: RefCell<Option<String>>,
|
||||
login_data: RefCell<Option<LoginData>>,
|
||||
token: RefCell<Option<String>>,
|
||||
}
|
||||
|
||||
if let Some(url) = self.settings.get_string("server-url") {
|
||||
if !url.is_empty() {
|
||||
self.server_url.replace(Some(url.to_string()));
|
||||
impl Client {
|
||||
/// Create a new client.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
server_url: RefCell::new(None),
|
||||
login_data: RefCell::new(None),
|
||||
token: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the URL of the Musicus server to connect to.
|
||||
pub fn set_server_url(&self, url: &str) -> Result<()> {
|
||||
self.settings.set_string("server-url", url)?;
|
||||
self.server_url.replace(Some(url.to_string()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the currently used login token.
|
||||
pub fn get_token(&self) -> Option<String> {
|
||||
self.token.borrow().clone()
|
||||
}
|
||||
|
||||
/// Set the login token to use. This will be done automatically by the login method.
|
||||
pub fn set_token(&self, token: &str) {
|
||||
self.token.replace(Some(token.to_string()));
|
||||
pub fn set_server_url(&self, url: &str) {
|
||||
self.server_url.replace(Some(url.to_owned()));
|
||||
}
|
||||
|
||||
/// Get the currently set server URL.
|
||||
|
|
@ -72,9 +63,10 @@ impl Backend {
|
|||
self.server_url.borrow().clone()
|
||||
}
|
||||
|
||||
/// Require the server URL to be set.
|
||||
fn server_url(&self) -> Result<String> {
|
||||
self.get_server_url().ok_or(Error::Other("The server URL is not available!"))
|
||||
/// Set the user credentials to use.
|
||||
pub fn set_login_data(&self, data: LoginData) {
|
||||
self.login_data.replace(Some(data));
|
||||
self.token.replace(None);
|
||||
}
|
||||
|
||||
/// Get the currently stored login credentials.
|
||||
|
|
@ -82,18 +74,6 @@ impl Backend {
|
|||
self.login_data.borrow().clone()
|
||||
}
|
||||
|
||||
fn login_data(&self) -> Result<LoginData> {
|
||||
self.get_login_data().ok_or(Error::Other("The login data is unset!"))
|
||||
}
|
||||
|
||||
/// Set the user credentials to use.
|
||||
pub async fn set_login_data(&self, data: LoginData) -> Result<()> {
|
||||
secure::store_login_data(data.clone()).await?;
|
||||
self.login_data.replace(Some(data));
|
||||
self.token.replace(None);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Try to login a user with the provided credentials and return, wether the login suceeded.
|
||||
pub async fn login(&self) -> Result<bool> {
|
||||
let server_url = self.server_url()?;
|
||||
|
|
@ -109,7 +89,7 @@ impl Backend {
|
|||
let success = match response.status() {
|
||||
StatusCode::OK => {
|
||||
let token = response.text_async().await?;
|
||||
self.set_token(&token);
|
||||
self.token.replace(Some(token));
|
||||
true
|
||||
}
|
||||
StatusCode::UNAUTHORIZED => false,
|
||||
|
|
@ -136,8 +116,7 @@ impl Backend {
|
|||
|
||||
/// Make an authenticated post request to the server.
|
||||
async fn post(&self, url: &str, body: String) -> Result<String> {
|
||||
let body = match self.get_token() {
|
||||
Some(_) => {
|
||||
let body = if self.token.borrow().is_some() {
|
||||
let mut response = self.post_priv(url, body.clone()).await?;
|
||||
|
||||
// Try one more time (maybe the token was expired)
|
||||
|
|
@ -150,8 +129,7 @@ impl Backend {
|
|||
}
|
||||
|
||||
response.text_async().await?
|
||||
}
|
||||
None => {
|
||||
} else {
|
||||
let mut response = if self.login().await? {
|
||||
self.post_priv(url, body).await?
|
||||
} else {
|
||||
|
|
@ -159,7 +137,6 @@ impl Backend {
|
|||
};
|
||||
|
||||
response.text_async().await?
|
||||
}
|
||||
};
|
||||
|
||||
Ok(body)
|
||||
|
|
@ -168,7 +145,7 @@ impl Backend {
|
|||
/// Post something to the server assuming there is a valid login token.
|
||||
async fn post_priv(&self, url: &str, body: String) -> Result<Response<Body>> {
|
||||
let server_url = self.server_url()?;
|
||||
let token = self.get_token().ok_or(Error::Other("No login token found!"))?;
|
||||
let token = self.token()?;
|
||||
|
||||
let response = Request::post(format!("{}/{}", server_url, url))
|
||||
.timeout(Duration::from_secs(10))
|
||||
|
|
@ -180,4 +157,19 @@ impl Backend {
|
|||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
/// Require the server URL to be set.
|
||||
fn server_url(&self) -> Result<String> {
|
||||
self.get_server_url().ok_or(Error::Other("The server URL is not available!"))
|
||||
}
|
||||
|
||||
/// Require the login data to be set.
|
||||
fn login_data(&self) -> Result<LoginData> {
|
||||
self.get_login_data().ok_or(Error::Other("The login data is unset!"))
|
||||
}
|
||||
|
||||
/// Require a login token to be set.
|
||||
fn token(&self) -> Result<String> {
|
||||
self.token.borrow().clone().ok_or(Error::Other("No login token found!"))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::backend::{Backend, Medium, Result};
|
||||
use crate::{Client, Result};
|
||||
use musicus_database::Medium;
|
||||
|
||||
impl Backend {
|
||||
impl Client {
|
||||
/// Get all available mediums from the server, that contain the specified
|
||||
/// recording.
|
||||
pub async fn get_mediums_for_recording(&self, recording_id: &str) -> Result<Vec<Medium>> {
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::backend::{Backend, Person, Result};
|
||||
use crate::{Client, Result};
|
||||
use musicus_database::Person;
|
||||
|
||||
impl Backend {
|
||||
impl Client {
|
||||
/// Get all available persons from the server.
|
||||
pub async fn get_persons(&self) -> Result<Vec<Person>> {
|
||||
let body = self.get("persons").await?;
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::backend::{Backend, Recording, Result};
|
||||
use crate::{Client, Result};
|
||||
use musicus_database::Recording;
|
||||
|
||||
impl Backend {
|
||||
impl Client {
|
||||
/// Get all available recordings from the server.
|
||||
pub async fn get_recordings_for_work(&self, work_id: &str) -> Result<Vec<Recording>> {
|
||||
let body = self.get(&format!("works/{}/recordings", work_id)).await?;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::backend::{Backend, Result};
|
||||
use crate::{Client, Result};
|
||||
use isahc::http::StatusCode;
|
||||
use isahc::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -23,7 +23,7 @@ pub struct UserRegistration {
|
|||
pub answer: String,
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
impl Client {
|
||||
/// Request a new captcha for registration.
|
||||
pub async fn get_captcha(&self) -> Result<Captcha> {
|
||||
let body = self.get("captcha").await?;
|
||||
|
|
@ -36,7 +36,7 @@ impl Backend {
|
|||
pub async fn register(&self, data: UserRegistration) -> Result<bool> {
|
||||
let server_url = self.server_url()?;
|
||||
|
||||
let mut response = Request::post(format!("{}/users", server_url))
|
||||
let response = Request::post(format!("{}/users", server_url))
|
||||
.timeout(Duration::from_secs(10))
|
||||
.header("Content-Type", "application/json")
|
||||
.body(serde_json::to_string(&data)?)?
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::backend::{Backend, Result, Work};
|
||||
use crate::{Client, Result};
|
||||
use musicus_database::Work;
|
||||
|
||||
impl Backend {
|
||||
impl Client {
|
||||
/// Get all available works from the server.
|
||||
pub async fn get_works(&self, composer_id: &str) -> Result<Vec<Work>> {
|
||||
let body = self.get(&format!("persons/{}/works", composer_id)).await?;
|
||||
15
crates/musicus_database/Cargo.toml
Normal file
15
crates/musicus_database/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "musicus_database"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
workspace = "../.."
|
||||
|
||||
[dependencies]
|
||||
diesel = { version = "1.4.5", features = ["sqlite"] }
|
||||
diesel_migrations = "1.4.0"
|
||||
futures-channel = "0.3.5"
|
||||
rand = "0.7.3"
|
||||
serde = { version = "1.0.117", features = ["derive"] }
|
||||
serde_json = "1.0.59"
|
||||
thiserror = "1.0.23"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::schema::ensembles;
|
||||
use super::{Database, DatabaseResult};
|
||||
use super::{Database, Result};
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ pub struct Ensemble {
|
|||
|
||||
impl Database {
|
||||
/// Update an existing ensemble or insert a new one.
|
||||
pub fn update_ensemble(&self, ensemble: Ensemble) -> DatabaseResult<()> {
|
||||
pub fn update_ensemble(&self, ensemble: Ensemble) -> Result<()> {
|
||||
self.defer_foreign_keys()?;
|
||||
|
||||
self.connection.transaction(|| {
|
||||
|
|
@ -26,7 +26,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get an existing ensemble.
|
||||
pub fn get_ensemble(&self, id: &str) -> DatabaseResult<Option<Ensemble>> {
|
||||
pub fn get_ensemble(&self, id: &str) -> Result<Option<Ensemble>> {
|
||||
let ensemble = ensembles::table
|
||||
.filter(ensembles::id.eq(id))
|
||||
.load::<Ensemble>(&self.connection)?
|
||||
|
|
@ -37,14 +37,14 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Delete an existing ensemble.
|
||||
pub fn delete_ensemble(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub fn delete_ensemble(&self, id: &str) -> Result<()> {
|
||||
diesel::delete(ensembles::table.filter(ensembles::id.eq(id))).execute(&self.connection)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get all existing ensembles.
|
||||
pub fn get_ensembles(&self) -> DatabaseResult<Vec<Ensemble>> {
|
||||
pub fn get_ensembles(&self) -> Result<Vec<Ensemble>> {
|
||||
let ensembles = ensembles::table.load::<Ensemble>(&self.connection)?;
|
||||
|
||||
Ok(ensembles)
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
use thiserror::Error;
|
||||
|
||||
/// Error that happens within the database module.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DatabaseError {
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
ConnectionError(#[from] diesel::result::ConnectionError),
|
||||
|
||||
|
|
@ -23,4 +21,4 @@ pub enum DatabaseError {
|
|||
}
|
||||
|
||||
/// Return type for database methods.
|
||||
pub type DatabaseResult<T> = Result<T, DatabaseError>;
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::schema::instruments;
|
||||
use super::{Database, DatabaseResult};
|
||||
use super::{Database, Result};
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ pub struct Instrument {
|
|||
|
||||
impl Database {
|
||||
/// Update an existing instrument or insert a new one.
|
||||
pub fn update_instrument(&self, instrument: Instrument) -> DatabaseResult<()> {
|
||||
pub fn update_instrument(&self, instrument: Instrument) -> Result<()> {
|
||||
self.defer_foreign_keys()?;
|
||||
|
||||
self.connection.transaction(|| {
|
||||
|
|
@ -26,7 +26,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get an existing instrument.
|
||||
pub fn get_instrument(&self, id: &str) -> DatabaseResult<Option<Instrument>> {
|
||||
pub fn get_instrument(&self, id: &str) -> Result<Option<Instrument>> {
|
||||
let instrument = instruments::table
|
||||
.filter(instruments::id.eq(id))
|
||||
.load::<Instrument>(&self.connection)?
|
||||
|
|
@ -37,7 +37,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Delete an existing instrument.
|
||||
pub fn delete_instrument(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub fn delete_instrument(&self, id: &str) -> Result<()> {
|
||||
diesel::delete(instruments::table.filter(instruments::id.eq(id)))
|
||||
.execute(&self.connection)?;
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get all existing instruments.
|
||||
pub fn get_instruments(&self) -> DatabaseResult<Vec<Instrument>> {
|
||||
pub fn get_instruments(&self) -> Result<Vec<Instrument>> {
|
||||
let instruments = instruments::table.load::<Instrument>(&self.connection)?;
|
||||
|
||||
Ok(instruments)
|
||||
|
|
@ -1,3 +1,11 @@
|
|||
// Required for schema.rs
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
|
||||
// Required for embed_migrations macro in database.rs
|
||||
#[macro_use]
|
||||
extern crate diesel_migrations;
|
||||
|
||||
use diesel::prelude::*;
|
||||
|
||||
pub mod ensembles;
|
||||
|
|
@ -44,7 +52,7 @@ pub struct Database {
|
|||
|
||||
impl Database {
|
||||
/// Create a new database interface and run migrations if necessary.
|
||||
pub fn new(file_name: &str) -> DatabaseResult<Database> {
|
||||
pub fn new(file_name: &str) -> Result<Database> {
|
||||
let connection = SqliteConnection::establish(file_name)?;
|
||||
|
||||
diesel::sql_query("PRAGMA foreign_keys = ON").execute(&connection)?;
|
||||
|
|
@ -54,7 +62,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Defer all foreign keys for the next transaction.
|
||||
fn defer_foreign_keys(&self) -> DatabaseResult<()> {
|
||||
fn defer_foreign_keys(&self) -> Result<()> {
|
||||
diesel::sql_query("PRAGMA defer_foreign_keys = ON").execute(&self.connection)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use super::generate_id;
|
||||
use super::schema::{mediums, recordings, track_sets, tracks};
|
||||
use super::{Database, DatabaseError, Recording, DatabaseResult};
|
||||
use super::{Database, Error, Recording, Result};
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -79,10 +79,10 @@ struct TrackRow {
|
|||
|
||||
impl Database {
|
||||
/// Update an existing medium or insert a new one.
|
||||
pub fn update_medium(&self, medium: Medium) -> DatabaseResult<()> {
|
||||
pub fn update_medium(&self, medium: Medium) -> Result<()> {
|
||||
self.defer_foreign_keys()?;
|
||||
|
||||
self.connection.transaction::<(), DatabaseError, _>(|| {
|
||||
self.connection.transaction::<(), Error, _>(|| {
|
||||
let medium_id = &medium.id;
|
||||
|
||||
// This will also delete the track sets and tracks.
|
||||
|
|
@ -152,7 +152,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get an existing medium.
|
||||
pub fn get_medium(&self, id: &str) -> DatabaseResult<Option<Medium>> {
|
||||
pub fn get_medium(&self, id: &str) -> Result<Option<Medium>> {
|
||||
let row = mediums::table
|
||||
.filter(mediums::id.eq(id))
|
||||
.load::<MediumRow>(&self.connection)?
|
||||
|
|
@ -169,13 +169,13 @@ impl Database {
|
|||
|
||||
/// Delete a medium and all of its tracks. This will fail, if the music
|
||||
/// library contains audio files referencing any of those tracks.
|
||||
pub fn delete_medium(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub fn delete_medium(&self, id: &str) -> Result<()> {
|
||||
diesel::delete(mediums::table.filter(mediums::id.eq(id))).execute(&self.connection)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get all available track sets for a recording.
|
||||
pub fn get_track_sets(&self, recording_id: &str) -> DatabaseResult<Vec<TrackSet>> {
|
||||
pub fn get_track_sets(&self, recording_id: &str) -> Result<Vec<TrackSet>> {
|
||||
let mut track_sets: Vec<TrackSet> = Vec::new();
|
||||
|
||||
let rows = track_sets::table
|
||||
|
|
@ -193,7 +193,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Retrieve all available information on a medium from related tables.
|
||||
fn get_medium_data(&self, row: MediumRow) -> DatabaseResult<Medium> {
|
||||
fn get_medium_data(&self, row: MediumRow) -> Result<Medium> {
|
||||
let track_set_rows = track_sets::table
|
||||
.filter(track_sets::medium.eq(&row.id))
|
||||
.order_by(track_sets::index)
|
||||
|
|
@ -217,12 +217,12 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Convert a track set row from the database to an actual track set.
|
||||
fn get_track_set_from_row(&self, row: TrackSetRow) -> DatabaseResult<TrackSet> {
|
||||
fn get_track_set_from_row(&self, row: TrackSetRow) -> Result<TrackSet> {
|
||||
let recording_id = row.recording;
|
||||
|
||||
let recording = self
|
||||
.get_recording(&recording_id)?
|
||||
.ok_or(DatabaseError::Other(format!(
|
||||
.ok_or(Error::Other(format!(
|
||||
"Failed to get recording ({}) for track set ({}).",
|
||||
recording_id,
|
||||
row.id,
|
||||
|
|
@ -241,12 +241,11 @@ impl Database {
|
|||
.split(',')
|
||||
.map(|part_index| {
|
||||
str::parse(part_index)
|
||||
.or(Err(DatabaseError::Other(format!(
|
||||
"Failed to parse part index from '{}'.",
|
||||
track_row.work_parts,
|
||||
)))?)
|
||||
.or(Err(Error::Other(
|
||||
format!("Failed to parse part index from '{}'.", track_row.work_parts,
|
||||
))))
|
||||
})
|
||||
.collect::<DatabaseResult<Vec<usize>>>()?;
|
||||
.collect::<Result<Vec<usize>>>()?;
|
||||
|
||||
let track = Track {
|
||||
work_parts,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::schema::persons;
|
||||
use super::{Database, DatabaseResult};
|
||||
use super::{Database, Result};
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ impl Person {
|
|||
|
||||
impl Database {
|
||||
/// Update an existing person or insert a new one.
|
||||
pub fn update_person(&self, person: Person) -> DatabaseResult<()> {
|
||||
pub fn update_person(&self, person: Person) -> Result<()> {
|
||||
self.defer_foreign_keys()?;
|
||||
|
||||
self.connection.transaction(|| {
|
||||
|
|
@ -39,7 +39,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get an existing person.
|
||||
pub fn get_person(&self, id: &str) -> DatabaseResult<Option<Person>> {
|
||||
pub fn get_person(&self, id: &str) -> Result<Option<Person>> {
|
||||
let person = persons::table
|
||||
.filter(persons::id.eq(id))
|
||||
.load::<Person>(&self.connection)?
|
||||
|
|
@ -50,14 +50,14 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Delete an existing person.
|
||||
pub fn delete_person(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub fn delete_person(&self, id: &str) -> Result<()> {
|
||||
diesel::delete(persons::table.filter(persons::id.eq(id))).execute(&self.connection)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get all existing persons.
|
||||
pub fn get_persons(&self) -> DatabaseResult<Vec<Person>> {
|
||||
pub fn get_persons(&self) -> Result<Vec<Person>> {
|
||||
let persons = persons::table.load::<Person>(&self.connection)?;
|
||||
|
||||
Ok(persons)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use super::generate_id;
|
||||
use super::schema::{ensembles, performances, persons, recordings};
|
||||
use super::{Database, Ensemble, DatabaseError, Instrument, Person, DatabaseResult, Work};
|
||||
use super::{Database, Ensemble, Error, Instrument, Person, Result, Work};
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -119,9 +119,9 @@ impl Recording {
|
|||
impl Database {
|
||||
/// Update an existing recording or insert a new one.
|
||||
// TODO: Think about whether to also insert the other items.
|
||||
pub fn update_recording(&self, recording: Recording) -> DatabaseResult<()> {
|
||||
pub fn update_recording(&self, recording: Recording) -> Result<()> {
|
||||
self.defer_foreign_keys()?;
|
||||
self.connection.transaction::<(), DatabaseError, _>(|| {
|
||||
self.connection.transaction::<(), Error, _>(|| {
|
||||
let recording_id = &recording.id;
|
||||
self.delete_recording(recording_id)?;
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Check whether the database contains a recording.
|
||||
pub fn recording_exists(&self, id: &str) -> DatabaseResult<bool> {
|
||||
pub fn recording_exists(&self, id: &str) -> Result<bool> {
|
||||
let exists = recordings::table
|
||||
.filter(recordings::id.eq(id))
|
||||
.load::<RecordingRow>(&self.connection)?
|
||||
|
|
@ -190,7 +190,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get an existing recording.
|
||||
pub fn get_recording(&self, id: &str) -> DatabaseResult<Option<Recording>> {
|
||||
pub fn get_recording(&self, id: &str) -> Result<Option<Recording>> {
|
||||
let row = recordings::table
|
||||
.filter(recordings::id.eq(id))
|
||||
.load::<RecordingRow>(&self.connection)?
|
||||
|
|
@ -206,7 +206,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Retrieve all available information on a recording from related tables.
|
||||
fn get_recording_data(&self, row: RecordingRow) -> DatabaseResult<Recording> {
|
||||
fn get_recording_data(&self, row: RecordingRow) -> Result<Recording> {
|
||||
let mut performance_descriptions: Vec<Performance> = Vec::new();
|
||||
|
||||
let performance_rows = performances::table
|
||||
|
|
@ -218,7 +218,7 @@ impl Database {
|
|||
person: match row.person {
|
||||
Some(id) => Some(
|
||||
self.get_person(&id)?
|
||||
.ok_or(DatabaseError::Other(format!(
|
||||
.ok_or(Error::Other(format!(
|
||||
"Failed to get person ({}) for recording ({}).",
|
||||
id,
|
||||
row.id,
|
||||
|
|
@ -229,7 +229,7 @@ impl Database {
|
|||
ensemble: match row.ensemble {
|
||||
Some(id) => Some(
|
||||
self.get_ensemble(&id)?
|
||||
.ok_or(DatabaseError::Other(format!(
|
||||
.ok_or(Error::Other(format!(
|
||||
"Failed to get ensemble ({}) for recording ({}).",
|
||||
id,
|
||||
row.id,
|
||||
|
|
@ -240,7 +240,7 @@ impl Database {
|
|||
role: match row.role {
|
||||
Some(id) => Some(
|
||||
self.get_instrument(&id)?
|
||||
.ok_or(DatabaseError::Other(format!(
|
||||
.ok_or(Error::Other(format!(
|
||||
"Failed to get instrument ({}) for recording ({}).",
|
||||
id,
|
||||
row.id,
|
||||
|
|
@ -254,7 +254,7 @@ impl Database {
|
|||
let work_id = &row.work;
|
||||
let work = self
|
||||
.get_work(work_id)?
|
||||
.ok_or(DatabaseError::Other(format!(
|
||||
.ok_or(Error::Other(format!(
|
||||
"Failed to get work ({}) for recording ({}).",
|
||||
work_id,
|
||||
row.id,
|
||||
|
|
@ -271,7 +271,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get all available information on all recordings where a person is performing.
|
||||
pub fn get_recordings_for_person(&self, person_id: &str) -> DatabaseResult<Vec<Recording>> {
|
||||
pub fn get_recordings_for_person(&self, person_id: &str) -> Result<Vec<Recording>> {
|
||||
let mut recordings: Vec<Recording> = Vec::new();
|
||||
|
||||
let rows = recordings::table
|
||||
|
|
@ -289,7 +289,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get all available information on all recordings where an ensemble is performing.
|
||||
pub fn get_recordings_for_ensemble(&self, ensemble_id: &str) -> DatabaseResult<Vec<Recording>> {
|
||||
pub fn get_recordings_for_ensemble(&self, ensemble_id: &str) -> Result<Vec<Recording>> {
|
||||
let mut recordings: Vec<Recording> = Vec::new();
|
||||
|
||||
let rows = recordings::table
|
||||
|
|
@ -307,7 +307,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get allavailable information on all recordings of a work.
|
||||
pub fn get_recordings_for_work(&self, work_id: &str) -> DatabaseResult<Vec<Recording>> {
|
||||
pub fn get_recordings_for_work(&self, work_id: &str) -> Result<Vec<Recording>> {
|
||||
let mut recordings: Vec<Recording> = Vec::new();
|
||||
|
||||
let rows = recordings::table
|
||||
|
|
@ -323,7 +323,7 @@ impl Database {
|
|||
|
||||
/// Delete an existing recording. This will fail if there are still references to this
|
||||
/// recording from other tables that are not directly part of the recording data.
|
||||
pub fn delete_recording(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub fn delete_recording(&self, id: &str) -> Result<()> {
|
||||
diesel::delete(recordings::table.filter(recordings::id.eq(id)))
|
||||
.execute(&self.connection)?;
|
||||
Ok(())
|
||||
|
|
@ -6,31 +6,31 @@ use std::thread;
|
|||
|
||||
/// An action the database thread can perform.
|
||||
pub enum Action {
|
||||
UpdatePerson(Person, Sender<DatabaseResult<()>>),
|
||||
GetPerson(String, Sender<DatabaseResult<Option<Person>>>),
|
||||
DeletePerson(String, Sender<DatabaseResult<()>>),
|
||||
GetPersons(Sender<DatabaseResult<Vec<Person>>>),
|
||||
UpdateInstrument(Instrument, Sender<DatabaseResult<()>>),
|
||||
GetInstrument(String, Sender<DatabaseResult<Option<Instrument>>>),
|
||||
DeleteInstrument(String, Sender<DatabaseResult<()>>),
|
||||
GetInstruments(Sender<DatabaseResult<Vec<Instrument>>>),
|
||||
UpdateWork(Work, Sender<DatabaseResult<()>>),
|
||||
DeleteWork(String, Sender<DatabaseResult<()>>),
|
||||
GetWorks(String, Sender<DatabaseResult<Vec<Work>>>),
|
||||
UpdateEnsemble(Ensemble, Sender<DatabaseResult<()>>),
|
||||
GetEnsemble(String, Sender<DatabaseResult<Option<Ensemble>>>),
|
||||
DeleteEnsemble(String, Sender<DatabaseResult<()>>),
|
||||
GetEnsembles(Sender<DatabaseResult<Vec<Ensemble>>>),
|
||||
UpdateRecording(Recording, Sender<DatabaseResult<()>>),
|
||||
DeleteRecording(String, Sender<DatabaseResult<()>>),
|
||||
GetRecordingsForPerson(String, Sender<DatabaseResult<Vec<Recording>>>),
|
||||
GetRecordingsForEnsemble(String, Sender<DatabaseResult<Vec<Recording>>>),
|
||||
GetRecordingsForWork(String, Sender<DatabaseResult<Vec<Recording>>>),
|
||||
RecordingExists(String, Sender<DatabaseResult<bool>>),
|
||||
UpdateMedium(Medium, Sender<DatabaseResult<()>>),
|
||||
GetMedium(String, Sender<DatabaseResult<Option<Medium>>>),
|
||||
DeleteMedium(String, Sender<DatabaseResult<()>>),
|
||||
GetTrackSets(String, Sender<DatabaseResult<Vec<TrackSet>>>),
|
||||
UpdatePerson(Person, Sender<Result<()>>),
|
||||
GetPerson(String, Sender<Result<Option<Person>>>),
|
||||
DeletePerson(String, Sender<Result<()>>),
|
||||
GetPersons(Sender<Result<Vec<Person>>>),
|
||||
UpdateInstrument(Instrument, Sender<Result<()>>),
|
||||
GetInstrument(String, Sender<Result<Option<Instrument>>>),
|
||||
DeleteInstrument(String, Sender<Result<()>>),
|
||||
GetInstruments(Sender<Result<Vec<Instrument>>>),
|
||||
UpdateWork(Work, Sender<Result<()>>),
|
||||
DeleteWork(String, Sender<Result<()>>),
|
||||
GetWorks(String, Sender<Result<Vec<Work>>>),
|
||||
UpdateEnsemble(Ensemble, Sender<Result<()>>),
|
||||
GetEnsemble(String, Sender<Result<Option<Ensemble>>>),
|
||||
DeleteEnsemble(String, Sender<Result<()>>),
|
||||
GetEnsembles(Sender<Result<Vec<Ensemble>>>),
|
||||
UpdateRecording(Recording, Sender<Result<()>>),
|
||||
DeleteRecording(String, Sender<Result<()>>),
|
||||
GetRecordingsForPerson(String, Sender<Result<Vec<Recording>>>),
|
||||
GetRecordingsForEnsemble(String, Sender<Result<Vec<Recording>>>),
|
||||
GetRecordingsForWork(String, Sender<Result<Vec<Recording>>>),
|
||||
RecordingExists(String, Sender<Result<bool>>),
|
||||
UpdateMedium(Medium, Sender<Result<()>>),
|
||||
GetMedium(String, Sender<Result<Option<Medium>>>),
|
||||
DeleteMedium(String, Sender<Result<()>>),
|
||||
GetTrackSets(String, Sender<Result<Vec<TrackSet>>>),
|
||||
Stop(Sender<()>),
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ pub struct DbThread {
|
|||
|
||||
impl DbThread {
|
||||
/// Create a new database connection in a background thread.
|
||||
pub async fn new(path: String) -> DatabaseResult<Self> {
|
||||
pub async fn new(path: String) -> Result<Self> {
|
||||
let (action_sender, action_receiver) = mpsc::channel();
|
||||
let (ready_sender, ready_receiver) = oneshot::channel();
|
||||
|
||||
|
|
@ -149,14 +149,14 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Update an existing person or insert a new one.
|
||||
pub async fn update_person(&self, person: Person) -> DatabaseResult<()> {
|
||||
pub async fn update_person(&self, person: Person) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(UpdatePerson(person, sender))?;
|
||||
receiver.await?
|
||||
}
|
||||
|
||||
/// Get an existing person.
|
||||
pub async fn get_person(&self, id: &str) -> DatabaseResult<Option<Person>> {
|
||||
pub async fn get_person(&self, id: &str) -> Result<Option<Person>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(GetPerson(id.to_string(), sender))?;
|
||||
receiver.await?
|
||||
|
|
@ -164,7 +164,7 @@ impl DbThread {
|
|||
|
||||
/// Delete an existing person. This will fail, if there are still other items referencing
|
||||
/// this person.
|
||||
pub async fn delete_person(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub async fn delete_person(&self, id: &str) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(DeletePerson(id.to_string(), sender))?;
|
||||
|
|
@ -172,14 +172,14 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get all existing persons.
|
||||
pub async fn get_persons(&self) -> DatabaseResult<Vec<Person>> {
|
||||
pub async fn get_persons(&self) -> Result<Vec<Person>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(GetPersons(sender))?;
|
||||
receiver.await?
|
||||
}
|
||||
|
||||
/// Update an existing instrument or insert a new one.
|
||||
pub async fn update_instrument(&self, instrument: Instrument) -> DatabaseResult<()> {
|
||||
pub async fn update_instrument(&self, instrument: Instrument) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(UpdateInstrument(instrument, sender))?;
|
||||
|
|
@ -187,7 +187,7 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get an existing instrument.
|
||||
pub async fn get_instrument(&self, id: &str) -> DatabaseResult<Option<Instrument>> {
|
||||
pub async fn get_instrument(&self, id: &str) -> Result<Option<Instrument>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(GetInstrument(id.to_string(), sender))?;
|
||||
|
|
@ -196,7 +196,7 @@ impl DbThread {
|
|||
|
||||
/// Delete an existing instrument. This will fail, if there are still other items referencing
|
||||
/// this instrument.
|
||||
pub async fn delete_instrument(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub async fn delete_instrument(&self, id: &str) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(DeleteInstrument(id.to_string(), sender))?;
|
||||
|
|
@ -204,14 +204,14 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get all existing instruments.
|
||||
pub async fn get_instruments(&self) -> DatabaseResult<Vec<Instrument>> {
|
||||
pub async fn get_instruments(&self) -> Result<Vec<Instrument>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(GetInstruments(sender))?;
|
||||
receiver.await?
|
||||
}
|
||||
|
||||
/// Update an existing work or insert a new one.
|
||||
pub async fn update_work(&self, work: Work) -> DatabaseResult<()> {
|
||||
pub async fn update_work(&self, work: Work) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(UpdateWork(work, sender))?;
|
||||
receiver.await?
|
||||
|
|
@ -219,7 +219,7 @@ impl DbThread {
|
|||
|
||||
/// Delete an existing work. This will fail, if there are still other items referencing
|
||||
/// this work.
|
||||
pub async fn delete_work(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub async fn delete_work(&self, id: &str) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(DeleteWork(id.to_string(), sender))?;
|
||||
|
|
@ -227,7 +227,7 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get information on all existing works by a composer.
|
||||
pub async fn get_works(&self, person_id: &str) -> DatabaseResult<Vec<Work>> {
|
||||
pub async fn get_works(&self, person_id: &str) -> Result<Vec<Work>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(GetWorks(person_id.to_string(), sender))?;
|
||||
|
|
@ -235,14 +235,14 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Update an existing ensemble or insert a new one.
|
||||
pub async fn update_ensemble(&self, ensemble: Ensemble) -> DatabaseResult<()> {
|
||||
pub async fn update_ensemble(&self, ensemble: Ensemble) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(UpdateEnsemble(ensemble, sender))?;
|
||||
receiver.await?
|
||||
}
|
||||
|
||||
/// Get an existing ensemble.
|
||||
pub async fn get_ensemble(&self, id: &str) -> DatabaseResult<Option<Ensemble>> {
|
||||
pub async fn get_ensemble(&self, id: &str) -> Result<Option<Ensemble>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(GetEnsemble(id.to_string(), sender))?;
|
||||
|
|
@ -251,7 +251,7 @@ impl DbThread {
|
|||
|
||||
/// Delete an existing ensemble. This will fail, if there are still other items referencing
|
||||
/// this ensemble.
|
||||
pub async fn delete_ensemble(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub async fn delete_ensemble(&self, id: &str) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(DeleteEnsemble(id.to_string(), sender))?;
|
||||
|
|
@ -259,14 +259,14 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get all existing ensembles.
|
||||
pub async fn get_ensembles(&self) -> DatabaseResult<Vec<Ensemble>> {
|
||||
pub async fn get_ensembles(&self) -> Result<Vec<Ensemble>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(GetEnsembles(sender))?;
|
||||
receiver.await?
|
||||
}
|
||||
|
||||
/// Update an existing recording or insert a new one.
|
||||
pub async fn update_recording(&self, recording: Recording) -> DatabaseResult<()> {
|
||||
pub async fn update_recording(&self, recording: Recording) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(UpdateRecording(recording, sender))?;
|
||||
|
|
@ -274,7 +274,7 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Delete an existing recording.
|
||||
pub async fn delete_recording(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub async fn delete_recording(&self, id: &str) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(DeleteRecording(id.to_string(), sender))?;
|
||||
|
|
@ -282,7 +282,7 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get information on all recordings in which a person performs.
|
||||
pub async fn get_recordings_for_person(&self, person_id: &str) -> DatabaseResult<Vec<Recording>> {
|
||||
pub async fn get_recordings_for_person(&self, person_id: &str) -> Result<Vec<Recording>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(GetRecordingsForPerson(person_id.to_string(), sender))?;
|
||||
|
|
@ -290,7 +290,7 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get information on all recordings in which an ensemble performs.
|
||||
pub async fn get_recordings_for_ensemble(&self, ensemble_id: &str) -> DatabaseResult<Vec<Recording>> {
|
||||
pub async fn get_recordings_for_ensemble(&self, ensemble_id: &str) -> Result<Vec<Recording>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(GetRecordingsForEnsemble(ensemble_id.to_string(), sender))?;
|
||||
|
|
@ -298,7 +298,7 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get information on all recordings of a work.
|
||||
pub async fn get_recordings_for_work(&self, work_id: &str) -> DatabaseResult<Vec<Recording>> {
|
||||
pub async fn get_recordings_for_work(&self, work_id: &str) -> Result<Vec<Recording>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(GetRecordingsForWork(work_id.to_string(), sender))?;
|
||||
|
|
@ -306,7 +306,7 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Check whether a recording exists within the database.
|
||||
pub async fn recording_exists(&self, id: &str) -> DatabaseResult<bool> {
|
||||
pub async fn recording_exists(&self, id: &str) -> Result<bool> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender
|
||||
.send(RecordingExists(id.to_string(), sender))?;
|
||||
|
|
@ -314,7 +314,7 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Update an existing medium or insert a new one.
|
||||
pub async fn update_medium(&self, medium: Medium) -> DatabaseResult<()> {
|
||||
pub async fn update_medium(&self, medium: Medium) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(UpdateMedium(medium, sender))?;
|
||||
receiver.await?
|
||||
|
|
@ -322,7 +322,7 @@ impl DbThread {
|
|||
|
||||
/// Delete an existing medium. This will fail, if there are still other
|
||||
/// items referencing this medium.
|
||||
pub async fn delete_medium(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub async fn delete_medium(&self, id: &str) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
|
||||
self.action_sender
|
||||
|
|
@ -332,21 +332,21 @@ impl DbThread {
|
|||
}
|
||||
|
||||
/// Get an existing medium.
|
||||
pub async fn get_medium(&self, id: &str) -> DatabaseResult<Option<Medium>> {
|
||||
pub async fn get_medium(&self, id: &str) -> Result<Option<Medium>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(GetMedium(id.to_owned(), sender))?;
|
||||
receiver.await?
|
||||
}
|
||||
|
||||
/// Get all track sets for a recording.
|
||||
pub async fn get_track_sets(&self, recording_id: &str) -> DatabaseResult<Vec<TrackSet>> {
|
||||
pub async fn get_track_sets(&self, recording_id: &str) -> Result<Vec<TrackSet>> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(GetTrackSets(recording_id.to_owned(), sender))?;
|
||||
receiver.await?
|
||||
}
|
||||
|
||||
/// Stop the database thread. Any future access to the database will fail.
|
||||
pub async fn stop(&self) -> DatabaseResult<()> {
|
||||
pub async fn stop(&self) -> Result<()> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.action_sender.send(Stop(sender))?;
|
||||
Ok(receiver.await?)
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
use super::generate_id;
|
||||
use super::schema::{instrumentations, work_parts, work_sections, works};
|
||||
use super::{Database, DatabaseError, Instrument, Person, DatabaseResult};
|
||||
use super::{Database, Error, Instrument, Person, Result};
|
||||
use diesel::prelude::*;
|
||||
use diesel::{Insertable, Queryable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Table row data for a work.
|
||||
#[derive(Insertable, Queryable, Debug, Clone)]
|
||||
|
|
@ -105,10 +104,10 @@ impl Work {
|
|||
impl Database {
|
||||
/// Update an existing work or insert a new one.
|
||||
// TODO: Think about also inserting related items.
|
||||
pub fn update_work(&self, work: Work) -> DatabaseResult<()> {
|
||||
pub fn update_work(&self, work: Work) -> Result<()> {
|
||||
self.defer_foreign_keys()?;
|
||||
|
||||
self.connection.transaction::<(), DatabaseError, _>(|| {
|
||||
self.connection.transaction::<(), Error, _>(|| {
|
||||
let work_id = &work.id;
|
||||
self.delete_work(work_id)?;
|
||||
|
||||
|
|
@ -194,7 +193,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Get an existing work.
|
||||
pub fn get_work(&self, id: &str) -> DatabaseResult<Option<Work>> {
|
||||
pub fn get_work(&self, id: &str) -> Result<Option<Work>> {
|
||||
let row = works::table
|
||||
.filter(works::id.eq(id))
|
||||
.load::<WorkRow>(&self.connection)?
|
||||
|
|
@ -210,7 +209,7 @@ impl Database {
|
|||
}
|
||||
|
||||
/// Retrieve all available information on a work from related tables.
|
||||
fn get_work_data(&self, row: WorkRow) -> DatabaseResult<Work> {
|
||||
fn get_work_data(&self, row: WorkRow) -> Result<Work> {
|
||||
let mut instruments: Vec<Instrument> = Vec::new();
|
||||
|
||||
let instrumentations = instrumentations::table
|
||||
|
|
@ -221,7 +220,7 @@ impl Database {
|
|||
let id = &instrumentation.instrument;
|
||||
instruments.push(
|
||||
self.get_instrument(id)?
|
||||
.ok_or(DatabaseError::Other(format!(
|
||||
.ok_or(Error::Other(format!(
|
||||
"Failed to get instrument ({}) for work ({}).",
|
||||
id,
|
||||
row.id,
|
||||
|
|
@ -241,7 +240,7 @@ impl Database {
|
|||
composer: match part_row.composer {
|
||||
Some(composer) => Some(
|
||||
self.get_person(&composer)?
|
||||
.ok_or(DatabaseError::Other(format!(
|
||||
.ok_or(Error::Other(format!(
|
||||
"Failed to get person ({}) for work ({}).",
|
||||
composer,
|
||||
row.id,
|
||||
|
|
@ -268,7 +267,7 @@ impl Database {
|
|||
let person_id = &row.composer;
|
||||
let person = self
|
||||
.get_person(person_id)?
|
||||
.ok_or(DatabaseError::Other(format!(
|
||||
.ok_or(Error::Other(format!(
|
||||
"Failed to get person ({}) for work ({}).",
|
||||
person_id,
|
||||
row.id,
|
||||
|
|
@ -286,13 +285,13 @@ impl Database {
|
|||
|
||||
/// Delete an existing work. This will fail if there are still other tables that relate to
|
||||
/// this work except for the things that are part of the information on the work it
|
||||
pub fn delete_work(&self, id: &str) -> DatabaseResult<()> {
|
||||
pub fn delete_work(&self, id: &str) -> Result<()> {
|
||||
diesel::delete(works::table.filter(works::id.eq(id))).execute(&self.connection)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get all existing works by a composer and related information from other tables.
|
||||
pub fn get_works(&self, composer_id: &str) -> DatabaseResult<Vec<Work>> {
|
||||
pub fn get_works(&self, composer_id: &str) -> Result<Vec<Work>> {
|
||||
let mut works: Vec<Work> = Vec::new();
|
||||
|
||||
let rows = works::table
|
||||
|
|
@ -20,6 +20,6 @@ i18n = import('i18n')
|
|||
subdir('data')
|
||||
subdir('po')
|
||||
subdir('res')
|
||||
subdir('src')
|
||||
subdir('crates/musicus/src')
|
||||
|
||||
meson.add_install_script('build-aux/postinstall.py')
|
||||
|
|
|
|||
134
src/meson.build
134
src/meson.build
|
|
@ -1,134 +0,0 @@
|
|||
prefix = get_option('prefix')
|
||||
localedir = join_paths(prefix, get_option('localedir'))
|
||||
|
||||
global_conf = configuration_data()
|
||||
global_conf.set_quoted('LOCALEDIR', localedir)
|
||||
global_conf.set_quoted('VERSION', meson.project_version())
|
||||
config_rs = configure_file(
|
||||
input: 'config.rs.in',
|
||||
output: 'config.rs',
|
||||
configuration: global_conf
|
||||
)
|
||||
|
||||
run_command(
|
||||
'cp',
|
||||
config_rs,
|
||||
meson.current_source_dir(),
|
||||
check: true
|
||||
)
|
||||
|
||||
resource_conf = configuration_data()
|
||||
resource_conf.set_quoted('RESOURCEFILE', resources.full_path())
|
||||
resource_rs = configure_file(
|
||||
input: 'resources.rs.in',
|
||||
output: 'resources.rs',
|
||||
configuration: resource_conf
|
||||
)
|
||||
|
||||
run_command(
|
||||
'cp',
|
||||
resource_rs,
|
||||
meson.current_source_dir(),
|
||||
check: true
|
||||
)
|
||||
|
||||
sources = files(
|
||||
'backend/client/ensembles.rs',
|
||||
'backend/client/instruments.rs',
|
||||
'backend/client/mediums.rs',
|
||||
'backend/client/mod.rs',
|
||||
'backend/client/persons.rs',
|
||||
'backend/client/recordings.rs',
|
||||
'backend/client/register.rs',
|
||||
'backend/client/works.rs',
|
||||
'backend/database/ensembles.rs',
|
||||
'backend/database/error.rs',
|
||||
'backend/database/instruments.rs',
|
||||
'backend/database/medium.rs',
|
||||
'backend/database/mod.rs',
|
||||
'backend/database/persons.rs',
|
||||
'backend/database/recordings.rs',
|
||||
'backend/database/schema.rs',
|
||||
'backend/database/thread.rs',
|
||||
'backend/database/works.rs',
|
||||
'backend/error.rs',
|
||||
'backend/library.rs',
|
||||
'backend/mod.rs',
|
||||
'backend/player.rs',
|
||||
'backend/secure.rs',
|
||||
'editors/ensemble.rs',
|
||||
'editors/instrument.rs',
|
||||
'editors/mod.rs',
|
||||
'editors/performance.rs',
|
||||
'editors/person.rs',
|
||||
'editors/recording.rs',
|
||||
'editors/work.rs',
|
||||
'editors/work_part.rs',
|
||||
'editors/work_section.rs',
|
||||
'import/disc_source.rs',
|
||||
'import/folder_source.rs',
|
||||
'import/medium_editor.rs',
|
||||
'import/mod.rs',
|
||||
'import/source.rs',
|
||||
'import/source_selector.rs',
|
||||
'import/track_editor.rs',
|
||||
'import/track_selector.rs',
|
||||
'import/track_set_editor.rs',
|
||||
'navigator/mod.rs',
|
||||
'navigator/window.rs',
|
||||
'preferences/login.rs',
|
||||
'preferences/mod.rs',
|
||||
'preferences/register.rs',
|
||||
'preferences/server.rs',
|
||||
'screens/ensemble.rs',
|
||||
'screens/mod.rs',
|
||||
'screens/person.rs',
|
||||
'screens/player_screen.rs',
|
||||
'screens/recording.rs',
|
||||
'screens/work.rs',
|
||||
'selectors/ensemble.rs',
|
||||
'selectors/instrument.rs',
|
||||
'selectors/mod.rs',
|
||||
'selectors/person.rs',
|
||||
'selectors/recording.rs',
|
||||
'selectors/selector.rs',
|
||||
'selectors/work.rs',
|
||||
'widgets/button_row.rs',
|
||||
'widgets/editor.rs',
|
||||
'widgets/entry_row.rs',
|
||||
'widgets/upload_section.rs',
|
||||
'widgets/indexed_list_model.rs',
|
||||
'widgets/list.rs',
|
||||
'widgets/mod.rs',
|
||||
'widgets/player_bar.rs',
|
||||
'widgets/poe_list.rs',
|
||||
'widgets/screen.rs',
|
||||
'widgets/section.rs',
|
||||
'config.rs',
|
||||
'config.rs.in',
|
||||
'macros.rs',
|
||||
'main.rs',
|
||||
'resources.rs',
|
||||
'resources.rs.in',
|
||||
'window.rs',
|
||||
)
|
||||
|
||||
cargo_script = find_program(join_paths(meson.source_root(), 'build-aux/cargo.sh'))
|
||||
cargo_release = custom_target(
|
||||
'cargo-build',
|
||||
build_by_default: true,
|
||||
input: sources,
|
||||
depends: resources,
|
||||
output: meson.project_name(),
|
||||
console: true,
|
||||
install: true,
|
||||
install_dir: get_option('bindir'),
|
||||
command: [
|
||||
cargo_script,
|
||||
meson.build_root(),
|
||||
meson.source_root(),
|
||||
'@OUTPUT@',
|
||||
get_option('buildtype'),
|
||||
meson.project_name(),
|
||||
]
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue