mod dannmu_msg;
mod interact_word;
mod send_gift;
mod super_chat;
mod welcome_guard;
use serde::Deserialize;
use serde_json::Value;
use crate::ws_type::welcome_guard::WelcomeGuard;
pub use self::dannmu_msg::DanmuMessage;
pub use self::interact_word::InteractWord;
pub use self::send_gift::SendGift;
pub use self::super_chat::SuperChatMessage;
#[derive(Debug, Deserialize, Clone)]
pub struct WsStreamCtx {
cmd: Option<String>,
info: Option<Vec<Value>>,
data: Option<WsStreamCtxData>,
#[serde(flatten)]
_v: Value,
}
#[derive(Debug, Deserialize, Clone)]
pub struct WsStreamCtxData {
message: Option<String>,
price: Option<u32>,
start_time: Option<u64>,
time: Option<u32>,
uid: Option<Value>,
user_info: Option<WsStreamCtxDataUser>,
medal_info: Option<WsStreamCtxDataMedalInfo>,
uname: Option<String>,
fans_medal: Option<WsStreamCtxDataMedalInfo>,
action: Option<String>,
#[serde(rename = "giftName")]
gift_name: Option<String>,
num: Option<u64>,
combo_num: Option<u64>,
gift_num: Option<u64>,
combo_send: Box<Option<WsStreamCtxData>>,
guard_level: Option<u64>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct WsStreamCtxDataMedalInfo {
medal_name: Option<String>,
medal_level: Option<u32>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct WsStreamCtxDataUser {
face: String,
uname: String,
}
#[derive(Debug)]
pub enum WsStreamMessageType {
DanmuMsg(DanmuMessage),
WelcomeGuard(WelcomeGuard),
SuperChatMessage(SuperChatMessage),
InteractWord(InteractWord),
SendGift(SendGift),
}
#[derive(thiserror::Error, Debug)]
pub enum LiveMessageError {
#[error("Can't deserialize message: {0}")]
CantParse(String),
#[error("Can't get superchat message: {0:#?}")]
SuperChatMessageError(WsStreamCtx),
#[error("Can't get danmu message: {0:#?}")]
DanmuMessageError(WsStreamCtx),
#[error("Can't get ineract message: {0:#?}")]
InteractWordError(WsStreamCtx),
#[error("Can't get send gift message: {0:#?}")]
SendGiftMessageError(WsStreamCtx),
#[error("Can't get welcome guard message: {0:#?}")]
WelcomeGuardError(WsStreamCtx),
#[error("Unknown msg: {0:#?}")]
UnknownMessage(WsStreamCtx),
}
pub type LiveMessageResult<'a, T> = std::result::Result<T, LiveMessageError>;
impl WsStreamCtx {
pub fn new(s: &'_ str) -> LiveMessageResult<'_, Self> {
serde_json::from_str(s).map_err(|_| LiveMessageError::CantParse(s.to_string()))
}
pub fn match_msg(&'_ self) -> LiveMessageResult<'_, WsStreamMessageType> {
let cmd = self.handle_cmd();
let result = match cmd {
Some("DANMU_MSG") => WsStreamMessageType::DanmuMsg(DanmuMessage::new_from_ctx(self)?),
Some("SUPER_CHAT_MESSAGE") => {
WsStreamMessageType::SuperChatMessage(SuperChatMessage::new_from_ctx(self)?)
}
Some("INTERACT_WORD") => {
WsStreamMessageType::InteractWord(InteractWord::new_from_ctx(self)?)
}
Some("SEND_GIFT") | Some("COMBO_SEND") => {
WsStreamMessageType::SendGift(SendGift::new_from_ctx(self)?)
}
Some("WELCOME_GUARD") => {
WsStreamMessageType::WelcomeGuard(WelcomeGuard::new_from_ctx(self)?)
}
_ => return Err(LiveMessageError::UnknownMessage(self.clone())),
};
Ok(result)
}
fn handle_cmd(&self) -> Option<&str> {
let cmd = if let Some(c) = self.cmd.as_deref() {
if c.starts_with("DANMU_MSG") {
Some("DANMU_MSG")
} else {
Some(c)
}
} else {
None
};
cmd
}
}