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")]
16#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
17#[cfg_attr(feature = "typescript", ts(export))]
18pub enum ServerAddr {
19 #[default]
20 Remote,
21 Local {
22 addr: SocketAddrV4,
23 },
24}
25
26impl ServerAddr {
27 #[inline]
28 pub fn url(&self, route: &str) -> Result<Url> {
29 match self {
30 Self::Remote => Ok(REMOTE_SERVER_ADDR.join(route)?),
31 Self::Local { addr } => {
32 let ip = addr.ip();
33 let port = addr.port();
34 Ok(Url::parse(&format!("http://{ip}:{port}/{route}"))?)
35 }
36 }
37 }
38}
39
40impl From<SocketAddrV4> for ServerAddr {
41 fn from(addr: SocketAddrV4) -> Self {
42 Self::Local { addr }
43 }
44}
45
46impl From<&[u8]> for ServerAddr {
47 fn from(bytes: &[u8]) -> Self {
48 if let Ok(addr) = SocketAddrV4::parse_ascii(bytes) {
49 Self::Local { addr }
50 } else {
51 Self::Remote
52 }
53 }
54}
55
56impl From<&OsStr> for ServerAddr {
57 fn from(value: &OsStr) -> Self {
58 Self::from(value.as_encoded_bytes())
59 }
60}
61
62impl From<OsString> for ServerAddr {
63 fn from(value: OsString) -> Self {
64 Self::from(value.as_os_str())
65 }
66}
67
68macro_rules! from_bytes {
69 ($($type_:ty),+ $(,)?) => {
70 $(
71 impl From<$type_> for ServerAddr {
72 fn from(value: $type_) -> Self {
73 Self::from(value.as_bytes())
74 }
75 }
76 )+
77 };
78}
79
80from_bytes!(&str, String, &String, Arc<str>, Box<str>);