diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dfca90..524e877 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,18 @@ Procedure when bumping the version number: ## Unreleased +## v0.6.1 - 2025-02-23 + +### Changed + +- Updated set of emoji names + +### Fixed + +- Nick hue hashing algorithm in some edge cases + +## v0.6.0 - 2025-02-21 + ### Added - `api::Time::from_timestamp` diff --git a/Cargo.toml b/Cargo.toml index 0ae6832..cf65579 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,34 +1,34 @@ [package] name = "euphoxide" -version = "0.5.1" +version = "0.6.1" edition = "2021" [features] bot = ["dep:async-trait", "dep:clap", "dep:cookie"] [dependencies] -async-trait = { version = "0.1.83", optional = true } -caseless = "0.2.1" +async-trait = { version = "0.1.86", optional = true } +caseless = "0.2.2" cookie = { version = "0.18.1", optional = true } futures-util = { version = "0.3.31", default-features = false, features = ["sink"] } -jiff = { version = "0.1.15", features = ["serde"] } -log = "0.4.22" -serde = { version = "1.0.215", features = ["derive"] } -serde_json = "1.0.133" -tokio = { version = "1.42.0", features = ["time", "sync", "macros", "rt"] } -tokio-stream = "0.1.16" -tokio-tungstenite = { version = "0.24.0", features = ["rustls-tls-native-roots"] } +jiff = { version = "0.2.1", features = ["serde"] } +log = "0.4.25" +serde = { version = "1.0.218", features = ["derive"] } +serde_json = "1.0.139" +tokio = { version = "1.43.0", features = ["time", "sync", "macros", "rt"] } +tokio-stream = "0.1.17" +tokio-tungstenite = { version = "0.26.2", features = ["rustls-tls-native-roots"] } unicode-normalization = "0.1.24" [dependencies.clap] -version = "4.5.22" +version = "4.5.30" optional = true default-features = false features = ["std", "derive", "deprecated"] [dev-dependencies] # For example bot -rustls = "0.23.19" -tokio = { version = "1.42.0", features = ["rt-multi-thread"] } +rustls = "0.23.23" +tokio = { version = "1.43.0", features = ["rt-multi-thread"] } [[example]] name = "testbot_instance" diff --git a/src/conn.rs b/src/conn.rs index 6d88827..7255d60 100644 --- a/src/conn.rs +++ b/src/conn.rs @@ -427,7 +427,7 @@ impl Conn { } tungstenite::Message::Ping(_) => {} tungstenite::Message::Pong(payload) => { - if self.last_ws_ping_payload == Some(payload) { + if self.last_ws_ping_payload == Some(payload.to_vec()) { self.last_ws_ping_replied_to = true; } } @@ -528,7 +528,9 @@ impl Conn { let ws_payload = now.as_millisecond().to_be_bytes().to_vec(); self.last_ws_ping_payload = Some(ws_payload.clone()); self.last_ws_ping_replied_to = false; - self.ws.send(tungstenite::Message::Ping(ws_payload)).await?; + self.ws + .send(tungstenite::Message::Ping(ws_payload.into())) + .await?; // Send new euph ping let euph_payload = Time::from_timestamp(now); @@ -561,7 +563,7 @@ impl Conn { .into_packet()?; debug!(target: "euphoxide::conn::full", "Sending {packet:?}"); - let msg = tungstenite::Message::Text(serde_json::to_string(&packet)?); + let msg = tungstenite::Message::Text(serde_json::to_string(&packet)?.into()); self.ws.send(msg).await?; let _ = reply_tx.send(self.replies.wait_for(id)); @@ -579,7 +581,7 @@ impl Conn { .into_packet()?; debug!(target: "euphoxide::conn::full", "Sending {packet:?}"); - let msg = tungstenite::Message::Text(serde_json::to_string(&packet)?); + let msg = tungstenite::Message::Text(serde_json::to_string(&packet)?.into()); self.ws.send(msg).await?; Ok(()) diff --git a/src/emoji.json b/src/emoji.json index e9f8068..b26a1f7 100644 --- a/src/emoji.json +++ b/src/emoji.json @@ -878,7 +878,7 @@ "fist_raised": "270a", "fist_right": "1f91c", "five": "35-fe0f-20e3", - "fjafjkldskf7jkfdj": "1f577", + "fjafjkldskf7jkfdj": "1f577-fe0f", "flags": "1f38f", "flamingo": "1f9a9", "flashlight": "1f526", @@ -958,6 +958,7 @@ "georgia": "1f1ec-1f1ea", "ghana": "1f1ec-1f1ed", "ghost": "1f47b", + "ghoti": "1f41f", "gibraltar": "1f1ec-1f1ee", "gift": "1f381", "gift_heart": "1f49d", @@ -2985,7 +2986,7 @@ "speaking_head": "1f5e3-fe0f", "speech_balloon": "1f4ac", "speedboat": "1f6a4", - "spider": "1f577", + "spider": "1f577-fe0f", "spider_web": "1f578-fe0f", "spiral_calendar": "1f5d3-fe0f", "spiral_notepad": "1f5d2-fe0f", diff --git a/src/nick.rs b/src/nick.rs index 03ada70..fc652bf 100644 --- a/src/nick.rs +++ b/src/nick.rs @@ -5,9 +5,10 @@ use unicode_normalization::UnicodeNormalization; use crate::emoji::Emoji; -/// Does not remove emoji. -fn hue_normalize(text: &str) -> String { - text.chars() +fn hue_normalize(emoji: &Emoji, text: &str) -> String { + emoji + .remove(text) + .chars() .filter(|&c| c.is_ascii_alphanumeric() || c == '_' || c == '-') .map(|c| c.to_ascii_lowercase()) .collect() @@ -15,7 +16,7 @@ fn hue_normalize(text: &str) -> String { /// A re-implementation of [euphoria's nick hue hashing algorithm][0]. /// -/// [0]: https://github.com/CylonicRaider/heim/blob/master/client/lib/hueHash.js +/// [0]: https://github.com/CylonicRaider/heim/blob/097a1fde89ada53de2b70e51e635257f27956e4e/client/lib/heim/hueHash.js fn hue_hash(text: &str, offset: i64) -> u8 { let mut val = 0_i32; for bibyte in text.encode_utf16() { @@ -35,7 +36,13 @@ const GREENIE_OFFSET: i64 = 148 - 192; // 148 - hue_hash("greenie", 0) /// This should be slightly faster than [`hue`] but produces incorrect results /// if any colon-delimited emoji are present. pub fn hue_without_removing_emoji(nick: &str) -> u8 { - let normalized = hue_normalize(nick); + // An emoji-less version of hue_normalize + let normalized = nick + .chars() + .filter(|&c| c.is_ascii_alphanumeric() || c == '_' || c == '-') + .map(|c| c.to_ascii_lowercase()) + .collect::(); + if normalized.is_empty() { hue_hash(nick, GREENIE_OFFSET) } else { @@ -48,9 +55,14 @@ pub fn hue_without_removing_emoji(nick: &str) -> u8 { /// This is a reimplementation of [euphoria's nick hue hashing algorithm][0]. It /// should always return the same value as the official client's implementation. /// -/// [0]: https://github.com/CylonicRaider/heim/blob/978c921063e6b06012fc8d16d9fbf1b3a0be1191/client/lib/hueHash.js +/// [0]: https://github.com/CylonicRaider/heim/blob/097a1fde89ada53de2b70e51e635257f27956e4e/client/lib/heim/hueHash.js pub fn hue(emoji: &Emoji, nick: &str) -> u8 { - hue_without_removing_emoji(&emoji.remove(nick)) + let normalized = hue_normalize(emoji, nick); + if normalized.is_empty() { + hue_hash(nick, GREENIE_OFFSET) + } else { + hue_hash(&normalized, GREENIE_OFFSET) + } } /// Normalize a nick to a form that can be compared against other nicks.