hexagonal?
parent
312d6c98cf
commit
eb23143739
|
|
@ -103,6 +103,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
|
|
@ -1122,6 +1128,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
name = "memejoin-rs"
|
name = "memejoin-rs"
|
||||||
version = "0.2.2-alpha"
|
version = "0.2.2-alpha"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
"axum-extra",
|
"axum-extra",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.100"
|
||||||
async-trait = "0.1.72"
|
async-trait = "0.1.72"
|
||||||
axum = { version = "0.6.9", features = ["headers", "multipart"] }
|
axum = { version = "0.6.9", features = ["headers", "multipart"] }
|
||||||
axum-extra = { version = "0.7.5", features = ["cookie-private", "cookie"] }
|
axum-extra = { version = "0.7.5", features = ["cookie-private", "cookie"] }
|
||||||
|
|
|
||||||
12
flake.lock
12
flake.lock
|
|
@ -36,11 +36,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1736320768,
|
"lastModified": 1744536153,
|
||||||
"narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=",
|
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "4bc9c909d9ac828a039f288cf872d16d38185db8",
|
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -62,11 +62,11 @@
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1743682350,
|
"lastModified": 1759718104,
|
||||||
"narHash": "sha256-S/MyKOFajCiBm5H5laoE59wB6w0NJ4wJG53iAPfYW3k=",
|
"narHash": "sha256-TbkLsgdnXHUXR4gOQBmhxkEE9ne+eHmX1chZHWRogy0=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "c4a8327b0f25d1d81edecbb6105f74d7cf9d7382",
|
"rev": "edea9f33f9a03f615ad3609a40fbcefe0ec835ca",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
local-rust = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain).override {
|
local-rust = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain).override {
|
||||||
extensions = [ "rust-analysis" ];
|
extensions = [ "rust-analyzer" "rust-src" ];
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod models;
|
||||||
|
pub mod ports;
|
||||||
|
pub mod service;
|
||||||
|
|
@ -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<Channel>,
|
||||||
|
users: Vec<User>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct User {
|
||||||
|
user: UserName,
|
||||||
|
channel_intros: HashMap<ChannelName, Vec<Intro>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod guild;
|
||||||
|
|
@ -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<Guild, CreateGuildError>;
|
||||||
|
async fn create_user(&self, req: CreateUserRequest) -> Result<User, CreateUserError>;
|
||||||
|
async fn create_channel(
|
||||||
|
&self,
|
||||||
|
req: CreateChannelRequest,
|
||||||
|
) -> Result<Channel, CreateChannelError>;
|
||||||
|
|
||||||
|
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<Guild, GetGuildError>;
|
||||||
|
|
||||||
|
async fn create_guild(&self, req: CreateGuildRequest) -> Result<Guild, CreateGuildError>;
|
||||||
|
async fn create_user(&self, req: CreateUserRequest) -> Result<User, CreateUserError>;
|
||||||
|
async fn create_channel(
|
||||||
|
&self,
|
||||||
|
req: CreateChannelRequest,
|
||||||
|
) -> Result<Channel, CreateChannelError>;
|
||||||
|
|
||||||
|
async fn add_intro_to_guild(
|
||||||
|
&self,
|
||||||
|
req: AddIntroToGuildRequest,
|
||||||
|
) -> Result<(), AddIntroToGuildError>;
|
||||||
|
|
||||||
|
async fn add_intro_to_user(
|
||||||
|
&self,
|
||||||
|
req: AddIntroToUserRequest,
|
||||||
|
) -> Result<(), AddIntroToUserError>;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::lib::domain::intro_tool::ports::{IntroToolRepository, IntroToolService};
|
||||||
|
|
||||||
|
use super::models;
|
||||||
|
|
||||||
|
pub struct Service<R>
|
||||||
|
where
|
||||||
|
R: IntroToolRepository,
|
||||||
|
{
|
||||||
|
repo: R,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Service<R>
|
||||||
|
where
|
||||||
|
R: IntroToolRepository,
|
||||||
|
{
|
||||||
|
pub fn new(repo: R) -> Self {
|
||||||
|
Self { repo }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> IntroToolService for Service<R>
|
||||||
|
where
|
||||||
|
R: IntroToolRepository,
|
||||||
|
{
|
||||||
|
async fn create_guild(
|
||||||
|
&self,
|
||||||
|
req: models::guild::CreateGuildRequest,
|
||||||
|
) -> Result<models::guild::Guild, models::guild::CreateGuildError> {
|
||||||
|
self.repo.create_guild(req).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_user(
|
||||||
|
&self,
|
||||||
|
req: models::guild::CreateUserRequest,
|
||||||
|
) -> Result<models::guild::User, models::guild::CreateUserError> {
|
||||||
|
self.repo.create_user(req).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_channel(
|
||||||
|
&self,
|
||||||
|
req: models::guild::CreateChannelRequest,
|
||||||
|
) -> Result<models::guild::Channel, models::guild::CreateChannelError> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod intro_tool;
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod domain;
|
||||||
|
pub mod inbound;
|
||||||
|
pub mod outbound;
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod sqlite;
|
||||||
|
|
@ -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<Self, std::io::Error> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntroToolRepository for Sqlite {
|
||||||
|
async fn get_guild(&self, guild_id: GuildId) -> Result<Guild, GetGuildError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_guild(&self, req: CreateGuildRequest) -> Result<Guild, CreateGuildError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_user(&self, req: CreateUserRequest) -> Result<User, CreateUserError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_channel(
|
||||||
|
&self,
|
||||||
|
req: CreateChannelRequest,
|
||||||
|
) -> Result<Channel, CreateChannelError> {
|
||||||
|
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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/main.rs
65
src/main.rs
|
|
@ -2,6 +2,8 @@
|
||||||
// #![feature(proc_macro_hygiene)]
|
// #![feature(proc_macro_hygiene)]
|
||||||
// #![feature(async_closure)]
|
// #![feature(async_closure)]
|
||||||
|
|
||||||
|
mod lib;
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
mod db;
|
mod db;
|
||||||
mod htmx;
|
mod htmx;
|
||||||
|
|
@ -28,6 +30,8 @@ use serenity::prelude::*;
|
||||||
use songbird::SerenityInit;
|
use songbird::SerenityInit;
|
||||||
use tracing::*;
|
use tracing::*;
|
||||||
|
|
||||||
|
use crate::lib::domain::intro_tool;
|
||||||
|
use crate::lib::outbound;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
enum HandlerMessage {
|
enum HandlerMessage {
|
||||||
|
|
@ -312,37 +316,52 @@ async fn spawn_bot(db: Arc<tokio::sync::Mutex<db::Database>>) {
|
||||||
#[instrument]
|
#[instrument]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
dotenv::dotenv().ok();
|
dotenv::dotenv().ok();
|
||||||
|
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let settings = serde_json::from_str::<Settings>(
|
let settings = serde_json::from_str::<Settings>(
|
||||||
&std::fs::read_to_string("config/settings.json").expect("no config/settings.json"),
|
&std::fs::read_to_string("config/settings.json").expect("no config/settings.json"),
|
||||||
)
|
)
|
||||||
.expect("error parsing settings file");
|
.expect("error parsing settings file");
|
||||||
info!("{settings:?}");
|
|
||||||
|
|
||||||
let (run_api, run_bot) = (settings.run_api, settings.run_bot);
|
let db = outbound::sqlite::Sqlite::new(".config/db.sqlite").expect("couldn't open sqlite db");
|
||||||
let db = Arc::new(tokio::sync::Mutex::new(
|
let service = intro_tool::service::Service::new(db);
|
||||||
db::Database::new("./config/db.sqlite").expect("couldn't open sqlite db"),
|
|
||||||
));
|
|
||||||
|
|
||||||
{
|
// TODO: http server
|
||||||
// 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(())
|
Ok(())
|
||||||
|
|
||||||
|
// dotenv::dotenv().ok();
|
||||||
|
//
|
||||||
|
// tracing_subscriber::fmt::init();
|
||||||
|
//
|
||||||
|
// let settings = serde_json::from_str::<Settings>(
|
||||||
|
// &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(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue