1use std::path::PathBuf;
6
7use crate::host::listener::AppState;
8use crate::shared::error::Error;
9
10#[derive(Debug, Clone)]
13pub struct HostArgs {
14 pub listen: String,
15 pub profile: ProfileChoice,
17 pub display: DisplayMode,
18 pub takeover: Takeover,
19 pub display_quality: u8,
23 pub browser: BrowserChoice,
24 pub browser_bin: Option<PathBuf>,
25 pub token: Option<String>,
26 pub ops_enabled: bool,
27 pub health_enabled: bool,
28 pub health_public: HealthPublic,
29 pub engine_envs: Vec<(String, String)>,
34 pub browser_args: Vec<String>,
41 pub proxy: Option<String>,
48 pub recent_requests_cap: usize,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub enum ProfileChoice {
55 Ephemeral,
56 Persistent(String),
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum DisplayMode {
61 Headless,
62 Headful,
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum Takeover {
67 Off,
68 Screencast,
69 Display { provider: DisplayProvider },
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum DisplayProvider {
74 KasmVnc,
75}
76
77impl DisplayProvider {
78 pub fn as_str(self) -> &'static str {
79 match self {
80 Self::KasmVnc => "kasmvnc",
81 }
82 }
83}
84
85impl std::str::FromStr for DisplayProvider {
86 type Err = String;
87
88 fn from_str(s: &str) -> Result<Self, Self::Err> {
89 Ok(match s {
90 "kasmvnc" => Self::KasmVnc,
91 other => return Err(format!("unknown {other:?}; expected kasmvnc")),
92 })
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Default)]
97pub enum BrowserChoice {
98 #[default]
99 Auto,
100 Chromium,
101 Chrome,
102 ChromeShell,
103 FingerprintChromium,
104 Edge,
105 Brave,
106 Lightpanda,
107 Camoufox,
111}
112
113impl std::str::FromStr for BrowserChoice {
114 type Err = String;
115
116 fn from_str(s: &str) -> Result<Self, Self::Err> {
117 Ok(match s {
118 "auto" => Self::Auto,
119 "chromium" => Self::Chromium,
120 "chrome" => Self::Chrome,
121 "chrome_shell" | "chrome-headless-shell" => Self::ChromeShell,
122 "fingerprint_chromium" | "fingerprint-chromium" => Self::FingerprintChromium,
123 "edge" => Self::Edge,
124 "brave" => Self::Brave,
125 "lightpanda" => Self::Lightpanda,
126 "camoufox" => Self::Camoufox,
127 other => return Err(format!("unknown {other:?}")),
128 })
129 }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub enum HealthPublic {
134 Off,
135 Minimal,
136}
137
138pub fn install_rustls_provider() {
139 let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
140}
141
142pub async fn run(args: HostArgs) -> Result<(), Error> {
145 install_rustls_provider();
146 let state = AppState::launch(&args).await?;
147 state.serve(&args.listen).await
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn browser_choice_default_is_auto() {
156 assert_eq!(BrowserChoice::default(), BrowserChoice::Auto);
157 }
158
159 #[test]
160 fn browser_choice_parses_every_variant_and_aliases() {
161 assert_eq!(
162 "auto".parse::<BrowserChoice>().unwrap(),
163 BrowserChoice::Auto
164 );
165 assert_eq!(
166 "chromium".parse::<BrowserChoice>().unwrap(),
167 BrowserChoice::Chromium
168 );
169 assert_eq!(
170 "chrome".parse::<BrowserChoice>().unwrap(),
171 BrowserChoice::Chrome
172 );
173 assert_eq!(
175 "chrome_shell".parse::<BrowserChoice>().unwrap(),
176 BrowserChoice::ChromeShell
177 );
178 assert_eq!(
179 "chrome-headless-shell".parse::<BrowserChoice>().unwrap(),
180 BrowserChoice::ChromeShell
181 );
182 assert_eq!(
183 "fingerprint_chromium".parse::<BrowserChoice>().unwrap(),
184 BrowserChoice::FingerprintChromium
185 );
186 assert_eq!(
187 "fingerprint-chromium".parse::<BrowserChoice>().unwrap(),
188 BrowserChoice::FingerprintChromium
189 );
190 assert_eq!(
191 "edge".parse::<BrowserChoice>().unwrap(),
192 BrowserChoice::Edge
193 );
194 assert_eq!(
195 "brave".parse::<BrowserChoice>().unwrap(),
196 BrowserChoice::Brave
197 );
198 assert_eq!(
199 "lightpanda".parse::<BrowserChoice>().unwrap(),
200 BrowserChoice::Lightpanda
201 );
202 assert_eq!(
203 "camoufox".parse::<BrowserChoice>().unwrap(),
204 BrowserChoice::Camoufox
205 );
206 }
207
208 #[test]
209 fn browser_choice_rejects_unknown() {
210 let err = "netscape".parse::<BrowserChoice>().unwrap_err();
211 assert!(err.contains("netscape"), "error was {err:?}");
212 }
213}