use crate::{
chat::{
commands::MessageType,
constants::{ELEMENT_END, ELEMENT_START, SEPARATOR, SEPARATOR_3_TIMES, SPACE, STARTER_VEC},
},
models::LiveDetail,
};
#[derive(Debug, Clone)]
pub struct ChatFormatter {
pub live_detail: LiveDetail,
pub password: String,
}
impl ChatFormatter {
pub fn new(live_detail: LiveDetail, password: String) -> Self {
Self {
live_detail,
password,
}
}
pub fn format_message(&self, message_type: MessageType) -> Vec<u8> {
let payload: String = match message_type {
MessageType::Connect => self.format_connect_packet(),
MessageType::JOIN => self.format_join_packet(),
_ => "".to_string(), };
return bundle(message_type, payload.as_bytes());
}
fn format_connect_packet(&self) -> String {
format!("{}16{}", SEPARATOR_3_TIMES, SEPARATOR)
}
fn format_join_packet(&self) -> String {
format!(
"\x0c{}\x0c\x0c0\x0c\x0clog\x11\x06&\x06set_bps\x06=\x068000\x06&\x06view_bps\x06=\x061000\x06&\x06quality\x06=\x06normal\x06&\x06uuid\x06=\x06\x06&\x06geo_cc\x06=\x06KR\x06&\x06geo_rc\x06=\x0626\x06&\x06acpt_lang\x06=\x06ko_KR\x06&\x06svc_lang\x06=\x06ko_KR\x06&\x06subscribe\x06=\x060\x06&\x06lowlatency\x06=\x060\x06&\x06mode\x06=\x06landing\x12pwd\x11{}\x12auth_info\x11NULL\x12pver\x112\x12access_system\x11html5\x12\x0c",
self.live_detail.ch_no, self.password
)
}
}
fn flatten_byte_slices(parts: &[&[u8]]) -> Vec<u8> {
let total_len = parts.iter().map(|s| s.len()).sum();
let mut result = Vec::with_capacity(total_len);
for part in parts {
result.extend_from_slice(part);
}
result
}
pub fn bundle(message_type: MessageType, body: &[u8]) -> Vec<u8> {
let code_str = format!("{:04}", message_type.to_code()); let body_len_str = format!("{:06}", body.len()); let reserved_str = "00";
let header_parts: Vec<&[u8]> = vec![
STARTER_VEC,
code_str.as_bytes(),
body_len_str.as_bytes(),
reserved_str.as_bytes(),
];
let mut header = flatten_byte_slices(&header_parts);
header.extend_from_slice(body);
header
}