1use super::*;
2use crate::engine::scaler::ProtocolFamily;
3
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5pub enum DownloadStatus {
6 Queued,
7 Downloading,
8 Paused,
9 Stopped,
10 Completed,
11 Error(String),
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct DownloadTask {
16 pub id: Uuid,
17 pub url: String,
18 pub filename: String,
19 pub dir: PathBuf,
20 pub total_size: u64,
21 pub downloaded_size: u64,
22 pub connections: usize,
23 pub status: DownloadStatus,
24 pub speed: f64,
25 pub dry_run: bool,
26 pub dry_run_size_mb: Option<u64>,
27 pub borrow_limit_mb: u64,
28 pub min_connections: usize,
29 pub max_connections: usize,
30 pub per_download_bandwidth_limit_bps: u64,
31 pub schedule_mode: ScheduleMode,
32 pub http_mode: HttpMode,
33 pub log_root: Option<PathBuf>,
34 #[serde(skip)]
36 pub request_context: Option<crate::service::RequestContext>,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
40pub enum ScheduleMode {
41 Fib,
42 FibAdaptive,
43 Equal,
44}
45
46impl ScheduleMode {
47 pub fn parse(input: &str) -> Result<Self> {
48 match input.trim().to_ascii_lowercase().as_str() {
49 "fib" => Ok(Self::Fib),
50 "fib-adaptive" | "fib_adaptive" | "adaptive-fib" | "adaptive_fib" => {
51 Ok(Self::FibAdaptive)
52 }
53 "equal" => Ok(Self::Equal),
54 other => Err(anyhow!("unsupported schedule mode: {}", other)),
55 }
56 }
57
58 pub(crate) fn as_str(self) -> &'static str {
59 match self {
60 Self::Fib => "fib",
61 Self::FibAdaptive => "fib-adaptive",
62 Self::Equal => "equal",
63 }
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
68pub enum HttpMode {
69 Auto,
70 Http1,
71 Http2,
72 Http3,
73}
74
75impl HttpMode {
76 pub fn parse(input: &str) -> Result<Self> {
77 match input.trim().to_ascii_lowercase().as_str() {
78 "auto" => Ok(Self::Auto),
79 "http1" | "http/1.1" | "h1" => Ok(Self::Http1),
80 "http2" | "http/2" | "h2" => Ok(Self::Http2),
81 "http3" | "http/3" | "h3" | "quic" => Ok(Self::Http3),
82 other => Err(anyhow!("unsupported http mode: {}", other)),
83 }
84 }
85
86 pub(crate) fn as_str(self) -> &'static str {
87 match self {
88 Self::Auto => "auto",
89 Self::Http1 => "http1",
90 Self::Http2 => "http2",
91 Self::Http3 => "http3",
92 }
93 }
94}
95
96#[derive(Debug)]
97pub struct ActiveRange {
98 pub id: u64,
99 pub label_start_mb: u64,
100 pub label_end_mb: u64,
101 pub byte_start: u64,
102 pub assigned_to: Cell<u32>,
103 pub cursor: Cell<u64>,
104 pub end: Cell<u64>,
105 pub parent_range_id: Option<u64>,
106 pub status: Cell<u8>,
107 pub last_sample_cursor: Cell<u64>,
108 pub last_sample_at_ms: Cell<u64>,
109 pub recent_speed_bps: Cell<u64>,
110}
111
112#[derive(Debug)]
113pub struct WorkRequest {
114 pub connection_id: u32,
115 pub tx: oneshot::Sender<Option<Rc<ActiveRange>>>,
116}
117
118#[derive(Debug, Clone)]
119pub enum EngineEvent {
120 Progress(Uuid, u64, f64),
121 StatusChanged(Uuid, DownloadStatus),
122 TotalSize(Uuid, u64),
123 Workers(Uuid, Vec<WorkerSnapshot>),
124 Protocol(Uuid, ProtocolInfo),
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
130#[serde(rename_all = "snake_case")]
131pub enum WorkerState {
132 Connecting,
133 WaitingForWork,
134 Downloading,
135 Retrying,
136 Paused,
137 Stopped,
138 Finished,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
142#[serde(rename_all = "camelCase")]
143pub struct WorkerSnapshot {
144 pub connection_id: u32,
145 pub state: WorkerState,
146 pub transferred_bytes: u64,
147 pub speed_bps: f64,
148 pub range_start: Option<u64>,
149 pub range_end: Option<u64>,
150 pub range_cursor: Option<u64>,
151 pub detail: Option<String>,
152}
153
154pub enum EngineCommand {
155 Add(DownloadTask),
156 Resume(Uuid),
157 Stop(Uuid),
158 Cancel(Uuid),
159 UpdateScaling(Uuid, ScalerConfig),
160 RuntimeStopped(TaskSnapshot, HaltMode),
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
165pub struct ProtocolInfo {
166 pub requested: HttpMode,
168 pub negotiated: ProtocolFamily,
170}
171
172impl ProtocolInfo {
173 pub fn display_label(&self) -> String {
175 let req = match self.requested {
176 HttpMode::Auto => "auto",
177 HttpMode::Http1 => "h1",
178 HttpMode::Http2 => "h2",
179 HttpMode::Http3 => "h3",
180 };
181 let neg = self.negotiated.as_str();
182 if req == neg || self.negotiated == ProtocolFamily::Other {
183 req.to_string()
184 } else {
185 format!("{}→{}", req, neg)
186 }
187 }
188}
189
190impl Default for ProtocolInfo {
191 fn default() -> Self {
192 Self {
193 requested: HttpMode::Auto,
194 negotiated: ProtocolFamily::Other,
195 }
196 }
197}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
200pub enum HaltMode {
201 Running,
203 Draining,
205 Hibernating,
207 PersistToDisk,
209}