1use crate::fd_budget;
2use crate::git;
3use crate::hex::ToHex;
4use sha2::{Digest, Sha256};
5use std::fs::{read_to_string, File};
6use std::io::Read;
7use std::path::PathBuf;
8use std::sync::OnceLock;
10
11static SYSTEM_INFO: OnceLock<SystemInfo> = OnceLock::new();
12
13#[derive(Clone)]
14pub struct SystemInfo {
15 pub system_id: Option<Vec<u8>>,
17 pub git_hash: Option<Vec<u8>>,
19 pub git_short_hash: Option<Vec<u8>>,
21 pub version: String,
23 pub cpu_physical_cores: u16,
25 pub total_memory: u64,
27 pub fd_limit: u32,
29 pub proxy_socket_limit_per_cpu_core: Option<u32>,
31}
32
33impl std::fmt::Debug for SystemInfo {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 f.debug_struct("SystemInfo")
37 .field("system_id", &self.system_id.as_ref().map(|id| id.to_hex()))
38 .field("git_hash", &self.git_hash.as_ref().map(|hash| hash.to_hex()))
39 .field("git_short_hash", &self.git_short_hash.as_ref().map(|hash| hash.to_hex()))
40 .field("version", &self.version)
41 .field("cpu_physical_cores", &self.cpu_physical_cores)
42 .field("total_memory", &self.total_memory)
43 .field("fd_limit", &self.fd_limit)
44 .field("proxy_socket_limit_per_cpu_core", &self.proxy_socket_limit_per_cpu_core)
45 .finish()
46 }
47}
48
49impl Default for SystemInfo {
50 fn default() -> Self {
51 let system_info = SYSTEM_INFO.get_or_init(|| {
52 let mut system = sysinfo::System::new();
53 system.refresh_memory();
54 let cpu_physical_cores = num_cpus::get() as u16;
55 let total_memory = system.total_memory();
56 let fd_limit = fd_budget::limit() as u32;
57 let system_id = Self::try_system_id();
58 let git_hash = git::hash();
59 let git_short_hash = git::short_hash();
60 let version = git::version();
61 let proxy_socket_limit_per_cpu_core = Self::try_proxy_socket_limit_per_cpu_core();
62
63 SystemInfo {
64 system_id,
65 git_hash,
66 git_short_hash,
67 version,
68 cpu_physical_cores,
69 total_memory,
70 fd_limit,
71 proxy_socket_limit_per_cpu_core,
72 }
73 });
74 (*system_info).clone()
75 }
76}
77
78impl SystemInfo {
79 fn try_system_id() -> Option<Vec<u8>> {
81 let some_id = if let Ok(mut file) = File::open("/etc/machine-id") {
82 let mut machine_id = String::new();
84 file.read_to_string(&mut machine_id).ok();
85 machine_id.trim().to_string()
86 } else if let Ok(Some(mac)) = mac_address::get_mac_address() {
87 mac.to_string().trim().to_string()
89 } else {
90 return None;
92 };
93 let mut sha256 = Sha256::default();
94 sha256.update(some_id.as_bytes());
95 Some(sha256.finalize().to_vec())
96 }
97
98 fn try_proxy_socket_limit_per_cpu_core() -> Option<u32> {
99 let nginx_config_path = PathBuf::from("/etc/nginx/nginx.conf");
100 if nginx_config_path.exists() {
101 read_to_string(nginx_config_path)
102 .ok()
103 .and_then(|content| content.lines().find(|line| line.trim().starts_with("worker_connections")).map(String::from))
104 .and_then(|line| line.split_whitespace().nth(1).map(|v| v.replace(";", "")))
105 .and_then(|value| value.parse::<u32>().ok())
106 } else {
107 None
108 }
109 }
110}
111
112impl AsRef<SystemInfo> for SystemInfo {
113 fn as_ref(&self) -> &SystemInfo {
114 self
115 }
116}
117
118