diff --git a/Cargo.lock b/Cargo.lock index fcf9b38..86eccc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1211,6 +1211,19 @@ dependencies = [ "slab", ] +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2035,6 +2048,19 @@ version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "loop9" version = "0.1.5" @@ -3210,6 +3236,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -3461,6 +3493,15 @@ dependencies = [ "serde", ] +[[package]] +name = "snowflaked" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "398d462c4c454399be452039b24b0aa0ecb4c7a57f6ae615f5d25de2b032f850" +dependencies = [ + "loom", +] + [[package]] name = "socket2" version = "0.5.8" @@ -3773,10 +3814,10 @@ dependencies = [ "chrono", "comrak", "hex_fmt", - "num-bigint", "rand 0.9.1", "serde", "sha2", + "snowflaked", "uuid 1.16.0", ] @@ -4633,6 +4674,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -4695,6 +4745,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -4727,6 +4792,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -4739,6 +4810,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -4751,6 +4828,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -4775,6 +4858,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -4787,6 +4876,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -4799,6 +4894,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -4811,6 +4912,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/crates/app/src/public/html/components.html b/crates/app/src/public/html/components.html index c57660f..2412e03 100644 --- a/crates/app/src/public/html/components.html +++ b/crates/app/src/public/html/components.html @@ -234,7 +234,7 @@ and show_community and community.id != config.town_square or question %} {% else %}
{{ icon "triangle-alert" }} {{ post.context.content_warning }} diff --git a/crates/core/src/model/auth.rs b/crates/core/src/model/auth.rs index f565fa6..0bcf54b 100644 --- a/crates/core/src/model/auth.rs +++ b/crates/core/src/model/auth.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use totp_rs::TOTP; use tetratto_shared::{ hash::{hash_salted, salt}, - snow::AlmostSnowflake, + snow::Snowflake, unix_epoch_timestamp, }; @@ -227,10 +227,7 @@ impl User { let password = hash_salted(password, salt.clone()); Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, username, password, @@ -408,10 +405,7 @@ impl Notification { /// Returns a new [`Notification`]. pub fn new(title: String, content: String, owner: usize) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, title, content, @@ -434,10 +428,7 @@ impl UserFollow { /// Create a new [`UserFollow`]. pub fn new(initiator: usize, receiver: usize) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, initiator, receiver, @@ -465,10 +456,7 @@ impl UserBlock { /// Create a new [`UserBlock`]. pub fn new(initiator: usize, receiver: usize) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, initiator, receiver, @@ -488,10 +476,7 @@ impl IpBlock { /// Create a new [`IpBlock`]. pub fn new(initiator: usize, receiver: String) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, initiator, receiver, @@ -532,10 +517,7 @@ impl UserWarning { /// Create a new [`UserWarning`]. pub fn new(user: usize, moderator: usize, content: String) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, receiver: user, moderator, diff --git a/crates/core/src/model/channels.rs b/crates/core/src/model/channels.rs index 740a0d6..987cd31 100644 --- a/crates/core/src/model/channels.rs +++ b/crates/core/src/model/channels.rs @@ -1,5 +1,5 @@ use serde::{Serialize, Deserialize}; -use tetratto_shared::{snow::AlmostSnowflake, unix_epoch_timestamp}; +use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp}; use super::communities_permissions::CommunityPermission; @@ -30,10 +30,7 @@ impl Channel { /// Create a new [`Channel`]. pub fn new(community: usize, owner: usize, position: usize, title: String) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), community, owner, created: unix_epoch_timestamp() as usize, @@ -84,10 +81,7 @@ impl Message { let now = unix_epoch_timestamp() as usize; Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), channel, owner, created: now, diff --git a/crates/core/src/model/communities.rs b/crates/core/src/model/communities.rs index 5528b71..47e9825 100644 --- a/crates/core/src/model/communities.rs +++ b/crates/core/src/model/communities.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use tetratto_shared::{snow::AlmostSnowflake, unix_epoch_timestamp}; +use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp}; use super::communities_permissions::CommunityPermission; #[derive(Clone, Serialize, Deserialize)] @@ -30,10 +30,7 @@ impl Community { /// Create a new [`Community`]. pub fn new(title: String, owner: usize) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, title: title.clone(), context: CommunityContext { @@ -145,10 +142,7 @@ impl CommunityMembership { /// Create a new [`CommunityMembership`]. pub fn new(owner: usize, community: usize, role: CommunityPermission) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, owner, community, @@ -250,10 +244,7 @@ impl Post { owner: usize, ) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, content, owner, @@ -328,10 +319,7 @@ impl Question { ip: String, ) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, owner, receiver, diff --git a/crates/core/src/model/moderation.rs b/crates/core/src/model/moderation.rs index 9929fed..12b1fbc 100644 --- a/crates/core/src/model/moderation.rs +++ b/crates/core/src/model/moderation.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use tetratto_shared::{snow::AlmostSnowflake, unix_epoch_timestamp}; +use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp}; use super::reactions::AssetType; @@ -15,10 +15,7 @@ impl AuditLogEntry { /// Create a new [`AuditLogEntry`]. pub fn new(moderator: usize, content: String) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, moderator, content, @@ -40,10 +37,7 @@ impl Report { /// Create a new [`Report`]. pub fn new(owner: usize, content: String, asset: usize, asset_type: AssetType) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, owner, content, diff --git a/crates/core/src/model/reactions.rs b/crates/core/src/model/reactions.rs index e615874..8f634af 100644 --- a/crates/core/src/model/reactions.rs +++ b/crates/core/src/model/reactions.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use tetratto_shared::{snow::AlmostSnowflake, unix_epoch_timestamp}; +use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp}; /// All of the items which support reactions. #[derive(Serialize, Deserialize)] @@ -28,10 +28,7 @@ impl Reaction { /// Create a new [`Reaction`]. pub fn new(owner: usize, asset: usize, asset_type: AssetType, is_like: bool) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, owner, asset, diff --git a/crates/core/src/model/requests.rs b/crates/core/src/model/requests.rs index 867c723..ce11f40 100644 --- a/crates/core/src/model/requests.rs +++ b/crates/core/src/model/requests.rs @@ -1,5 +1,5 @@ use serde::{Serialize, Deserialize}; -use tetratto_shared::{snow::AlmostSnowflake, unix_epoch_timestamp}; +use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp}; #[derive(Serialize, Deserialize, PartialEq, Eq)] pub enum ActionType { @@ -32,10 +32,7 @@ impl ActionRequest { /// Create a new [`ActionRequest`]. pub fn new(owner: usize, action_type: ActionType, linked_asset: usize) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, owner, action_type, diff --git a/crates/core/src/model/uploads.rs b/crates/core/src/model/uploads.rs index f4c76a7..5006c97 100644 --- a/crates/core/src/model/uploads.rs +++ b/crates/core/src/model/uploads.rs @@ -1,5 +1,5 @@ use serde::{Serialize, Deserialize}; -use tetratto_shared::{snow::AlmostSnowflake, unix_epoch_timestamp}; +use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp}; #[derive(Serialize, Deserialize)] pub enum MediaType { @@ -27,10 +27,7 @@ impl MediaUpload { /// Create a new [`MediaUpload`]. pub fn new(what: MediaType, owner: usize) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, owner, what, @@ -61,10 +58,7 @@ impl CustomEmoji { is_animated: bool, ) -> Self { Self { - id: AlmostSnowflake::new(1234567890) - .to_string() - .parse::() - .unwrap(), + id: Snowflake::new().to_string().parse::().unwrap(), created: unix_epoch_timestamp() as usize, owner, community, diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index 9c4c940..baa7c8b 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -11,8 +11,8 @@ ammonia = "4.1.0" chrono = "0.4.41" comrak = "0.38.0" hex_fmt = "0.3.0" -num-bigint = "0.4.6" rand = "0.9.1" serde = "1.0.219" sha2 = "0.10.8" +snowflaked = "1.0.3" uuid = { version = "1.16.0", features = ["v4"] } diff --git a/crates/shared/src/snow.rs b/crates/shared/src/snow.rs index 24f21d8..654a438 100644 --- a/crates/shared/src/snow.rs +++ b/crates/shared/src/snow.rs @@ -1,51 +1,29 @@ -//! Almost Snowflake -//! -//! Random IDs which include timestamp information (like Twitter Snowflakes) -//! -//! IDs are generated with 41 bits of an epoch timestamp, 10 bits of a machine/server ID, and 12 bits of randomly generated numbers. -//! -//! ``` -//! tttttttttttttttttttttttttttttttttttttttttiiiiiiiiiirrrrrrrrrrrr... -//! Timestamp ID Seed -//! ``` -use crate::epoch_timestamp; +use std::time::{UNIX_EPOCH, Duration}; use serde::{Deserialize, Serialize}; +use snowflaked::{Builder, Generator}; -use num_bigint::BigInt; -use rand::Rng; - -static SEED_LEN: usize = 12; -// static ID_LEN: usize = 10; +pub const EPOCH_2024: u64 = 1704067200000; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct AlmostSnowflake(String); +pub struct Snowflake(String); -pub fn bigint(input: usize) -> BigInt { - BigInt::from(input) -} +impl Snowflake { + pub fn builder() -> Builder { + Builder::new().epoch(UNIX_EPOCH + Duration::from_millis(EPOCH_2024)) + } -impl AlmostSnowflake { /// Create a new [`AlmostSnowflake`] - pub fn new(server_id: usize) -> Self { - // generate random bytes - let mut bytes = String::new(); - - let mut rng = rand::rng(); - for _ in 1..=SEED_LEN { - bytes.push_str(&rng.random_range(0..10).to_string()) - } - - // build id - let mut id = bigint(epoch_timestamp(2024) as usize) << 22_u128; - id |= bigint((server_id % 1024) << 12); - id |= bigint((bytes.parse::().unwrap() + 1) % 4096); - - // return - Self(id.to_string()) + pub fn new() -> Self { + Self( + Self::builder() + .build::() + .generate::() + .to_string(), + ) } } -impl std::fmt::Display for AlmostSnowflake { +impl std::fmt::Display for Snowflake { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) }