Skip to main content

soup_sdk/chat/
events.rs

1use chrono::{DateTime, Utc};
2use serde::{Serialize, Serializer};
3use std::sync::Arc;
4
5fn serialize_arc_bytes<S>(data: &Arc<[u8]>, serializer: S) -> Result<S::Ok, S::Error>
6where
7    S: Serializer,
8{
9    serializer.serialize_bytes(data)
10}
11
12use crate::chat::{
13    constants::message_codes::MessageCode,
14    types::{ChatType, DonationType, Emoticon, GiftType, MissionType, User},
15};
16
17// --- 채팅 이벤트 ---
18#[derive(Debug, Clone, Serialize)]
19#[serde(tag = "type", content = "payload")]
20pub enum Event {
21    // --- 생명 주기 관련 이벤트 ---
22    /// 최초 연결 성공 시 발생
23    Connected,
24    /// 연결이 완전히 종료되었을 때 발생
25    Disconnected(DisconnectedEvent),
26
27    // --- 채팅 관련 이벤트 ---
28    BJStateChange,
29    /// 채팅 메시지가 수신되었을 때 발생합니다.
30    Chat(ChatEvent),
31    /// 후원 (텍스트, 영상, 애드벌룬)이 발생했을 때.
32    Donation(DonationEvent),
33    /// 구독이 발생했을 때.
34    Subscribe(SubscribeEvent),
35    /// 새로운 시청자가 채팅방에 입장했을 때.
36    Enter(UserEvent),
37    /// 시청자가 채팅방에서 퇴장했을 때.
38    Exit(UserEvent),
39    // 시청자가 퇴장당한 경우,
40    Kick(UserEvent),
41    // 강제 퇴장 취소,
42    KickCancel(SimplifiedUserEvent),
43    // Sticker,
44    Sticker(StickerEvent),
45    // Gift
46    Gift(GiftEvent),
47    // 시청자가 Mute 당한 경우
48    Mute(MuteEvent),
49    // 시청자가 블랙 당한경우,
50    Black(SimplifiedUserEvent),
51    // 채팅방이 얼려진 경우,
52    Freeze(FreezeEvent),
53    /// 스트리머나 매니저가 보낸 공지사항 메시지.
54    Notification(NotificationEvent),
55    /// 채팅 참여자 명단 최종 집계 결과.
56    ParticipantList(ParticipantListEvent),
57    /// 미션
58    MissionDonation(MissionEvent),
59    /// 미션 정산
60    MissionTotal(MissionTotalEvent),
61    /// 미션 결과
62    BattleMissionResult(BattleMissionResultEvent),
63    ChallengeMissionResult(ChallengeMissionResultEvent),
64    /// 알 수 없는 이벤트 타입
65    Unknown(MessageCode),
66    // 슬로우 이벤트
67    Slow(SlowEvent),
68    /// 직접 처리
69    #[serde(serialize_with = "serialize_arc_bytes")]
70    Raw(Arc<[u8]>), // 원시 데이터로 처리할 수 있는 이벤트
71    /// 프로토콜 분석과 파싱 실패 진단용 이벤트
72    Diagnostic(DiagnosticEvent),
73}
74
75#[derive(Debug, Clone, Serialize)]
76pub struct EventMeta {
77    /// 이벤트가 라이브러리에서 생성된 시간
78    pub received_time: DateTime<Utc>,
79}
80
81// --- 생명 주기 관련 이벤트 ---
82#[derive(Debug, Clone, Serialize)]
83pub struct ConnectedEvent {
84    #[serde(flatten)]
85    pub meta: EventMeta,
86}
87
88#[derive(Debug, Clone, Serialize)]
89#[serde(rename_all = "camelCase")]
90pub struct DisconnectedEvent {
91    #[serde(flatten)]
92    pub meta: EventMeta,
93    pub reason: DisconnectReason,
94}
95
96#[derive(Debug, Clone, Serialize)]
97#[serde(rename_all = "camelCase")]
98pub enum DisconnectReason {
99    Shutdown,
100    WebSocketClosed,
101    ConnectionFailed,
102    ProtocolError,
103    ChannelClosed,
104}
105
106#[derive(Debug, Clone, Serialize)]
107#[serde(tag = "kind", content = "payload")]
108pub enum DiagnosticEvent {
109    RawFrame(RawFrameDiagnostic),
110    DecodedFrame(DecodedFrameDiagnostic),
111    UnknownCode(UnknownCodeDiagnostic),
112    ParseFailed(ParseFailedDiagnostic),
113}
114
115#[derive(Debug, Clone, Serialize)]
116#[serde(rename_all = "camelCase")]
117pub struct RawFrameDiagnostic {
118    #[serde(flatten)]
119    pub meta: EventMeta,
120    pub byte_len: usize,
121    #[serde(serialize_with = "serialize_arc_bytes")]
122    pub raw: Arc<[u8]>,
123}
124
125#[derive(Debug, Clone, Serialize)]
126#[serde(rename_all = "camelCase")]
127pub struct DecodedFrameDiagnostic {
128    #[serde(flatten)]
129    pub meta: EventMeta,
130    pub code: MessageCode,
131    pub ret_code: u32,
132    pub field_count: usize,
133    pub body: Vec<String>,
134    #[serde(serialize_with = "serialize_arc_bytes")]
135    pub raw: Arc<[u8]>,
136}
137
138#[derive(Debug, Clone, Serialize)]
139#[serde(rename_all = "camelCase")]
140pub struct UnknownCodeDiagnostic {
141    #[serde(flatten)]
142    pub meta: EventMeta,
143    pub code: MessageCode,
144    pub ret_code: u32,
145    pub field_count: usize,
146    pub body: Vec<String>,
147    #[serde(serialize_with = "serialize_arc_bytes")]
148    pub raw: Arc<[u8]>,
149}
150
151#[derive(Debug, Clone, Serialize)]
152#[serde(rename_all = "camelCase")]
153pub struct ParseFailedDiagnostic {
154    #[serde(flatten)]
155    pub meta: EventMeta,
156    pub code: Option<MessageCode>,
157    pub body_field_count: Option<usize>,
158    pub field_index: Option<usize>,
159    pub expected_type: Option<String>,
160    pub reason: String,
161    #[serde(serialize_with = "serialize_arc_bytes")]
162    pub raw: Arc<[u8]>,
163}
164
165// --- 채팅 관련 이벤트 ---
166
167#[derive(Debug, Clone, Serialize)]
168#[serde(rename_all = "camelCase")]
169pub struct ChatEvent {
170    /// 공통 속성 영역
171    #[serde(flatten)]
172    pub meta: EventMeta,
173    pub comment: String,
174    pub chat_type: ChatType,
175    pub user: User,
176    // manager chat에서만 true/false로 할당됩니다.
177    pub is_admin: bool,
178    // emoticon 채팅에서만 할당됩니다.
179    pub emoticon: Option<Emoticon>,
180}
181
182#[derive(Debug, Clone, Serialize)]
183#[serde(rename_all = "camelCase")]
184pub struct GiftEvent {
185    /// 공통 속성 영역
186    #[serde(flatten)]
187    pub meta: EventMeta,
188    pub gift_type: GiftType,
189    pub sender_id: String,
190    pub sender_label: String,
191    pub receiver_id: String,
192    pub receiver_label: String,
193    pub gift_code: String,
194}
195
196#[derive(Debug, Clone, Serialize)]
197#[serde(rename_all = "camelCase")]
198pub struct DonationEvent {
199    #[serde(flatten)]
200    pub meta: EventMeta,
201    pub from: String,
202    pub from_label: String,
203    pub amount: u32,           // 후원 금액
204    pub fan_club_ordinal: u32, // 팬클럽 순번
205    pub become_top_fan: bool,
206    pub donation_type: DonationType,
207}
208
209#[derive(Debug, Clone, Serialize)]
210#[serde(rename_all = "camelCase")]
211pub struct StickerEvent {
212    #[serde(flatten)]
213    pub meta: EventMeta,
214    pub from: String,
215    pub from_label: String,
216    pub amount: u32,            // 스티커 갯수 금액
217    pub supporter_ordinal: u32, // 서포터 순번
218}
219
220#[derive(Debug, Clone, Serialize)]
221#[serde(rename_all = "camelCase")]
222pub struct MissionEvent {
223    #[serde(flatten)]
224    pub meta: EventMeta,
225    pub from: String,
226    pub from_label: String,
227    pub amount: u32, // 후원 금액
228    pub mission_type: MissionType,
229}
230
231#[derive(Debug, Clone, Serialize)]
232#[serde(rename_all = "camelCase")]
233pub struct MissionTotalEvent {
234    #[serde(flatten)]
235    pub meta: EventMeta,
236    pub mission_type: MissionType,
237    pub amount: u32,
238}
239
240#[derive(Debug, Clone, Serialize)]
241#[serde(rename_all = "camelCase")]
242pub struct ChallengeMissionResultEvent {
243    #[serde(flatten)]
244    pub meta: EventMeta,
245    pub is_success: bool,
246    pub title: String,
247}
248
249#[derive(Debug, Clone, Serialize)]
250#[serde(rename_all = "camelCase")]
251pub struct BattleMissionResultEvent {
252    #[serde(flatten)]
253    pub meta: EventMeta,
254    pub is_draw: bool,
255    pub winner: String,
256    pub title: String,
257}
258
259#[derive(Debug, Clone, Serialize)]
260#[serde(rename_all = "camelCase")]
261pub struct SubscribeEvent {
262    #[serde(flatten)]
263    pub meta: EventMeta,
264    pub user_id: String,
265    pub label: String,
266    pub tier: u32,
267    // 구독 갱신인 경우 할당됩니다.
268    pub renew: u32,
269}
270
271#[derive(Debug, Clone, Serialize)]
272pub struct NotificationEvent {
273    #[serde(flatten)]
274    pub meta: EventMeta,
275    pub message: String,
276    pub show: bool,
277}
278
279#[derive(Debug, Clone, Serialize)]
280pub struct UserEvent {
281    #[serde(flatten)]
282    pub meta: EventMeta,
283    #[serde(flatten)]
284    pub user: User,
285}
286
287#[derive(Debug, Clone, Serialize)]
288#[serde(rename_all = "camelCase")]
289pub struct SimplifiedUserEvent {
290    #[serde(flatten)]
291    pub meta: EventMeta,
292    pub user_id: String,
293}
294
295#[derive(Debug, Clone, Serialize)]
296#[serde(rename_all = "camelCase")]
297pub struct ParticipantListEvent {
298    #[serde(flatten)]
299    pub meta: EventMeta,
300    pub result_code: String,
301    pub count: usize,
302    pub entries: Vec<User>,
303}
304
305#[derive(Debug, Clone)]
306pub(crate) struct ParticipantListCompleteEvent {
307    pub(crate) meta: EventMeta,
308    pub(crate) result_code: String,
309}
310
311#[derive(Debug, Clone, Serialize)]
312#[serde(rename_all = "camelCase")]
313pub struct FreezeEvent {
314    #[serde(flatten)]
315    pub meta: EventMeta,
316    pub freezed: bool,
317    pub limit_subscription_month: u32,
318    pub limit_balloons: u32,
319    pub targets: Vec<String>,
320}
321
322#[derive(Debug, Clone, Serialize)]
323#[serde(rename_all = "camelCase")]
324pub struct MuteEvent {
325    #[serde(flatten)]
326    pub meta: EventMeta,
327    pub user: User,
328    pub seconds: u32,
329    pub message: String,
330    pub by: String,
331    pub counts: u32,
332    pub superuser_type: String,
333}
334
335#[derive(Debug, Clone, Serialize)]
336pub struct SlowEvent {
337    #[serde(flatten)]
338    pub meta: EventMeta,
339    pub duration: u32,
340}