diff --git a/Cargo.lock b/Cargo.lock index 1083388..837bff5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + [[package]] name = "arrayvec" version = "0.7.4" @@ -1122,6 +1128,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" name = "memejoin-rs" version = "0.2.2-alpha" dependencies = [ + "anyhow", "async-trait", "axum", "axum-extra", diff --git a/Cargo.toml b/Cargo.toml index a34d895..ce4f0d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.100" async-trait = "0.1.72" axum = { version = "0.6.9", features = ["headers", "multipart"] } axum-extra = { version = "0.7.5", features = ["cookie-private", "cookie"] } diff --git a/flake.lock b/flake.lock index c0650e4..d06e5bf 100644 --- a/flake.lock +++ b/flake.lock @@ -36,11 +36,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1736320768, - "narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=", + "lastModified": 1744536153, + "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "4bc9c909d9ac828a039f288cf872d16d38185db8", + "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11", "type": "github" }, "original": { @@ -62,11 +62,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1743682350, - "narHash": "sha256-S/MyKOFajCiBm5H5laoE59wB6w0NJ4wJG53iAPfYW3k=", + "lastModified": 1759718104, + "narHash": "sha256-TbkLsgdnXHUXR4gOQBmhxkEE9ne+eHmX1chZHWRogy0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "c4a8327b0f25d1d81edecbb6105f74d7cf9d7382", + "rev": "edea9f33f9a03f615ad3609a40fbcefe0ec835ca", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index a67982e..b09a39e 100644 --- a/flake.nix +++ b/flake.nix @@ -24,7 +24,7 @@ }; }); local-rust = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain).override { - extensions = [ "rust-analysis" ]; + extensions = [ "rust-analyzer" "rust-src" ]; }; in { diff --git a/src/lib/domain/intro_tool/mod.rs b/src/lib/domain/intro_tool/mod.rs new file mode 100644 index 0000000..901e625 --- /dev/null +++ b/src/lib/domain/intro_tool/mod.rs @@ -0,0 +1,3 @@ +pub mod models; +pub mod ports; +pub mod service; diff --git a/src/lib/domain/intro_tool/models/guild.rs b/src/lib/domain/intro_tool/models/guild.rs new file mode 100644 index 0000000..19ef931 --- /dev/null +++ b/src/lib/domain/intro_tool/models/guild.rs @@ -0,0 +1,104 @@ +use std::collections::HashMap; + +use thiserror::Error; + +pub struct GuildId(u64); +pub struct ExternalGuildId(u64); +pub struct UserName(String); +pub struct ChannelName(String); +pub struct IntroId(i32); + +pub struct Guild { + id: GuildId, + + name: String, + sound_delay: u32, + external_id: ExternalGuildId, + + channels: Vec, + users: Vec, +} + +pub struct User { + user: UserName, + channel_intros: HashMap>, +} + +pub struct Channel { + name: ChannelName, +} + +pub struct Intro { + id: IntroId, + + name: String, + filename: String, +} + +pub struct CreateGuildRequest { + name: String, + sound_delay: u32, + external_id: ExternalGuildId, +} + +pub struct CreateUserRequest { + user: UserName, +} + +pub struct CreateChannelRequest { + guild_id: GuildId, + channel_name: ChannelName, +} + +pub struct AddIntroToGuildRequest { + guild_id: GuildId, + name: String, + volume: i32, + filename: String, +} + +pub struct AddIntroToUserRequest { + user: UserName, + guild_id: GuildId, + channel_name: ChannelName, + intro_id: IntroId, +} + +#[derive(Debug, Error)] +pub enum CreateGuildError { + #[error(transparent)] + Unknown(#[from] anyhow::Error), +} + +#[derive(Debug, Error)] +pub enum CreateUserError { + #[error(transparent)] + Unknown(#[from] anyhow::Error), +} + +#[derive(Debug, Error)] +pub enum CreateChannelError { + #[error(transparent)] + Unknown(#[from] anyhow::Error), +} + +#[derive(Debug, Error)] +pub enum AddIntroToGuildError { + #[error(transparent)] + Unknown(#[from] anyhow::Error), +} + +#[derive(Debug, Error)] +pub enum AddIntroToUserError { + #[error(transparent)] + Unknown(#[from] anyhow::Error), +} + +#[derive(Debug, Error)] +pub enum GetGuildError { + #[error("Guild not found")] + NotFound, + + #[error(transparent)] + Unknown(#[from] anyhow::Error), +} diff --git a/src/lib/domain/intro_tool/models/mod.rs b/src/lib/domain/intro_tool/models/mod.rs new file mode 100644 index 0000000..4931e5f --- /dev/null +++ b/src/lib/domain/intro_tool/models/mod.rs @@ -0,0 +1 @@ +pub mod guild; diff --git a/src/lib/domain/intro_tool/ports.rs b/src/lib/domain/intro_tool/ports.rs new file mode 100644 index 0000000..082895d --- /dev/null +++ b/src/lib/domain/intro_tool/ports.rs @@ -0,0 +1,45 @@ +use super::models::guild::{ + AddIntroToGuildError, AddIntroToGuildRequest, AddIntroToUserError, AddIntroToUserRequest, + Channel, CreateChannelError, CreateChannelRequest, CreateGuildError, CreateGuildRequest, + CreateUserError, CreateUserRequest, GetGuildError, Guild, GuildId, User, +}; + +pub trait IntroToolService { + async fn create_guild(&self, req: CreateGuildRequest) -> Result; + async fn create_user(&self, req: CreateUserRequest) -> Result; + async fn create_channel( + &self, + req: CreateChannelRequest, + ) -> Result; + + async fn add_intro_to_guild( + &self, + req: AddIntroToGuildRequest, + ) -> Result<(), AddIntroToGuildError>; + + async fn add_intro_to_user( + &self, + req: AddIntroToUserRequest, + ) -> Result<(), AddIntroToUserError>; +} + +pub trait IntroToolRepository { + async fn get_guild(&self, guild_id: GuildId) -> Result; + + async fn create_guild(&self, req: CreateGuildRequest) -> Result; + async fn create_user(&self, req: CreateUserRequest) -> Result; + async fn create_channel( + &self, + req: CreateChannelRequest, + ) -> Result; + + async fn add_intro_to_guild( + &self, + req: AddIntroToGuildRequest, + ) -> Result<(), AddIntroToGuildError>; + + async fn add_intro_to_user( + &self, + req: AddIntroToUserRequest, + ) -> Result<(), AddIntroToUserError>; +} diff --git a/src/lib/domain/intro_tool/service.rs b/src/lib/domain/intro_tool/service.rs new file mode 100644 index 0000000..2fb45c7 --- /dev/null +++ b/src/lib/domain/intro_tool/service.rs @@ -0,0 +1,59 @@ +use crate::lib::domain::intro_tool::ports::{IntroToolRepository, IntroToolService}; + +use super::models; + +pub struct Service +where + R: IntroToolRepository, +{ + repo: R, +} + +impl Service +where + R: IntroToolRepository, +{ + pub fn new(repo: R) -> Self { + Self { repo } + } +} + +impl IntroToolService for Service +where + R: IntroToolRepository, +{ + async fn create_guild( + &self, + req: models::guild::CreateGuildRequest, + ) -> Result { + self.repo.create_guild(req).await + } + + async fn create_user( + &self, + req: models::guild::CreateUserRequest, + ) -> Result { + self.repo.create_user(req).await + } + + async fn create_channel( + &self, + req: models::guild::CreateChannelRequest, + ) -> Result { + self.repo.create_channel(req).await + } + + async fn add_intro_to_guild( + &self, + req: models::guild::AddIntroToGuildRequest, + ) -> Result<(), models::guild::AddIntroToGuildError> { + self.repo.add_intro_to_guild(req).await + } + + async fn add_intro_to_user( + &self, + req: models::guild::AddIntroToUserRequest, + ) -> Result<(), models::guild::AddIntroToUserError> { + self.repo.add_intro_to_user(req).await + } +} diff --git a/src/lib/domain/mod.rs b/src/lib/domain/mod.rs new file mode 100644 index 0000000..f069a16 --- /dev/null +++ b/src/lib/domain/mod.rs @@ -0,0 +1 @@ +pub mod intro_tool; diff --git a/src/lib/inbound/mod.rs b/src/lib/inbound/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/mod.rs b/src/lib/mod.rs new file mode 100644 index 0000000..a65f027 --- /dev/null +++ b/src/lib/mod.rs @@ -0,0 +1,3 @@ +pub mod domain; +pub mod inbound; +pub mod outbound; diff --git a/src/lib/outbound/mod.rs b/src/lib/outbound/mod.rs new file mode 100644 index 0000000..6b1c108 --- /dev/null +++ b/src/lib/outbound/mod.rs @@ -0,0 +1 @@ +pub mod sqlite; diff --git a/src/lib/outbound/sqlite.rs b/src/lib/outbound/sqlite.rs new file mode 100644 index 0000000..e0822fe --- /dev/null +++ b/src/lib/outbound/sqlite.rs @@ -0,0 +1,51 @@ +use crate::lib::domain::intro_tool::{ + models::guild::{ + self, AddIntroToGuildError, AddIntroToGuildRequest, AddIntroToUserRequest, Channel, + CreateChannelError, CreateChannelRequest, CreateGuildError, CreateGuildRequest, + CreateUserError, CreateUserRequest, GetGuildError, Guild, GuildId, User, + }, + ports::IntroToolRepository, +}; + +pub struct Sqlite {} + +impl Sqlite { + pub fn new(path: &str) -> Result { + todo!() + } +} + +impl IntroToolRepository for Sqlite { + async fn get_guild(&self, guild_id: GuildId) -> Result { + todo!() + } + + async fn create_guild(&self, req: CreateGuildRequest) -> Result { + todo!() + } + + async fn create_user(&self, req: CreateUserRequest) -> Result { + todo!() + } + + async fn create_channel( + &self, + req: CreateChannelRequest, + ) -> Result { + todo!() + } + + async fn add_intro_to_guild( + &self, + req: AddIntroToGuildRequest, + ) -> Result<(), AddIntroToGuildError> { + todo!() + } + + async fn add_intro_to_user( + &self, + req: AddIntroToUserRequest, + ) -> Result<(), guild::AddIntroToUserError> { + todo!() + } +} diff --git a/src/main.rs b/src/main.rs index 4ac9783..8609872 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ // #![feature(proc_macro_hygiene)] // #![feature(async_closure)] +mod lib; + mod auth; mod db; mod htmx; @@ -28,6 +30,8 @@ use serenity::prelude::*; use songbird::SerenityInit; use tracing::*; +use crate::lib::domain::intro_tool; +use crate::lib::outbound; use crate::settings::Settings; enum HandlerMessage { @@ -312,37 +316,52 @@ async fn spawn_bot(db: Arc>) { #[instrument] async fn main() -> std::io::Result<()> { dotenv::dotenv().ok(); - tracing_subscriber::fmt::init(); let settings = serde_json::from_str::( &std::fs::read_to_string("config/settings.json").expect("no config/settings.json"), ) .expect("error parsing settings file"); - info!("{settings:?}"); - let (run_api, run_bot) = (settings.run_api, settings.run_bot); - let db = Arc::new(tokio::sync::Mutex::new( - db::Database::new("./config/db.sqlite").expect("couldn't open sqlite db"), - )); + let db = outbound::sqlite::Sqlite::new(".config/db.sqlite").expect("couldn't open sqlite db"); + let service = intro_tool::service::Service::new(db); - { - // attempt to initialize the database with the schema - let db = db.lock().await; - db.init().expect("couldn't init db"); - } - - if run_api { - spawn_api(db.clone()); - } - if run_bot { - spawn_bot(db).await; - } - - info!("spawned background tasks"); - - let _ = tokio::signal::ctrl_c().await; - info!("Received Ctrl-C, shuttdown down."); + // TODO: http server Ok(()) + + // dotenv::dotenv().ok(); + // + // tracing_subscriber::fmt::init(); + // + // let settings = serde_json::from_str::( + // &std::fs::read_to_string("config/settings.json").expect("no config/settings.json"), + // ) + // .expect("error parsing settings file"); + // info!("{settings:?}"); + // + // let (run_api, run_bot) = (settings.run_api, settings.run_bot); + // let db = Arc::new(tokio::sync::Mutex::new( + // db::Database::new("./config/db.sqlite").expect("couldn't open sqlite db"), + // )); + // + // { + // // attempt to initialize the database with the schema + // let db = db.lock().await; + // db.init().expect("couldn't init db"); + // } + // + // if run_api { + // spawn_api(db.clone()); + // } + // if run_bot { + // spawn_bot(db).await; + // } + // + // info!("spawned background tasks"); + // + // let _ = tokio::signal::ctrl_c().await; + // info!("Received Ctrl-C, shuttdown down."); + // + // Ok(()) }