1use crate::args::Args;
2use crate::models::relay::Relay;
3use gethostname::gethostname;
4use std::sync::Arc;
5use std::time::Duration;
6use tracing::error;
7use webterm_core::random::{random_alphanumeric, random_in_range};
8
9const DEFAULT_RELAYS: [&str; 4] = [
11 "r1.relays.webterm.run",
12 "r2.relays.webterm.run",
13 "r4.relays.webterm.run",
14 "r5.relays.webterm.run",
15];
16pub const RELAY_RECONNECT_INTERVAL: Duration = Duration::from_secs(5);
17pub const DEFAULT_PBKDF2_ITERATIONS: u32 = 100_000;
18
19pub struct Config {
20 args: Args,
21 available_relays: Vec<Arc<Relay>>,
22 original_device_subname: String,
23}
24
25impl Config {
26 pub fn new(args: Args) -> Self {
27 let available_relays = Self::init_available_relays(&args);
28 let device_subname = infer_subname(&args);
29 Self {
30 args,
31 available_relays,
32 original_device_subname: device_subname.clone(),
33 }
34 }
35
36 pub fn device_name(&self) -> &String {
37 &self.args.device_name
38 }
39
40 pub fn original_device_subname(&self) -> &String {
41 &self.original_device_subname
42 }
43
44 pub fn try_new_device_subname(&self) -> String {
45 format!(
46 "{}-{}",
47 self.original_device_subname,
48 random_alphanumeric(4)
49 )
50 }
51
52 pub fn secret_key(&self) -> &String {
53 &self.args.secret_key
54 }
55
56 #[inline]
57 pub fn is_unix(&self) -> bool {
58 cfg!(unix)
59 }
60
61 pub fn wants_daemon(&self) -> bool {
62 self.args.daemon
63 }
64
65 pub fn can_daemon(&self) -> bool {
66 self.is_unix()
67 }
68
69 fn init_available_relays(args: &Args) -> Vec<Arc<Relay>> {
70 let mut result: Vec<Arc<Relay>> = args
71 .relays
72 .as_ref()
73 .map(|relays| {
74 relays
75 .split(',')
76 .map(|s| s.trim().to_string())
77 .filter(|s| !s.is_empty())
78 .filter_map(|s| match Relay::new(&s) {
79 Ok(relay) => Some(Arc::new(relay)),
80 Err(e) => {
81 error!("Failed to create relay for {}: {}", s, e);
82 None
83 }
84 })
85 .collect()
86 })
87 .unwrap_or_default();
88
89 if result.is_empty() {
90 result = DEFAULT_RELAYS
91 .iter()
92 .map(|s| Arc::new(Relay::new(s).unwrap()))
93 .collect()
94 }
95
96 result
97 }
98
99 pub fn random_relay(&self) -> Arc<Relay> {
100 let relays = &self.available_relays;
101 let index = random_in_range(0, relays.len());
102 relays[index].clone()
103 }
104}
105
106fn infer_subname(args: &Args) -> String {
107 args.device_subname
108 .clone()
109 .unwrap_or_else(|| get_hostname().unwrap_or_else(random_subname))
110}
111
112fn random_subname() -> String {
113 format!("device-{}", random_alphanumeric(8))
114}
115
116fn get_hostname() -> Option<String> {
117 let name = gethostname().to_string_lossy().to_string();
118 if name.trim().is_empty() {
119 None
120 } else {
121 Some(name)
122 }
123}