refactor (backend-rs): remove strum derives

This commit is contained in:
naskya 2024-06-06 17:10:39 +09:00
parent f479ffb0e5
commit 642c4cb2c7
No known key found for this signature in database
GPG key ID: 712D413B3A9FED5C
14 changed files with 124 additions and 134 deletions

31
Cargo.lock generated
View file

@ -226,7 +226,6 @@ dependencies = [
"serde",
"serde_json",
"serde_yaml",
"strum 0.26.2",
"sysinfo",
"thiserror",
"tokio",
@ -2644,12 +2643,6 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustversion"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
[[package]]
name = "ryu"
version = "1.0.18"
@ -2712,7 +2705,7 @@ dependencies = [
"serde",
"serde_json",
"sqlx",
"strum 0.25.0",
"strum",
"thiserror",
"time",
"tracing",
@ -3240,28 +3233,6 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
[[package]]
name = "strum"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.66",
]
[[package]]
name = "subtle"
version = "2.5.0"

View file

@ -35,7 +35,6 @@ sea-orm = { version = "0.12.15", default-features = false }
serde = { version = "1.0.203", default-features = false }
serde_json = { version = "1.0.117", default-features = false }
serde_yaml = { version = "0.9.34", default-features = false }
strum = { version = "0.26.2", default-features = false }
syn = { version = "2.0.66", default-features = false }
sysinfo = { version = "0.30.12", default-features = false }
thiserror = { version = "1.0.61", default-features = false }

View file

@ -39,7 +39,6 @@ sea-orm = { workspace = true, features = ["macros", "runtime-tokio-rustls", "sql
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
strum = { workspace = true, features = ["derive"] }
sysinfo = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["fs", "io-std", "io-util", "macros", "process", "rt-multi-thread", "signal", "sync", "time"] }

View file

@ -1365,13 +1365,13 @@ export function updateAntennasOnNewNote(note: Note, noteAuthor: Acct, noteMutedU
export function watchNote(watcherId: string, noteAuthorId: string, noteId: string): Promise<void>
export function unwatchNote(watcherId: string, noteId: string): Promise<void>
export enum PushNotificationKind {
Generic = 'generic',
Chat = 'chat',
ReadAllChats = 'readAllChats',
ReadAllChatsInTheRoom = 'readAllChatsInTheRoom',
ReadNotifications = 'readNotifications',
ReadAllNotifications = 'readAllNotifications',
Mastodon = 'mastodon'
Generic = 0,
Chat = 1,
ReadAllChats = 2,
ReadAllChatsInTheRoom = 3,
ReadNotifications = 4,
ReadAllNotifications = 5,
Mastodon = 6
}
export function sendPushNotification(receiverUserId: string, kind: PushNotificationKind, content: any): Promise<void>
export function publishToChannelStream(channelId: string, userId: string): Promise<void>

View file

@ -4,16 +4,12 @@ use crate::database::{redis_conn, redis_key, RedisConnError};
use redis::{AsyncCommands, RedisError};
use serde::{Deserialize, Serialize};
#[derive(strum::Display, Debug)]
#[cfg_attr(test, derive(Debug))]
pub enum Category {
#[strum(serialize = "fetchUrl")]
FetchUrl,
#[strum(serialize = "blocking")]
Block,
#[strum(serialize = "following")]
Follow,
#[cfg(test)]
#[strum(serialize = "usedOnlyForTesting")]
Test,
}
@ -32,9 +28,15 @@ fn prefix_key(key: &str) -> String {
redis_key(format!("cache:{}", key))
}
#[inline]
fn categorize(category: Category, key: &str) -> String {
format!("{}:{}", category, key)
let prefix = match category {
Category::FetchUrl => "fetchUrl",
Category::Block => "blocking",
Category::Follow => "following",
#[cfg(test)]
Category::Test => "usedOnlyForTesting",
};
format!("{}:{}", prefix, key)
}
#[inline]

View file

@ -32,32 +32,18 @@ fn get_client() -> Result<IsahcWebPushClient, Error> {
.cloned()?)
}
#[derive(strum::Display, PartialEq)]
#[crate::export(string_enum = "camelCase")]
#[crate::export]
pub enum PushNotificationKind {
#[strum(serialize = "notification")]
Generic,
#[strum(serialize = "unreadMessagingMessage")]
Chat,
#[strum(serialize = "readAllMessagingMessages")]
ReadAllChats,
#[strum(serialize = "readAllMessagingMessagesOfARoom")]
ReadAllChatsInTheRoom,
#[strum(serialize = "readNotifications")]
ReadNotifications,
#[strum(serialize = "readAllNotifications")]
ReadAllNotifications,
Mastodon,
}
fn compact_content(
kind: &PushNotificationKind,
mut content: serde_json::Value,
) -> Result<serde_json::Value, Error> {
if kind != &PushNotificationKind::Generic {
return Ok(content);
}
fn compact_content(mut content: serde_json::Value) -> Result<serde_json::Value, Error> {
if !content.is_object() {
return Err(Error::InvalidContent("not a JSON object".to_string()));
}
@ -159,24 +145,40 @@ pub async fn send_push_notification(
.all(db)
.await?;
let use_mastodon_api = matches!(kind, PushNotificationKind::Mastodon);
// TODO: refactoring
let payload = if kind == PushNotificationKind::Mastodon {
let payload = if use_mastodon_api {
// Leave the `content` as it is
serde_json::to_string(content)?
} else {
// Format the `content` passed from the TypeScript backend
// for Firefish push notifications
let label = match kind {
PushNotificationKind::Generic => "notification",
PushNotificationKind::Chat => "unreadMessagingMessage",
PushNotificationKind::ReadAllChats => "readAllMessagingMessages",
PushNotificationKind::ReadAllChatsInTheRoom => "readAllMessagingMessagesOfARoom",
PushNotificationKind::ReadNotifications => "readNotifications",
PushNotificationKind::ReadAllNotifications => "readAllNotifications",
// unreachable
_ => "unknown",
};
format!(
"{{\"type\":\"{}\",\"userId\":\"{}\",\"dateTime\":{},\"body\":{}}}",
kind,
label,
receiver_user_id,
chrono::Utc::now().timestamp_millis(),
serde_json::to_string(&compact_content(&kind, content.clone())?)?
match kind {
PushNotificationKind::Generic =>
serde_json::to_string(&compact_content(content.to_owned())?)?,
_ => serde_json::to_string(&content)?,
}
)
};
tracing::trace!("payload: {}", payload);
let encoding = if kind == PushNotificationKind::Mastodon {
let encoding = if use_mastodon_api {
ContentEncoding::AesGcm
} else {
ContentEncoding::Aes128Gcm
@ -184,13 +186,13 @@ pub async fn send_push_notification(
for subscription in subscriptions.iter() {
if !subscription.send_read_message
&& [
PushNotificationKind::ReadAllChats,
PushNotificationKind::ReadAllChatsInTheRoom,
PushNotificationKind::ReadAllNotifications,
PushNotificationKind::ReadNotifications,
]
.contains(&kind)
&& matches!(
kind,
PushNotificationKind::ReadAllChats
| PushNotificationKind::ReadAllChatsInTheRoom
| PushNotificationKind::ReadAllNotifications
| PushNotificationKind::ReadNotifications
)
{
continue;
}

View file

@ -10,39 +10,44 @@ use crate::config::CONFIG;
use crate::database::{redis_conn, RedisConnError};
use redis::{AsyncCommands, RedisError};
#[derive(strum::Display)]
pub enum Stream {
#[strum(serialize = "internal")]
Internal,
#[strum(serialize = "broadcast")]
CustomEmoji,
#[strum(to_string = "adminStream:{moderator_id}")]
Moderation { moderator_id: String },
#[strum(to_string = "user:{user_id}")]
User { user_id: String },
#[strum(to_string = "channelStream:{channel_id}")]
Channel { channel_id: String },
#[strum(to_string = "noteStream:{note_id}")]
Note { note_id: String },
#[strum(serialize = "notesStream")]
Moderation {
moderator_id: String,
},
User {
user_id: String,
},
Channel {
channel_id: String,
},
Note {
note_id: String,
},
Notes,
#[strum(to_string = "userListStream:{list_id}")]
UserList { list_id: String },
#[strum(to_string = "mainStream:{user_id}")]
Main { user_id: String },
#[strum(to_string = "driveStream:{user_id}")]
Drive { user_id: String },
#[strum(to_string = "antennaStream:{antenna_id}")]
Antenna { antenna_id: String },
#[strum(to_string = "messagingStream:{sender_user_id}-{receiver_user_id}")]
UserList {
list_id: String,
},
Main {
user_id: String,
},
Drive {
user_id: String,
},
Antenna {
antenna_id: String,
},
Chat {
sender_user_id: String,
receiver_user_id: String,
},
#[strum(to_string = "messagingStream:{group_id}")]
GroupChat { group_id: String },
#[strum(to_string = "messagingIndexStream:{user_id}")]
ChatIndex { user_id: String },
GroupChat {
group_id: String,
},
ChatIndex {
user_id: String,
},
}
#[derive(thiserror::Error, Debug)]
@ -59,9 +64,29 @@ pub enum Error {
pub async fn publish_to_stream(
stream: &Stream,
kind: Option<String>,
kind: Option<&str>,
value: Option<String>,
) -> Result<(), Error> {
let channel = match stream {
Stream::Internal => "internal".to_string(),
Stream::CustomEmoji => "broadcast".to_string(),
Stream::Moderation { moderator_id } => format!("adminStream:{moderator_id}"),
Stream::User { user_id } => format!("user:{user_id}"),
Stream::Channel { channel_id } => format!("channelStream:{channel_id}"),
Stream::Note { note_id } => format!("noteStream:{note_id}"),
Stream::Notes => "notesStream".to_string(),
Stream::UserList { list_id } => format!("userListStream:{list_id}"),
Stream::Main { user_id } => format!("mainStream:{user_id}"),
Stream::Drive { user_id } => format!("driveStream:{user_id}"),
Stream::Antenna { antenna_id } => format!("antennaStream:{antenna_id}"),
Stream::Chat {
sender_user_id,
receiver_user_id,
} => format!("messagingStream:{sender_user_id}-{receiver_user_id}"),
Stream::GroupChat { group_id } => format!("messagingStream:{group_id}"),
Stream::ChatIndex { user_id } => format!("messagingIndexStream:{user_id}"),
};
let message = if let Some(kind) = kind {
format!(
"{{\"type\":\"{}\",\"body\":{}}}",
@ -76,28 +101,9 @@ pub async fn publish_to_stream(
.await?
.publish(
&CONFIG.host,
format!("{{\"channel\":\"{}\",\"message\":{}}}", stream, message),
format!("{{\"channel\":\"{}\",\"message\":{}}}", channel, message),
)
.await?;
Ok(())
}
#[cfg(test)]
mod unit_test {
use super::Stream;
use pretty_assertions::assert_eq;
#[test]
fn channel_to_string() {
assert_eq!(Stream::Internal.to_string(), "internal");
assert_eq!(Stream::CustomEmoji.to_string(), "broadcast");
assert_eq!(
Stream::Moderation {
moderator_id: "9tb42br63g5apjcq".to_string()
}
.to_string(),
"adminStream:9tb42br63g5apjcq"
);
}
}

View file

@ -4,7 +4,7 @@ use crate::service::stream::{publish_to_stream, Error, Stream};
pub async fn publish(antenna_id: String, note: &note::Model) -> Result<(), Error> {
publish_to_stream(
&Stream::Antenna { antenna_id },
Some("note".to_string()),
Some("note"),
Some(serde_json::to_string(note)?),
)
.await

View file

@ -4,7 +4,7 @@ use crate::service::stream::{publish_to_stream, Error, Stream};
pub async fn publish(channel_id: String, user_id: String) -> Result<(), Error> {
publish_to_stream(
&Stream::Channel { channel_id },
Some("typing".to_string()),
Some("typing"),
Some(format!("\"{}\"", user_id)),
)
.await

View file

@ -1,15 +1,10 @@
use crate::service::stream::{publish_to_stream, Error, Stream};
#[derive(strum::Display)]
#[crate::export(string_enum = "camelCase")]
pub enum ChatEvent {
#[strum(serialize = "message")]
Message,
#[strum(serialize = "read")]
Read,
#[strum(serialize = "deleted")]
Deleted,
#[strum(serialize = "typing")]
Typing,
}
@ -23,12 +18,19 @@ pub async fn publish(
kind: ChatEvent,
object: &serde_json::Value,
) -> Result<(), Error> {
let kind = match kind {
ChatEvent::Message => "message",
ChatEvent::Read => "read",
ChatEvent::Deleted => "deleted",
ChatEvent::Typing => "typing",
};
publish_to_stream(
&Stream::Chat {
sender_user_id,
receiver_user_id,
},
Some(kind.to_string()),
Some(kind),
Some(serde_json::to_string(object)?),
)
.await

View file

@ -1,11 +1,8 @@
use crate::service::stream::{publish_to_stream, Error, Stream};
#[derive(strum::Display)]
#[crate::export(string_enum = "camelCase")]
pub enum ChatIndexEvent {
#[strum(serialize = "message")]
Message,
#[strum(serialize = "read")]
Read,
}
@ -18,9 +15,14 @@ pub async fn publish(
kind: ChatIndexEvent,
object: &serde_json::Value,
) -> Result<(), Error> {
let kind = match kind {
ChatIndexEvent::Message => "message",
ChatIndexEvent::Read => "read",
};
publish_to_stream(
&Stream::ChatIndex { user_id },
Some(kind.to_string()),
Some(kind),
Some(serde_json::to_string(object)?),
)
.await

View file

@ -21,7 +21,7 @@ pub struct PackedEmoji {
pub async fn publish(emoji: &PackedEmoji) -> Result<(), Error> {
publish_to_stream(
&Stream::CustomEmoji,
Some("emojiAdded".to_string()),
Some("emojiAdded"),
Some(format!("{{\"emoji\":{}}}", serde_json::to_string(emoji)?)),
)
.await

View file

@ -9,9 +9,16 @@ pub async fn publish(
kind: ChatEvent,
object: &serde_json::Value,
) -> Result<(), Error> {
let kind = match kind {
ChatEvent::Message => "message",
ChatEvent::Read => "read",
ChatEvent::Deleted => "deleted",
ChatEvent::Typing => "typing",
};
publish_to_stream(
&Stream::GroupChat { group_id },
Some(kind.to_string()),
Some(kind),
Some(serde_json::to_string(object)?),
)
.await

View file

@ -15,7 +15,7 @@ pub struct AbuseUserReportLike {
pub async fn publish(moderator_id: String, report: &AbuseUserReportLike) -> Result<(), Error> {
publish_to_stream(
&Stream::Moderation { moderator_id },
Some("newAbuseUserReport".to_string()),
Some("newAbuseUserReport"),
Some(serde_json::to_string(report)?),
)
.await