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