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