use crate::impl_str_enum;
use crate::model::user::{Metal, to_metal};
use crate::utils::error::Error;
use serde::{Deserialize, Deserializer};
use serde_json::Value;
use std::str::FromStr;
#[derive(Clone, Debug)]
pub enum ClientType {
Web,
PC,
Mobile,
Windows,
MacOs,
Linux,
Ios,
Android,
Idea,
Chrome,
Edge,
VSCode,
Python,
Golang,
Rust,
Harmony,
Cli,
Bird,
IceNet,
ElvesOnline,
Other,
}
pub enum ChatContentType {
Markdown,
Html,
}
#[repr(u8)]
pub enum ChatRoomMessageMode {
Context = 0,
Before = 1,
After = 2,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ChatRoomMessageType {
Online,
DiscussChanged,
Revoke,
Msg,
RedPacket,
RedPacketStatus,
Barrager,
Custom,
}
#[derive(Clone, Debug)]
pub struct CustomMsg {
pub message: String,
}
pub struct DiscussMsg;
#[derive(Clone, Debug)]
pub struct RevokeMsg {
pub msg: String,
}
#[derive(Clone, Debug)]
pub struct BarragerCost {
pub cost: u32,
pub unit: String,
}
pub struct WeatherData {
pub date: String,
pub code: WeatherCode,
pub min: String,
pub max: String,
}
pub struct ChatRoomSource {
pub client: String,
pub version: String,
}
#[derive(Clone, Debug)]
pub enum WeatherCode {
ClearDay,
ClearNight,
Cloudy,
Dust,
Fog,
HeavyHaze,
HeavyRain,
HeavySnow,
LightHaze,
LightRain,
LightSnow,
ModerateHaze,
ModerateRain,
ModerateSnow,
PartlyCloudyDay,
PartlyCloudyNight,
Sand,
StormRain,
StormSnow,
Wind,
}
#[derive(Clone, Debug)]
#[allow(non_snake_case)]
pub struct ChatRoomMsg<T = Value> {
pub r#type: ChatRoomMessageType,
pub oId: String,
pub time: String,
pub userOId: String,
pub userName: String,
pub userNickname: String,
pub userAvatarURL: String,
pub sysMetal: Vec<Metal>,
pub content: T,
pub md: String,
pub client: String,
pub via: ClientType,
}
#[derive(Clone, Debug, Deserialize)]
#[allow(non_snake_case)]
pub struct BarragerMsg {
pub userName: String,
pub userNickname: String,
pub barragerContent: String,
pub barragerColor: String,
pub userAvatarURL: String,
pub userAvatarURL200: String,
pub userAvatarURL48: String,
pub userAvatarURL210: String,
}
#[derive(Clone, Debug)]
#[allow(non_snake_case)]
pub struct OnlineInfo {
pub homePage: String,
pub userAvatarURL: String,
pub userName: String,
}
impl_str_enum!(ClientType {
Web => "Web",
PC => "PC",
Mobile => "Mobile",
Windows => "Windows",
MacOs => "macOS",
Linux => "Linux",
Ios => "iOS",
Android => "Android",
Idea => "IDEA",
Chrome => "Chrome",
Edge => "Edge",
VSCode => "VSCode",
Python => "Python",
Golang => "Golang",
Rust => "Rust",
Harmony => "Harmony",
Cli => "CLI",
Bird => "Bird",
IceNet => "IceNet",
ElvesOnline => "ElvesOnline",
Other => "Other",
});
impl_str_enum!(ChatContentType {
Markdown => "Markdown",
Html => "Html",
});
impl_str_enum!(ChatRoomMessageType {
Online => "online",
DiscussChanged => "discussChanged",
Revoke => "revoke",
Msg => "msg",
RedPacket => "redPacket",
RedPacketStatus => "redPacketStatus",
Barrager => "barrager",
Custom => "customMessage",
});
impl_str_enum!(WeatherCode {
ClearDay => "CLEAR_DAY",
ClearNight => "CLEAR_NIGHT",
Cloudy => "CLOUDY",
Dust => "DUST",
Fog => "FOG",
HeavyHaze => "HEAVY_HAZE",
HeavyRain => "HEAVY_RAIN",
HeavySnow => "HEAVY_SNOW",
LightHaze => "LIGHT_HAZE",
LightRain => "LIGHT_RAIN",
LightSnow => "LIGHT_SNOW",
ModerateHaze => "MODERATE_HAZE",
ModerateRain => "MODERATE_RAIN",
ModerateSnow => "MODERATE_SNOW",
PartlyCloudyDay => "PARTLY_CLOUDY_DAY",
PartlyCloudyNight => "PARTLY_CLOUDY_NIGHT",
Sand => "SAND",
StormRain => "STORM_RAIN",
StormSnow => "STORM_SNOW",
Wind => "WIND",
});
impl_str_enum!(ChatRoomMessageMode{
Context => "0",
Before => "1",
After => "2",
});
impl Default for ChatRoomSource {
fn default() -> Self {
Self {
client: "Other".to_string(),
version: "latest".to_string(),
}
}
}
impl ChatRoomMsg {
pub fn from_value(value: &Value) -> Result<Self, Error> {
serde_json::from_value(value.clone())
.map_err(|e| Error::Parse(format!("Failed to parse ChatRoomMsg: {}", e)))
}
pub fn name(&self) -> &str {
if self.userNickname.is_empty() {
&self.userName
} else {
&self.userNickname
}
}
}
impl BarragerMsg {
pub fn from_value(value: &Value) -> Result<Self, Error> {
serde_json::from_value(value.clone())
.map_err(|e| Error::Parse(format!("Failed to parse BarragerMsg: {}", e)))
}
}
fn parse_content(content: &str) -> (ChatRoomMessageType, Value) {
if let Ok(data) = serde_json::from_str::<Value>(content) {
if let Some(msg_type_str) = data["msgType"].as_str() {
match msg_type_str {
"redPacket" => (ChatRoomMessageType::RedPacket, data),
"music" => (ChatRoomMessageType::Msg, data),
"weather" => (ChatRoomMessageType::Msg, data),
_ => (ChatRoomMessageType::Msg, Value::String(content.to_string())),
}
} else {
(ChatRoomMessageType::Msg, Value::String(content.to_string()))
}
} else {
(ChatRoomMessageType::Msg, Value::String(content.to_string()))
}
}
impl<'de> Deserialize<'de> for ChatRoomMsg<Value> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Raw {
oId: String,
time: String,
userOId: Value,
userName: String,
userNickname: String,
userAvatarURL: String,
sysMetal: Option<Value>,
content: String,
md: Option<String>,
client: Option<String>,
}
let raw = Raw::deserialize(deserializer)?;
let (r#type, content) = parse_content(&raw.content);
let via = raw
.client
.as_ref()
.and_then(|s| ClientType::from_str(s).ok())
.unwrap_or(ClientType::Other);
let client = raw.client.unwrap_or(ClientType::Rust.as_str().to_string());
let sys_metal = raw
.sysMetal
.as_ref()
.and_then(|v| v.as_str())
.map(|s| to_metal(s))
.unwrap_or(Ok(vec![]))
.unwrap_or(vec![]);
Ok(ChatRoomMsg {
r#type,
oId: raw.oId,
time: raw.time,
userOId: raw.userOId.to_string(),
userName: raw.userName,
userNickname: raw.userNickname,
userAvatarURL: raw.userAvatarURL,
sysMetal: sys_metal,
content,
md: raw.md.unwrap_or("".to_string()),
client,
via,
})
}
}
impl BarragerCost {
pub fn from_value(value: &Value) -> Self {
let content = value
.get("data")
.and_then(|v| v.as_str())
.unwrap_or("5积分");
let parts: Vec<&str> = content
.split(|c: char| !c.is_alphanumeric())
.filter(|s| !s.is_empty())
.collect();
Self {
cost: parts[0].parse::<u32>().unwrap_or(0),
unit: parts[1].to_string(),
}
}
}