新增本地服务器管理面板

新增 egui 服务器管理面板并支持 SSH alias 多服务器巡检

接入硬件状态、服务状态、HTTP 探测和生产巡检状态展示

增加受控 systemd 启动关闭重启操作和中文字体注入

补充本地服务器面板技术方案与团队共享记忆
This commit is contained in:
2026-06-11 22:33:05 +08:00
parent f8a80cd795
commit b54cbafc54
15 changed files with 3455 additions and 19 deletions

View File

@@ -0,0 +1,143 @@
use std::collections::HashSet;
use std::fs;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SshAlias {
pub name: String,
pub source: PathBuf,
}
pub fn discover_ssh_aliases() -> Vec<SshAlias> {
let Some(home) = std::env::var_os("HOME") else {
return Vec::new();
};
let config_path = PathBuf::from(home).join(".ssh/config");
discover_from_file(&config_path)
}
pub fn discover_from_file(path: &Path) -> Vec<SshAlias> {
let mut visited = HashSet::new();
let mut aliases = Vec::new();
discover_inner(path, &mut visited, &mut aliases);
dedupe_aliases(aliases)
}
fn discover_inner(path: &Path, visited: &mut HashSet<PathBuf>, aliases: &mut Vec<SshAlias>) {
let Ok(canonical) = path.canonicalize() else {
return;
};
if !visited.insert(canonical.clone()) {
return;
}
let Ok(content) = fs::read_to_string(&canonical) else {
return;
};
for line in content.lines() {
let trimmed = trim_comment(line);
let mut parts = trimmed.split_whitespace();
let Some(keyword) = parts.next() else {
continue;
};
if keyword.eq_ignore_ascii_case("host") {
aliases.extend(parts.filter_map(|name| {
is_concrete_alias(name).then(|| SshAlias {
name: name.to_owned(),
source: canonical.clone(),
})
}));
} else if keyword.eq_ignore_ascii_case("include") {
for include in parts {
for include_path in expand_include_path(include, canonical.parent()) {
discover_inner(&include_path, visited, aliases);
}
}
}
}
}
fn dedupe_aliases(aliases: Vec<SshAlias>) -> Vec<SshAlias> {
let mut seen = HashSet::new();
let mut deduped = Vec::new();
for alias in aliases {
if seen.insert(alias.name.clone()) {
deduped.push(alias);
}
}
deduped
}
fn trim_comment(line: &str) -> &str {
line.split('#').next().unwrap_or("").trim()
}
fn is_concrete_alias(value: &str) -> bool {
!value.is_empty()
&& !value.starts_with('-')
&& !value.starts_with('!')
&& !value.contains('*')
&& !value.contains('?')
&& !value.contains('%')
&& !value.contains('/')
}
fn expand_include_path(raw: &str, parent: Option<&Path>) -> Vec<PathBuf> {
if raw.contains('*') || raw.contains('?') {
// 中文注释SSH Include 支持复杂 glob面板只解析普通文件避免误扫过大目录。
return Vec::new();
}
let expanded = if let Some(rest) = raw.strip_prefix("~/") {
std::env::var_os("HOME")
.map(PathBuf::from)
.map(|home| home.join(rest))
} else {
let path = PathBuf::from(raw);
if path.is_absolute() {
Some(path)
} else {
parent.map(|base| base.join(path))
}
};
expanded.into_iter().collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn host_parser_ignores_wildcards_and_negations() {
let mut aliases = Vec::new();
let source = PathBuf::from("/tmp/config");
for line in [
"Host dev release *.internal !blocked",
"Host github.com",
"Host ?pattern",
"Host -bad",
] {
let trimmed = trim_comment(line);
let mut parts = trimmed.split_whitespace();
let keyword = parts.next().unwrap();
if keyword.eq_ignore_ascii_case("host") {
aliases.extend(parts.filter_map(|name| {
is_concrete_alias(name).then(|| SshAlias {
name: name.to_owned(),
source: source.clone(),
})
}));
}
}
let names: Vec<_> = dedupe_aliases(aliases)
.into_iter()
.map(|alias| alias.name)
.collect();
assert_eq!(names, ["dev", "release", "github.com"]);
}
#[test]
fn comment_trimming_keeps_plain_aliases() {
assert_eq!(trim_comment(" Host dev # release host "), "Host dev");
}
}