1use crate::error::Result;
5use serde::{Deserialize, Serialize};
6use std::ffi::{OsStr, OsString};
7use std::net::SocketAddrV4;
8use std::sync::{Arc, LazyLock};
9use strum::EnumIs;
10use url::Url;
11
12static REMOTE_SERVER_ADDR: LazyLock<Url> = LazyLock::new(nil_env::remote_server_addr);
13
14#[derive(Clone, Copy, Debug, Default, EnumIs, PartialEq, Eq, Hash, Deserialize, Serialize)]
15#[serde(tag = "kind", rename_all = "kebab-case")]
16pub enum ServerAddr {
17 #[default]
18 Remote,
19 Local {
20 addr: SocketAddrV4,
21 },
22}
23
24impl ServerAddr {
25 #[inline]
26 pub fn url(&self, route: &str) -> Result<Url> {
27 match self {
28 Self::Remote => Ok(REMOTE_SERVER_ADDR.join(route)?),
29 Self::Local { addr } => {
30 let ip = addr.ip();
31 let port = addr.port();
32 Ok(Url::parse(&format!("http://{ip}:{port}/{route}"))?)
33 }
34 }
35 }
36}
37
38impl From<SocketAddrV4> for ServerAddr {
39 fn from(addr: SocketAddrV4) -> Self {
40 Self::Local { addr }
41 }
42}
43
44impl From<&[u8]> for ServerAddr {
45 fn from(bytes: &[u8]) -> Self {
46 if let Ok(addr) = SocketAddrV4::parse_ascii(bytes) {
47 Self::Local { addr }
48 } else {
49 Self::Remote
50 }
51 }
52}
53
54impl From<&OsStr> for ServerAddr {
55 fn from(value: &OsStr) -> Self {
56 Self::from(value.as_encoded_bytes())
57 }
58}
59
60impl From<OsString> for ServerAddr {
61 fn from(value: OsString) -> Self {
62 Self::from(value.as_os_str())
63 }
64}
65
66macro_rules! from_bytes {
67 ($($type_:ty),+ $(,)?) => {
68 $(
69 impl From<$type_> for ServerAddr {
70 fn from(value: $type_) -> Self {
71 Self::from(value.as_bytes())
72 }
73 }
74 )+
75 };
76}
77
78from_bytes!(&str, String, &String, Arc<str>, Box<str>);