From 827a519ca5e7315ef1c1ea491e6201cd0d602a8e Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Sun, 12 Nov 2023 09:56:23 -0600 Subject: [PATCH] WIP deisel stuff --- .gitignore | 1 + Cargo.lock | 251 ++++++++++++++++++ Cargo.toml | 6 +- assets/favicon.svg | 0 assets/styles.css | 58 ++-- build.rs | 3 + data/.keep | 1 + diesel.toml | 6 + flake.nix | 11 +- .../2023-11-11-073646_create_users/down.sql | 1 + .../2023-11-11-073646_create_users/up.sql | 5 + src/main.rs | 135 +++++++--- src/schema.rs | 9 + 13 files changed, 429 insertions(+), 58 deletions(-) create mode 100644 assets/favicon.svg create mode 100644 build.rs create mode 100644 data/.keep create mode 100644 diesel.toml create mode 100644 migrations/2023-11-11-073646_create_users/down.sql create mode 100644 migrations/2023-11-11-073646_create_users/up.sql create mode 100644 src/schema.rs diff --git a/.gitignore b/.gitignore index 6abfe1b..3eb4c30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target /.direnv +*.sqlitedb diff --git a/Cargo.lock b/Cargo.lock index 557f721..53df93c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,6 +146,107 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "deadpool" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb84100978c1c7b37f09ed3ce3e5f843af02c2a2c431bae5b19230dad2c1b490" +dependencies = [ + "async-trait", + "deadpool-runtime", + "num_cpus", + "serde", + "tokio", +] + +[[package]] +name = "deadpool-diesel" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8404d25ddc6cb0676d4a863bbd007613ee3fffb54db23e0e6341e1fe61c3e" +dependencies = [ + "deadpool", + "deadpool-sync", + "diesel", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" +dependencies = [ + "tokio", +] + +[[package]] +name = "deadpool-sync" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8db70494c13cae4ce67b4b4dafdaf828cf0df7237ab5b9e2fcabee4965d0a0a" +dependencies = [ + "deadpool-runtime", + "tracing", +] + +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "diesel" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2268a214a6f118fce1838edba3d1561cf0e78d8de785475957a580a7f8c69d33" +dependencies = [ + "diesel_derives", + "libsqlite3-sys", + "time", +] + +[[package]] +name = "diesel_derives" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" +dependencies = [ + "diesel_table_macro_syntax", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "diesel_migrations" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac" +dependencies = [ + "diesel", + "migrations_internals", + "migrations_macros", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" +dependencies = [ + "syn 2.0.39", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fnv" version = "1.0.7" @@ -206,6 +307,12 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + [[package]] name = "hermit-abi" version = "0.3.3" @@ -275,6 +382,16 @@ dependencies = [ "want", ] +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.9" @@ -293,6 +410,16 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libsqlite3-sys" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "lock_api" version = "0.4.11" @@ -315,6 +442,10 @@ version = "0.1.0" dependencies = [ "anyhow", "axum", + "deadpool", + "deadpool-diesel", + "diesel", + "diesel_migrations", "maud", "serde", "tokio", @@ -367,6 +498,27 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "migrations_internals" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada" +dependencies = [ + "serde", + "toml", +] + +[[package]] +name = "migrations_macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08" +dependencies = [ + "migrations_internals", + "proc-macro2", + "quote", +] + [[package]] name = "mime" version = "0.3.17" @@ -505,6 +657,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -665,6 +829,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -759,6 +932,35 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + [[package]] name = "tokio" version = "1.34.0" @@ -802,6 +1004,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -958,6 +1194,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1066,3 +1308,12 @@ name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index 2a377ba..e883c04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,13 @@ edition = "2021" [dependencies] anyhow = "1.0.75" axum = "0.6.20" +deadpool = "0.10.0" +deadpool-diesel = { version = "0.5.0", features = ["rt_tokio_1", "sqlite", "tracing", "serde"] } +diesel = { version = "2.1.3", features = ["sqlite"] } +diesel_migrations = { version = "2.1.0", features = ["sqlite"] } maud = "0.25.0" serde = { version = "1.0.192", features = ["derive"] } -tokio = { version = "1.34.0", features = ["full"] } +tokio = { version = "1.34.0", features = ["full", "macros", "rt-multi-thread"] } tower-http = { version = "0.4.4", features = ["fs"] } tower-livereload = "0.8.2" tracing = "0.1.40" diff --git a/assets/favicon.svg b/assets/favicon.svg new file mode 100644 index 0000000..e69de29 diff --git a/assets/styles.css b/assets/styles.css index 68366f3..a5b1c3d 100644 --- a/assets/styles.css +++ b/assets/styles.css @@ -16,18 +16,7 @@ html { text-size-adjust: none; } -body, -h1, -h2, -h3, -h4, -h5, -h6, -p, -figure, -blockquote, -dl, -dd { +body { margin: 0; } @@ -53,6 +42,7 @@ h4, h5, h6, button, +.button, input, label { line-height: 1.1; @@ -73,6 +63,7 @@ picture { input, button, +.button, textarea, select { font: inherit; @@ -87,10 +78,6 @@ textarea:not([rows]) { scroll-margin-block: 5ex; } -a[class] { - color: currentColor; -} - /* end reset */ /* global classes */ @@ -103,6 +90,10 @@ a[class] { flex-direction: column; } +.gap { + gap: 1ex; +} + /* end global classes */ :root { @@ -175,6 +166,11 @@ a[class] { } } +ul, +ol { + padding-left: 2ex; +} + html { background-color: var(--bg); color: var(--text); @@ -182,11 +178,15 @@ html { font-size: 16px; } +body>header h1 { + margin: 0; +} + body>header { justify-content: space-between; /* border-bottom: solid 1px var(--bg2); */ - background-color: var(--bg); - box-shadow: 0 -1px 1ex var(--Crust); + background-color: color-mix(in srgb, var(--Surface0) 30%, transparent); + box-shadow: 0 -1px 1ex var(--Mantle); } body>header>nav { @@ -196,13 +196,33 @@ body>header>nav { body>header a:not([class]) { display: flex; align-items: center; - padding: 1ex; + padding: 1ex 2ex; transition: color 0.1s ease-out, background-color 0.1s ease-out; text-decoration: none; color: var(--primary); + gap: 0.5ex; +} + +main.prose { + padding: 1ex; + max-width: 80ch; +} + +.button { + background-color: var(--Surface0); + padding: 1ex 2ex; + text-decoration: none; + color: currentColor; + box-shadow: 0 -1px 1px var(--Mantle); + border-radius: 2px; } body>header a:hover { background-color: var(--primary); color: var(--bg); +} + +.bg-primary { + background-color: var(--primary); + color: var(--bg); } \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..31c4cfd --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=./migrations"); +} diff --git a/data/.keep b/data/.keep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/data/.keep @@ -0,0 +1 @@ + diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 0000000..fcaf131 --- /dev/null +++ b/diesel.toml @@ -0,0 +1,6 @@ +[print_schema] +file = "src/schema.rs" +custom_type_derives = ["diesel::query_builder::QueryId"] + +[migrations_directory] +dir = "migrations" diff --git a/flake.nix b/flake.nix index c186c9f..7b26a5c 100644 --- a/flake.nix +++ b/flake.nix @@ -33,6 +33,7 @@ in { packages.default = naersk.buildPackage { src = ./.; + buildInputs = with pkgs; [sqlite]; }; formatter = pkgs.alejandra; checks = { @@ -42,14 +43,22 @@ devShell = with pkgs; mkShell { buildInputs = [ - hurl toolchain + rustfmt rustPackages.clippy rust-analyzer nodePackages_latest.vscode-langservers-extracted + + # dedupe from package inputs? + sqlite + diesel-cli + hurl ]; RUST_SRC_PATH = rustPlatform.rustLibSrc; + shellHook = '' + export DATABASE_URL="sqlite://./data/lyrs.sqlitedb"; + ''; }; }); } diff --git a/migrations/2023-11-11-073646_create_users/down.sql b/migrations/2023-11-11-073646_create_users/down.sql new file mode 100644 index 0000000..d69c65a --- /dev/null +++ b/migrations/2023-11-11-073646_create_users/down.sql @@ -0,0 +1 @@ +drop table users diff --git a/migrations/2023-11-11-073646_create_users/up.sql b/migrations/2023-11-11-073646_create_users/up.sql new file mode 100644 index 0000000..88bd1c9 --- /dev/null +++ b/migrations/2023-11-11-073646_create_users/up.sql @@ -0,0 +1,5 @@ +create table users ( + id text primary key, + name text, + hashed_password text +) diff --git a/src/main.rs b/src/main.rs index 26217a2..1952ca7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,53 +1,83 @@ //! lyrs entrypoint -use axum::{response::Html, routing::get, Router}; -use maud::html; -use std::net::SocketAddr; +use axum::{http::StatusCode, response::Html, routing::get, Router}; +use deadpool_diesel::sqlite::{Manager, Pool, Runtime}; +use diesel::sqlite::Sqlite; +use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; +use maud::{html, PreEscaped}; +use std::{env, net::SocketAddr}; use tower_http::services::ServeDir; use tower_livereload::LiveReloadLayer; -use tracing::{info, instrument, trace}; -use tracing_subscriber::{ - filter::{Directive, LevelFilter}, - EnvFilter, -}; +use tracing::{info, instrument, span, trace, Level}; +use tracing_subscriber::{filter::LevelFilter, EnvFilter}; +#[instrument] fn setup_trace_logger() { - let default_filter: Result = - Ok(EnvFilter::builder() - .with_default_directive(LevelFilter::INFO.into()) - .parse("info") - .unwrap()); - - let default_directive: Result = - "lyrs=trace".parse(); - - if default_directive.is_err() { - println!("{:?}", default_directive); - } - - let filter = EnvFilter::try_from_env("LOG_FILTER") - .or(default_filter) - .unwrap() - .add_directive(LevelFilter::INFO.into()) - .add_directive("lyrs=trace".parse().unwrap()); + let filter = EnvFilter::builder() + .with_default_directive(LevelFilter::INFO.into()) + .parse_lossy("info,lyrs=trace"); tracing_subscriber::fmt().with_env_filter(filter).init(); trace!("Starting..."); } -fn router() -> Router { +// struct State { +// pub pool: Pool, +// } + +fn run_migrations( + connection: &mut impl MigrationHarness, +) -> Result<(), Box> { + // This will run the necessary migrations. + // + // See the documentation for `MigrationHarness` for + // all available methods. + connection.run_pending_migrations(MIGRATIONS)?; + + Ok(()) +} + +#[instrument] +async fn router() -> Result { let app_router = Router::new() .route("/hello-world", get(greet_world)) .route("/hello-world-text", get(greet_world_text)); let assets_dir = ServeDir::new("./assets"); - Router::new() + let pool; + + let dbspan = span!(Level::WARN, "database_setup"); + { + let _s = dbspan.enter(); + + let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + let manager = Manager::new(database_url, Runtime::Tokio1); + pool = Pool::builder(manager).max_size(8).build().unwrap(); + info!("Database pool creation complete!"); + + let conn = pool.get().await?; + let mspan = span!(Level::INFO, "migrations"); + { + let _s = mspan.enter(); + let _ = conn + .interact(|c| run_migrations(c)) + .await + .expect("Failed to run migrations"); + info!("Migrations completed!"); + } + } + + // let state = Arc::new(State { pool }); + + Ok(Router::new() + .fallback(|| async { (StatusCode::NOT_FOUND, "404 page not found") }) .nest("/app", app_router) .nest_service("/assets", assets_dir) .route("/", get(index)) - .layer(LiveReloadLayer::new()) + .layer(LiveReloadLayer::new())) + // .with_state(state)) } async fn listen(r: Router) { @@ -59,37 +89,68 @@ async fn listen(r: Router) { .unwrap(); } +pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); + #[tokio::main] -async fn main() { +async fn main() -> Result<(), anyhow::Error> { setup_trace_logger(); - listen(router()).await; + listen(router().await?).await; + Ok(()) } +// feather icons +const FEATHER_ICON_LAYOUT: &str = r#""#; + +const FEATHER_ICON_LOGIN: &str = r#""#; + #[instrument] async fn index() -> Html { Html( html! { head { link rel="stylesheet" href="/assets/styles.css" {} + link rel="icon" href="/assets/favicon.svg" {} } header class="flex" { nav class="flex" { h1 { a href="/" { "lyrs" } } - ul class="flex" - { - a href="/login" { "Login" } - } + // ul class="flex" + // { + // a href="/login" { "Login" } + // } } nav class="flex" { ul class="flex" { - a href="/register" { "Register" } - a href="/login" { "Login" } + a href="/dashboard" { + (PreEscaped(FEATHER_ICON_LAYOUT)) + "Dashboard" + } + a href="/login" { + (PreEscaped(FEATHER_ICON_LOGIN)) + "Login" + } } } } + main class="prose" { + h1 { "Manage live lyrics and music displays" } + p { "Stop struggling to share the same messy set of PowerPoint files or Google Presentations. Make editing and controlling your live lyrics and music displays easy and simple." } + ul { + li { "Live collaboration with your team" } + li { "Fully compatible with any device" } + li { "Simple workflow" } + li { "Dark theme and light theme" } + li { "Generous free plan" } + li { "Lightweight and fast" } + } + section class="flex gap" { + a class="button bg-primary" href="/register/anonymous" { "Try now" } + a class="button" href="/login" { "Login" } + } + } } .into_string(), ) diff --git a/src/schema.rs b/src/schema.rs new file mode 100644 index 0000000..b4dc1a5 --- /dev/null +++ b/src/schema.rs @@ -0,0 +1,9 @@ +// @generated automatically by Diesel CLI. + +diesel::table! { + users (id) { + id -> Nullable, + name -> Nullable, + hashed_password -> Nullable, + } +}