From 7aefedf993f22b3b8bc45a234a6bbf1f63ece955 Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Wed, 26 Jul 2023 17:10:52 -0700 Subject: [PATCH] Use Julids for DbId. First phase just does a typedef of "DbId = Julid", and confirms the plugin will load into sqlite. All tests pass. Next phase removes client-side generation of IDs. --- .gitignore | 1 + Cargo.lock | 289 +++++++++++++++++++++++--- Cargo.toml | 6 +- migrations/20230426221940_init.up.sql | 6 +- src/db.rs | 5 +- src/db_id.rs | 214 ------------------- src/import_utils.rs | 2 +- src/lib.rs | 3 +- src/signup.rs | 7 +- src/watches/handlers.rs | 3 +- 10 files changed, 277 insertions(+), 259 deletions(-) delete mode 100644 src/db_id.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..83e97b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/libjulid.so diff --git a/Cargo.lock b/Cargo.lock index 16e7123..ee31571 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,6 +234,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "auto-future" version = "1.0.0" @@ -439,6 +450,29 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "clap 3.2.25", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -520,6 +554,15 @@ version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -545,6 +588,32 @@ dependencies = [ "winapi", ] +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "strsim", + "termcolor", + "textwrap", +] + [[package]] name = "clap" version = "4.3.19" @@ -564,7 +633,7 @@ checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" dependencies = [ "anstream", "anstyle", - "clap_lex", + "clap_lex 0.5.0", "strsim", "unicase", "unicode-width", @@ -582,6 +651,15 @@ dependencies = [ "syn 2.0.27", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.5.0" @@ -754,6 +832,19 @@ dependencies = [ "serde", ] +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -958,6 +1049,18 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.0" @@ -974,7 +1077,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f" dependencies = [ - "hashbrown", + "hashbrown 0.14.0", ] [[package]] @@ -1011,6 +1114,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.2" @@ -1109,6 +1221,12 @@ dependencies = [ "libm", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.27" @@ -1165,6 +1283,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.0.0" @@ -1172,7 +1300,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.0", ] [[package]] @@ -1181,7 +1309,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.2", "rustix", "windows-sys", ] @@ -1210,6 +1338,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "julid-rs" +version = "0.1.6" +dependencies = [ + "rand", + "serde", + "sqlite-loadable", + "sqlx", +] + [[package]] name = "justerror" version = "1.1.0" @@ -1230,12 +1368,28 @@ dependencies = [ "spin 0.5.2", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + [[package]] name = "libm" version = "0.2.7" @@ -1421,7 +1575,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.2", "libc", ] @@ -1454,6 +1608,12 @@ dependencies = [ "syn 2.0.27", ] +[[package]] +name = "os_str_bytes" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" + [[package]] name = "overload" version = "0.1.1" @@ -1500,6 +1660,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1743,6 +1909,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.4" @@ -1825,18 +1997,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.175" +version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" +checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.175" +version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" +checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" dependencies = [ "proc-macro2", "quote", @@ -1929,6 +2101,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -2009,6 +2187,40 @@ dependencies = [ "unicode_categories", ] +[[package]] +name = "sqlite-loadable" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a916b7bb8738eef189dea88731b619b80bf3f62b3acf05138fa43fbf8621cc94" +dependencies = [ + "bitflags 1.3.2", + "serde", + "serde_json", + "sqlite-loadable-macros", + "sqlite3ext-sys", +] + +[[package]] +name = "sqlite-loadable-macros" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98bc75a8d6fd24f6a2cfea34f28758780fa17279d3051eec926efa381971e48" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sqlite3ext-sys" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afdc2b3dc08f16d6eecf8aa07d19975a268603ab1cca67d3f9b4172c507cf16" +dependencies = [ + "bindgen", + "cc", +] + [[package]] name = "sqlx" version = "0.7.1" @@ -2032,7 +2244,6 @@ dependencies = [ "atoi", "byteorder", "bytes", - "chrono", "crc", "crossbeam-queue", "dotenvy", @@ -2045,7 +2256,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap", + "indexmap 2.0.0", "log", "memchr", "once_cell", @@ -2059,7 +2270,6 @@ dependencies = [ "smallvec", "sqlformat", "thiserror", - "time", "tokio", "tokio-stream", "tracing", @@ -2098,7 +2308,6 @@ dependencies = [ "sha2 0.10.7", "sqlx-core", "sqlx-mysql", - "sqlx-postgres", "sqlx-sqlite", "syn 1.0.109", "tempfile", @@ -2117,7 +2326,6 @@ dependencies = [ "bitflags 2.3.3", "byteorder", "bytes", - "chrono", "crc", "digest 0.10.7", "dotenvy", @@ -2145,7 +2353,6 @@ dependencies = [ "sqlx-core", "stringprep", "thiserror", - "time", "tracing", "whoami", ] @@ -2160,7 +2367,6 @@ dependencies = [ "base64 0.21.2", "bitflags 2.3.3", "byteorder", - "chrono", "crc", "dotenvy", "etcetera", @@ -2186,7 +2392,6 @@ dependencies = [ "sqlx-core", "stringprep", "thiserror", - "time", "tracing", "whoami", ] @@ -2198,7 +2403,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2" dependencies = [ "atoi", - "chrono", "flume", "futures-channel", "futures-core", @@ -2210,7 +2414,6 @@ dependencies = [ "percent-encoding", "serde", "sqlx-core", - "time", "tracing", "url", ] @@ -2278,6 +2481,21 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + [[package]] name = "thiserror" version = "1.0.44" @@ -2528,15 +2746,6 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" -[[package]] -name = "ulid" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13a3aaa69b04e5b66cc27309710a569ea23593612387d67daaf102e73aa974fd" -dependencies = [ - "rand", -] - [[package]] name = "unicase" version = "2.6.0" @@ -2727,7 +2936,8 @@ dependencies = [ "axum-macros", "axum-test", "chrono", - "clap", + "clap 4.3.19", + "julid-rs", "justerror", "optional_optional_user", "password-hash", @@ -2744,10 +2954,20 @@ dependencies = [ "tower-http", "tracing", "tracing-subscriber", - "ulid", "unicode-segmentation", ] +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + [[package]] name = "whoami" version = "1.4.1" @@ -2770,6 +2990,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 090ce62..456de10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,11 +18,13 @@ axum-login = { git = "https://github.com/nebkor/axum-login", branch = "sqlx-0.7" axum-macros = "0.3" chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } clap = { version = "4", features = ["derive", "env", "unicode", "suggestions", "usage"] } +julid-rs = { path = "../julid" } justerror = "1" password-hash = { version = "0.5", features = ["std", "getrandom"] } rand = "0.8" +rand_distr = "0.4" serde = { version = "1", features = ["derive"] } -sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio-rustls", "sqlite", "chrono", "time"] } +sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio-rustls", "sqlite"] } thiserror = "1" tokio = { version = "1", features = ["full", "tracing"], default-features = false } tokio-retry = "0.3" @@ -31,9 +33,7 @@ tower = { version = "0.4", features = ["util", "timeout"], default-features = fa tower-http = { version = "0.4", features = ["add-extension", "trace"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } -ulid = { version = "1", features = ["rand"] } unicode-segmentation = "1" -rand_distr = "0.4" [dev-dependencies] axum-test = "9" diff --git a/migrations/20230426221940_init.up.sql b/migrations/20230426221940_init.up.sql index b1f6a81..77fe487 100644 --- a/migrations/20230426221940_init.up.sql +++ b/migrations/20230426221940_init.up.sql @@ -5,7 +5,7 @@ -- users create table if not exists users ( - id blob not null primary key, + id blob not null primary key default (julid_new()), username text not null unique, displayname text, email text, @@ -16,7 +16,7 @@ create table if not exists users ( -- table of things to watch create table if not exists watches ( - id blob not null primary key, + id blob not null primary key default (julid_new()), kind int not null, -- enum for movie or tv show or whatev title text not null, metadata_url text, -- possible url for imdb or other metadata-esque site to show the user @@ -52,7 +52,7 @@ create table if not exists follows ( ); create table if not exists watch_notes ( - id blob not null primary key, -- a user can have multiple notes about the same thing + id blob not null primary key default (julid_new()), -- a user can have multiple notes about the same thing user blob not null, watch blob not null, note blob, diff --git a/src/db.rs b/src/db.rs index be8762b..1a34afa 100644 --- a/src/db.rs +++ b/src/db.rs @@ -12,7 +12,7 @@ use sqlx::{ SqlitePool, }; -use crate::{db_id::DbId, User}; +use crate::{DbId, User}; const MAX_CONNS: u32 = 200; const MIN_CONNS: u32 = 5; @@ -49,6 +49,9 @@ pub fn get_db_pool() -> SqlitePool { .journal_mode(SqliteJournalMode::Wal) .synchronous(sqlx::sqlite::SqliteSynchronous::Normal) .filename(&db_filename) + // need to build this out of band and put it in the project root; see instructions at + // https://gitlab.com/nebkor/julid + .extension("./libjulid") .busy_timeout(Duration::from_secs(TIMEOUT)) .create_if_missing(true); diff --git a/src/db_id.rs b/src/db_id.rs deleted file mode 100644 index 24ba42d..0000000 --- a/src/db_id.rs +++ /dev/null @@ -1,214 +0,0 @@ -use std::{ - borrow::Cow, - fmt::{Debug, Display}, -}; - -use chrono::Utc; -use serde::{de::Visitor, Deserialize, Serialize}; -use sqlx::{ - encode::IsNull, - sqlite::{SqliteArgumentValue, SqliteValueRef}, - Decode, Encode, Sqlite, -}; -use ulid::Ulid; - -#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct DbId(pub Ulid); - -impl DbId { - pub fn bytes(&self) -> [u8; 16] { - self.to_be_bytes() - } - - pub fn to_be_bytes(self) -> [u8; 16] { - self.0 .0.to_be_bytes() - } - - pub fn is_nil(&self) -> bool { - self.0.is_nil() - } - - pub fn new() -> Self { - Self(Ulid::new()) - } - - pub fn from_string(s: &str) -> Result { - let id = Ulid::from_string(s)?; - Ok(id.into()) - } - - pub fn as_string(&self) -> String { - self.0.to_string() - } - - pub fn created_at(&self) -> chrono::DateTime { - self.0.datetime().into() - } -} - -//-************************************************************************ -// standard trait impls -//-************************************************************************ - -impl Display for DbId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0.to_string()) - } -} - -impl Debug for DbId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("DbId").field(&self.as_string()).finish() - } -} - -impl From for DbId { - fn from(value: Ulid) -> Self { - DbId(value) - } -} - -impl From for DbId { - fn from(value: u128) -> Self { - DbId(value.into()) - } -} - -//-************************************************************************ -// sqlx traits for going in and out of the db -//-************************************************************************ - -impl sqlx::Type for DbId { - fn type_info() -> ::TypeInfo { - <&[u8] as sqlx::Type>::type_info() - } -} - -impl<'q> Encode<'q, Sqlite> for DbId { - fn encode_by_ref(&self, args: &mut Vec>) -> IsNull { - args.push(SqliteArgumentValue::Blob(Cow::Owned(self.bytes().to_vec()))); - IsNull::No - } -} - -impl Decode<'_, Sqlite> for DbId { - fn decode(value: SqliteValueRef<'_>) -> Result { - let bytes = <&[u8] as Decode>::decode(value)?; - let bytes: [u8; 16] = bytes.try_into().unwrap_or_default(); - Ok(u128::from_be_bytes(bytes).into()) - } -} - -//-************************************************************************ -// serde traits -//-************************************************************************ -impl Serialize for DbId { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_bytes(&self.bytes()) - } -} - -struct DbIdVisitor; - -impl<'de> Visitor<'de> for DbIdVisitor { - type Value = DbId; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("16 bytes") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - match std::convert::TryInto::<[u8; 16]>::try_into(v) { - Ok(v) => Ok(u128::from_be_bytes(v).into()), - Err(_) => Err(serde::de::Error::invalid_length(v.len(), &self)), - } - } - - fn visit_string(self, v: String) -> Result - where - E: serde::de::Error, - { - DbId::from_string(&v) - .map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Str(&v), &self)) - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - DbId::from_string(v) - .map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Str(v), &self)) - } - - fn visit_byte_buf(self, v: Vec) -> Result - where - E: serde::de::Error, - { - let len = v.len(); - match std::convert::TryInto::<[u8; 16]>::try_into(v) { - Ok(v) => Ok(u128::from_be_bytes(v).into()), - Err(_) => Err(serde::de::Error::invalid_length(len, &self)), - } - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: serde::de::SeqAccess<'de>, - { - let mut raw_bytes_from_db = [0u8; 16]; - let size = seq.size_hint().unwrap_or(0); - let mut count = 0; - while let Some(val) = seq.next_element()? { - if count > 15 { - break; - } - raw_bytes_from_db[count] = val; - count += 1; - } - if count != 16 || size > 16 { - let sz = if count < 16 { count } else { size }; - Err(serde::de::Error::invalid_length(sz, &self)) - } else { - Ok(u128::from_be_bytes(raw_bytes_from_db).into()) - } - } -} - -impl<'de> Deserialize<'de> for DbId { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_bytes(DbIdVisitor) - } -} - -//-************************************************************************ -// serialization tests -//-************************************************************************ - -#[cfg(test)] -mod test { - use serde_test::{assert_tokens, Token}; - - use super::*; - - #[test] - fn test_ser_de() { - let bytes: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - let id: DbId = u128::from_be_bytes(bytes).into(); - - assert_tokens( - &id, - &[Token::Bytes(&[ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - ])], - ); - } -} diff --git a/src/import_utils.rs b/src/import_utils.rs index f4e2b4c..2772538 100644 --- a/src/import_utils.rs +++ b/src/import_utils.rs @@ -1,6 +1,6 @@ use sqlx::{query_scalar, SqlitePool}; -use crate::{db_id::DbId, util::year_to_epoch, ShowKind, User, Watch, WatchQuest}; +use crate::{util::year_to_epoch, DbId, ShowKind, User, Watch, WatchQuest}; const USER_EXISTS_QUERY: &str = "select count(*) from users where id = $1"; diff --git a/src/lib.rs b/src/lib.rs index c1e891d..ff5d1b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,6 @@ pub mod test_utils; /// Some public interfaces for interacting with the database outside of the web /// app pub use db::get_db_pool; -pub use db_id::DbId; pub mod import_utils; pub use users::User; pub use watches::{ShowKind, Watch, WatchQuest}; @@ -18,7 +17,6 @@ pub type WWRouter = axum::Router; // everything else is private to the crate mod db; -mod db_id; mod generic_handlers; mod login; mod signup; @@ -32,6 +30,7 @@ use optional_optional_user::OptionalOptionalUser; use templates::*; use watches::templates::*; +pub type DbId = julid::Julid; type AuthContext = axum_login::extractors::AuthContext>; /// Returns the router to be used as a service or test object, you do you. diff --git a/src/signup.rs b/src/signup.rs index 7e217a3..096cef3 100644 --- a/src/signup.rs +++ b/src/signup.rs @@ -110,7 +110,7 @@ pub async fn post_create_user( let id = DbId::new(); let user = create_user(username, &displayname, &email, password, &pool, id).await?; - let now = user.id.created_at(); + let now = user.id.timestamp(); tracing::debug!("created {user:?} at {now:?}"); let id = user.id.as_string(); let location = format!("/signup_success/{id}"); @@ -137,7 +137,7 @@ pub async fn get_signup_success( let mut resp = SignupSuccessPage(user.clone()).into_response(); - if user.username.is_empty() || id.is_nil() { + if user.username.is_empty() || id.is_alpha() { // redirect to front page if we got here without a valid user ID *resp.status_mut() = StatusCode::SEE_OTHER; resp.headers_mut().insert("Location", "/".parse().unwrap()); @@ -267,7 +267,8 @@ mod test { let server = server_with_pool(&pool).await; let user = get_test_user(); - let id = user.id.0.to_string(); + let id = user.id.to_string(); + dbg!(&id); let path = format!("/signup_success/{id}"); diff --git a/src/watches/handlers.rs b/src/watches/handlers.rs index b5b5aa3..df1ef11 100644 --- a/src/watches/handlers.rs +++ b/src/watches/handlers.rs @@ -8,9 +8,8 @@ use sqlx::{query, query_as, SqlitePool}; use super::templates::{AddNewWatchPage, GetWatchPage, SearchWatchesPage}; use crate::{ - db_id::DbId, util::{empty_string_as_none, year_to_epoch}, - AuthContext, MyWatchesPage, ShowKind, Watch, WatchQuest, + AuthContext, DbId, MyWatchesPage, ShowKind, Watch, WatchQuest, }; //-************************************************************************