kick_rust/fetch/
types.rs

1//! Types specific to the fetch module
2
3use serde::{Deserialize, Serialize};
4
5/// Result type for fetch operations
6pub type FetchResult<T> = Result<T, FetchError>;
7
8/// Error types for fetch operations
9#[derive(Debug, Clone, thiserror::Error)]
10pub enum FetchError {
11    #[error("Network error: {0}")]
12    Network(String),
13
14    #[error("HTTP request failed: {0}")]
15    Http(String),
16
17    #[error("JSON parsing error: {0}")]
18    Json(String),
19
20    #[error("Channel not found: {0}")]
21    ChannelNotFound(String),
22
23    #[error("Rate limit exceeded")]
24    RateLimit,
25
26    #[error("Invalid response format")]
27    InvalidResponse,
28
29    #[error("Timeout error")]
30    Timeout,
31
32    #[error("Authentication required")]
33    AuthenticationRequired,
34}
35
36/// Configuration for the HTTP client
37#[derive(Debug, Clone)]
38pub struct ClientConfig {
39    /// User agent string for requests
40    pub user_agent: Option<String>,
41    /// Request timeout in seconds
42    pub timeout_seconds: u64,
43    /// Maximum number of retries for failed requests
44    pub max_retries: u32,
45    /// Delay between retries in milliseconds
46    pub retry_delay_ms: u64,
47    /// Enable request/response logging
48    pub enable_logging: bool,
49    /// Custom headers to include in all requests
50    pub custom_headers: Vec<(String, String)>,
51}
52
53impl Default for ClientConfig {
54    fn default() -> Self {
55        Self {
56            user_agent: Some(crate::fetch::useragent::get_latest_chrome_user_agent().to_string()),
57            timeout_seconds: 30,
58            max_retries: 3,
59            retry_delay_ms: 1000,
60            enable_logging: false,
61            custom_headers: Vec::new(),
62        }
63    }
64}
65
66/// Channel information from the Kick API
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ChannelInfo {
69    /// Channel ID
70    pub id: u64,
71    /// Channel slug/name
72    pub slug: String,
73    /// Channel title
74    pub title: Option<String>,
75    /// Number of followers
76    pub followers_count: Option<u64>,
77    /// Number of subscribers
78    pub subscribers_count: Option<u64>,
79    /// Is channel currently live
80    pub is_live: bool,
81    /// Viewer count if live
82    pub viewers_count: Option<u64>,
83    /// Stream category
84    pub category: Option<String>,
85    /// Stream tags
86    pub tags: Option<Vec<String>>,
87    /// Channel language
88    pub language: Option<String>,
89    /// User information
90    pub user: Option<UserInfo>,
91    /// Chatroom information
92    pub chatroom: Option<ChatroomInfo>,
93}
94
95/// User information associated with a channel
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct UserInfo {
98    /// User ID
99    pub id: u64,
100    /// Username
101    pub username: String,
102    /// Display name
103    pub display_name: Option<String>,
104    /// Avatar URL
105    pub avatar_url: Option<String>,
106    /// Bio/description
107    pub bio: Option<String>,
108    /// Account creation date
109    pub created_at: Option<String>,
110}
111
112/// Chatroom information
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct ChatroomInfo {
115    /// Chatroom ID
116    pub id: u64,
117    /// Channel ID
118    pub channel_id: u64,
119    /// Chatroom name
120    pub name: String,
121    /// Chatroom type
122    pub chatroom_type: Option<String>,
123    /// Slow mode delay in seconds
124    pub slow_mode: Option<u32>,
125}
126
127/// Strategy configuration for different fetch approaches
128#[derive(Debug, Clone)]
129pub struct StrategyConfig {
130    /// Random delay range in milliseconds (for rate limiting)
131    pub random_delay_range: (u64, u64),
132}
133
134impl Default for StrategyConfig {
135    fn default() -> Self {
136        Self {
137            random_delay_range: (100, 500),
138        }
139    }
140}
141
142/// Request context for tracking fetch operations
143#[derive(Debug, Clone)]
144pub struct RequestContext {
145    /// Channel name being requested
146    pub channel_name: String,
147    /// Strategy being used
148    pub strategy: String,
149    /// Attempt number
150    pub attempt: u32,
151    /// Request timestamp
152    pub timestamp: chrono::DateTime<chrono::Utc>,
153    /// User agent used
154    pub user_agent: String,
155}
156
157impl RequestContext {
158    pub fn new(channel_name: &str, strategy: &str) -> Self {
159        Self {
160            channel_name: channel_name.to_string(),
161            strategy: strategy.to_string(),
162            attempt: 1,
163            timestamp: chrono::Utc::now(),
164            user_agent: "unknown".to_string(),
165        }
166    }
167}
168
169/// Metrics for fetch operations
170#[derive(Debug, Clone, Default)]
171pub struct FetchMetrics {
172    /// Total requests made
173    pub total_requests: u64,
174    /// Successful requests
175    pub successful_requests: u64,
176    /// Failed requests
177    pub failed_requests: u64,
178    /// Average response time in milliseconds
179    pub avg_response_time_ms: f64,
180    /// Cache hits
181    pub cache_hits: u64,
182    /// Rate limit hits
183    pub rate_limit_hits: u64,
184}
185
186impl FetchMetrics {
187    pub fn success_rate(&self) -> f64 {
188        if self.total_requests == 0 {
189            0.0
190        } else {
191            self.successful_requests as f64 / self.total_requests as f64 * 100.0
192        }
193    }
194
195    pub fn record_success(&mut self, response_time_ms: u64) {
196        self.total_requests += 1;
197        self.successful_requests += 1;
198        self.update_avg_response_time(response_time_ms);
199    }
200
201    pub fn record_failure(&mut self) {
202        self.total_requests += 1;
203        self.failed_requests += 1;
204    }
205
206    fn update_avg_response_time(&mut self, response_time_ms: u64) {
207        if self.total_requests == 1 {
208            self.avg_response_time_ms = response_time_ms as f64;
209        } else {
210            self.avg_response_time_ms = (self.avg_response_time_ms * (self.total_requests - 1) as f64 + response_time_ms as f64) / self.total_requests as f64;
211        }
212    }
213}