Skip to main content

nil_client/
server.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use 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>);