network-infra-utility 0.3.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +21 -0
- data/GUIDE.md +212 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +70 -0
- data/Rakefile +1 -1
- data/bin/dns-query +836 -0
- data/bin/geo-doc +135 -0
- data/bin/geo-get +1 -1
- data/bin/geo-update +429 -0
- data/document/ASNum/346/250/241/345/235/227/345/212/237/350/203/275/350/257/264/346/230/216.md +242 -0
- data/document/DNSQuery/345/267/245/345/205/267/344/275/277/347/224/250/346/226/271/346/263/225.md +248 -0
- data/document/Geo/345/221/275/344/273/244/345/267/245/345/205/267/344/275/277/347/224/250/346/226/271/346/263/225.md +441 -0
- data/document/IP/346/250/241/345/235/227/345/212/237/350/203/275/350/257/264/346/230/216.md +297 -0
- data/document/MAC/346/250/241/345/235/227/345/212/237/350/203/275/350/257/264/346/230/216.md +296 -0
- data/document/SSH/350/277/236/346/216/245/345/256/242/346/210/267/347/253/257/344/275/277/347/224/250/346/226/271/346/263/225.md +764 -0
- data/network-infra-utility.gemspec +4 -2
- data/network.rb +3 -1
- data/service/geodb/geodb.rb +278 -1
- data/service/ssh/README.md +955 -0
- data/service/ssh/bin/ssh-client +198 -0
- data/service/ssh/design/SSH/350/277/236/346/216/245/345/256/242/346/210/267/347/253/257/345/212/237/350/203/275/351/234/200/346/261/202/346/226/207/346/241/243.md +292 -0
- data/service/ssh/design/SSH/350/277/236/346/216/245/345/256/242/346/210/267/347/253/257/350/257/246/347/273/206/350/256/276/350/256/241/346/226/207/346/241/243.md +1521 -0
- data/service/ssh/design/SSH/350/277/236/346/216/245/345/256/242/346/210/267/347/253/257/350/275/257/344/273/266/350/256/276/350/256/241/346/226/207/346/241/243.md +2493 -0
- data/service/ssh/ext/ssh_core/bin/ssh_core.cmd +28 -0
- data/service/ssh/ext/ssh_core/config/sys.config +0 -0
- data/service/ssh/ext/ssh_core/config/vm.args +0 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/CHECKSUM +1 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/LICENSE +21 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/README.md +696 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/VERSION +1 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/contents.tar.gz +0 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/metadata.config +15 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/rebar.config +17 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/rebar.lock +1 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx.app.src +10 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx.erl +506 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_config.erl +393 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_config.hrl +18 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_consult.erl +81 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_decoder.erl +1909 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_encoder.erl +116 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_parser.erl +1214 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_to_json.erl +408 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_to_term.erl +389 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_verify.erl +121 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx.erl +506 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_config.erl +393 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_config.hrl +18 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_consult.erl +81 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_decoder.erl +1909 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_encoder.erl +116 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_parser.erl +1214 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_to_json.erl +408 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_to_term.erl +389 -0
- data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_verify.erl +121 -0
- data/service/ssh/ext/ssh_core/rebar.config +24 -0
- data/service/ssh/ext/ssh_core/rebar.lock +1 -0
- data/service/ssh/ext/ssh_core/src/ssh_auth_engine.erl +156 -0
- data/service/ssh/ext/ssh_core/src/ssh_channel_stm.erl +232 -0
- data/service/ssh/ext/ssh_core/src/ssh_codec.erl +83 -0
- data/service/ssh/ext/ssh_core/src/ssh_conn_sup.erl +48 -0
- data/service/ssh/ext/ssh_core/src/ssh_conn_worker.erl +535 -0
- data/service/ssh/ext/ssh_core/src/ssh_core.app.src +36 -0
- data/service/ssh/ext/ssh_core/src/ssh_core_app.erl +11 -0
- data/service/ssh/ext/ssh_core/src/ssh_core_sup.erl +46 -0
- data/service/ssh/ext/ssh_core/src/ssh_infra_sup.erl +117 -0
- data/service/ssh/ext/ssh_core/src/ssh_ipc.hrl +80 -0
- data/service/ssh/ext/ssh_core/src/ssh_ipc_coalesce.erl +94 -0
- data/service/ssh/ext/ssh_core/src/ssh_ipc_gateway.erl +467 -0
- data/service/ssh/ext/ssh_core/src/ssh_ipc_proto.erl +95 -0
- data/service/ssh/ext/ssh_core/src/ssh_jump_chain.erl +101 -0
- data/service/ssh/ext/ssh_core/src/ssh_keepalive_mgr.erl +222 -0
- data/service/ssh/ext/ssh_core/src/ssh_known_hosts_proxy.erl +67 -0
- data/service/ssh/ext/ssh_core/src/ssh_port_fwd.erl +225 -0
- data/service/ssh/ext/ssh_core/src/ssh_sftp_session.erl +250 -0
- data/service/ssh/ext/ssh_core/src/ssh_sftp_sup.erl +62 -0
- data/service/ssh/ext/ssh_core_rs/Cargo.lock +2345 -0
- data/service/ssh/ext/ssh_core_rs/Cargo.toml +30 -0
- data/service/ssh/ext/ssh_core_rs/bin/ssh_core_rs +34 -0
- data/service/ssh/ext/ssh_core_rs/bin/ssh_core_rs.cmd +40 -0
- data/service/ssh/ext/ssh_core_rs/src/channel.rs +296 -0
- data/service/ssh/ext/ssh_core_rs/src/coalesce.rs +143 -0
- data/service/ssh/ext/ssh_core_rs/src/codec.rs +71 -0
- data/service/ssh/ext/ssh_core_rs/src/conn.rs +628 -0
- data/service/ssh/ext/ssh_core_rs/src/gateway.rs +389 -0
- data/service/ssh/ext/ssh_core_rs/src/handler.rs +293 -0
- data/service/ssh/ext/ssh_core_rs/src/keepalive.rs +194 -0
- data/service/ssh/ext/ssh_core_rs/src/main.rs +351 -0
- data/service/ssh/ext/ssh_core_rs/src/portfwd.rs +378 -0
- data/service/ssh/ext/ssh_core_rs/src/proto.rs +198 -0
- data/service/ssh/ext/ssh_core_rs/src/sftp.rs +294 -0
- data/service/ssh/lib/network_infra_utility/ssh/automation/macro_engine.rb +213 -0
- data/service/ssh/lib/network_infra_utility/ssh/client.rb +257 -0
- data/service/ssh/lib/network_infra_utility/ssh/config/schema.rb +90 -0
- data/service/ssh/lib/network_infra_utility/ssh/config/settings.rb +103 -0
- data/service/ssh/lib/network_infra_utility/ssh/config/store.rb +90 -0
- data/service/ssh/lib/network_infra_utility/ssh/ipc/coalesce.rb +83 -0
- data/service/ssh/lib/network_infra_utility/ssh/ipc/errors.rb +36 -0
- data/service/ssh/lib/network_infra_utility/ssh/ipc/router.rb +212 -0
- data/service/ssh/lib/network_infra_utility/ssh/ipc/transport.rb +81 -0
- data/service/ssh/lib/network_infra_utility/ssh/security/host_key.rb +211 -0
- data/service/ssh/lib/network_infra_utility/ssh/security/vault.rb +211 -0
- data/service/ssh/lib/network_infra_utility/ssh/session/history.rb +56 -0
- data/service/ssh/lib/network_infra_utility/ssh/session/manager.rb +92 -0
- data/service/ssh/lib/network_infra_utility/ssh/session/session.rb +109 -0
- data/service/ssh/lib/network_infra_utility/ssh/session/tree.rb +95 -0
- data/service/ssh/lib/network_infra_utility/ssh/terminal/ansi_parser.rb +435 -0
- data/service/ssh/lib/network_infra_utility/ssh/terminal/buffer.rb +78 -0
- data/service/ssh/lib/network_infra_utility/ssh/terminal/emulator.rb +159 -0
- data/service/ssh/lib/network_infra_utility/ssh/terminal/logger.rb +195 -0
- data/service/ssh/lib/network_infra_utility/ssh/terminal/screen.rb +212 -0
- data/service/ssh/lib/network_infra_utility/ssh/terminal/theme.rb +127 -0
- data/service/ssh/lib/network_infra_utility/ssh/version.rb +7 -0
- data/service/ssh/lib/network_infra_utility/ssh.rb +44 -0
- data/support/basic/as_num.rb +221 -0
- data/support/basic/mac_address.rb +281 -0
- data/version.rb +1 -1
- metadata +142 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
//! 保活管理器 — 周期性检查所有活动连接,发送 keepalive 心跳。
|
|
2
|
+
//! 对应 Erlang 端的 ssh_keepalive_mgr.erl。
|
|
3
|
+
//!
|
|
4
|
+
//! 核心设计(与 Erlang 端完全对齐):
|
|
5
|
+
//! - 定时扫描所有 Ready 状态的连接,发送 keepalive 全局请求
|
|
6
|
+
//! - 连续 KEEPALIVE_MAX_FAIL(3)次失败 → 推送 conn.closed
|
|
7
|
+
//! - 重连决策由 Ruby 决定(通过 conn.reconnect RPC),核心不自主重连
|
|
8
|
+
//! - 活动感知:有数据流时跳过心跳(简化版:由 channel.rs 通知活动)
|
|
9
|
+
//!
|
|
10
|
+
//! RPC 方法:
|
|
11
|
+
//! - keepalive.set_interval:设置心跳间隔
|
|
12
|
+
//! - keepalive.get_interval:获取当前间隔
|
|
13
|
+
//! - keepalive.get_status:获取所有连接的保活状态
|
|
14
|
+
|
|
15
|
+
use std::collections::HashMap;
|
|
16
|
+
use std::sync::Arc;
|
|
17
|
+
use std::time::Duration;
|
|
18
|
+
|
|
19
|
+
use serde_json::{json, Value};
|
|
20
|
+
use tokio::sync::{Mutex, RwLock};
|
|
21
|
+
use tracing::{debug, warn};
|
|
22
|
+
|
|
23
|
+
use crate::codec;
|
|
24
|
+
use crate::conn::ConnManager;
|
|
25
|
+
use crate::gateway::Gateway;
|
|
26
|
+
use crate::proto;
|
|
27
|
+
|
|
28
|
+
/// 默认保活间隔(毫秒)
|
|
29
|
+
const KEEPALIVE_DEFAULT_INTERVAL_MS: u64 = 30_000;
|
|
30
|
+
|
|
31
|
+
/// 最大连续失败次数
|
|
32
|
+
const KEEPALIVE_MAX_FAIL: u32 = 3;
|
|
33
|
+
|
|
34
|
+
/// 保活管理器
|
|
35
|
+
pub struct KeepaliveMgr {
|
|
36
|
+
/// 心跳间隔(毫秒)
|
|
37
|
+
interval_ms: RwLock<u64>,
|
|
38
|
+
/// 失败计数:conn_id → count
|
|
39
|
+
fail_counts: Mutex<HashMap<String, u32>>,
|
|
40
|
+
/// 最近活动时间戳:conn_id → unix_ms
|
|
41
|
+
last_activity: Mutex<HashMap<String, u64>>,
|
|
42
|
+
/// 上次检查时间戳:conn_id → unix_ms
|
|
43
|
+
last_check: Mutex<HashMap<String, u64>>,
|
|
44
|
+
/// 连接管理器引用
|
|
45
|
+
conn_mgr: Arc<ConnManager>,
|
|
46
|
+
/// 网关引用
|
|
47
|
+
gateway: Arc<Gateway>,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
impl KeepaliveMgr {
|
|
51
|
+
pub fn new(conn_mgr: Arc<ConnManager>, gateway: Arc<Gateway>) -> Arc<Self> {
|
|
52
|
+
Arc::new(Self {
|
|
53
|
+
interval_ms: RwLock::new(KEEPALIVE_DEFAULT_INTERVAL_MS),
|
|
54
|
+
fail_counts: Mutex::new(HashMap::new()),
|
|
55
|
+
last_activity: Mutex::new(HashMap::new()),
|
|
56
|
+
last_check: Mutex::new(HashMap::new()),
|
|
57
|
+
conn_mgr,
|
|
58
|
+
gateway,
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// 启动保活循环
|
|
63
|
+
pub fn start(self: &Arc<Self>) {
|
|
64
|
+
let this = Arc::clone(self);
|
|
65
|
+
tokio::spawn(async move {
|
|
66
|
+
this.run_loop().await;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// 保活主循环
|
|
71
|
+
async fn run_loop(&self) {
|
|
72
|
+
loop {
|
|
73
|
+
let ms = *self.interval_ms.read().await;
|
|
74
|
+
tokio::time::sleep(Duration::from_millis(ms)).await;
|
|
75
|
+
self.tick().await;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// 单次保活检查
|
|
80
|
+
async fn tick(&self) {
|
|
81
|
+
let now = codec::unix_ms();
|
|
82
|
+
let conn_ids = self.conn_mgr.ready_conn_ids().await;
|
|
83
|
+
|
|
84
|
+
// 记录检查时间
|
|
85
|
+
{
|
|
86
|
+
let mut checks = self.last_check.lock().await;
|
|
87
|
+
for id in &conn_ids {
|
|
88
|
+
checks.insert(id.clone(), now);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
for conn_id in &conn_ids {
|
|
93
|
+
self.check_keepalive(conn_id).await;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 清理已断开的连接
|
|
97
|
+
let active_ids: std::collections::HashSet<String> = conn_ids.into_iter().collect();
|
|
98
|
+
{
|
|
99
|
+
let mut fails = self.fail_counts.lock().await;
|
|
100
|
+
fails.retain(|k, _| active_ids.contains(k));
|
|
101
|
+
}
|
|
102
|
+
{
|
|
103
|
+
let mut acts = self.last_activity.lock().await;
|
|
104
|
+
acts.retain(|k, _| active_ids.contains(k));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// 检查单个连接的保活
|
|
109
|
+
async fn check_keepalive(&self, conn_id: &str) {
|
|
110
|
+
// 发送 keepalive 全局请求
|
|
111
|
+
let handle = self.conn_mgr.get_handle(conn_id).await;
|
|
112
|
+
if handle.is_none() {
|
|
113
|
+
// 连接已断开
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
let handle = handle.unwrap();
|
|
117
|
+
|
|
118
|
+
let result = handle
|
|
119
|
+
.send_keepalive(true)
|
|
120
|
+
.await;
|
|
121
|
+
|
|
122
|
+
match result {
|
|
123
|
+
Ok(_) => {
|
|
124
|
+
// 成功——重置失败计数
|
|
125
|
+
self.fail_counts.lock().await.remove(conn_id);
|
|
126
|
+
debug!("keepalive ok for conn {}", conn_id);
|
|
127
|
+
}
|
|
128
|
+
Err(e) => {
|
|
129
|
+
let mut fails = self.fail_counts.lock().await;
|
|
130
|
+
let count = fails.entry(conn_id.to_string()).or_insert(0);
|
|
131
|
+
*count += 1;
|
|
132
|
+
|
|
133
|
+
if *count >= KEEPALIVE_MAX_FAIL {
|
|
134
|
+
warn!(
|
|
135
|
+
"conn {} keepalive failed {}/{}: {}, marking closed",
|
|
136
|
+
conn_id, *count, KEEPALIVE_MAX_FAIL, e
|
|
137
|
+
);
|
|
138
|
+
drop(fails);
|
|
139
|
+
self.conn_mgr
|
|
140
|
+
.mark_conn_closed(conn_id, "keepalive_failed")
|
|
141
|
+
.await;
|
|
142
|
+
} else {
|
|
143
|
+
warn!(
|
|
144
|
+
"conn {} keepalive failed {}/{}: {}",
|
|
145
|
+
conn_id, *count, KEEPALIVE_MAX_FAIL, e
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/// 通知活动(由 channel.rs 在数据收发时调用)
|
|
153
|
+
pub async fn notify_activity(&self, conn_id: &str) {
|
|
154
|
+
let now = codec::unix_ms();
|
|
155
|
+
self.last_activity.lock().await.insert(conn_id.to_string(), now);
|
|
156
|
+
self.fail_counts.lock().await.remove(conn_id);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/// RPC: keepalive.set_interval
|
|
160
|
+
pub async fn rpc_set_interval(&self, params: Value) -> Result<Value, String> {
|
|
161
|
+
let interval_ms = proto::get_num(¶ms, "interval_ms")
|
|
162
|
+
.ok_or("missing interval_ms")? as u64;
|
|
163
|
+
*self.interval_ms.write().await = interval_ms;
|
|
164
|
+
Ok(json!({"ok": true}))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/// RPC: keepalive.get_interval
|
|
168
|
+
pub async fn rpc_get_interval(&self, _params: Value) -> Result<Value, String> {
|
|
169
|
+
let ms = *self.interval_ms.read().await;
|
|
170
|
+
Ok(json!({"interval_ms": ms}))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/// RPC: keepalive.get_status
|
|
174
|
+
pub async fn rpc_get_status(&self, _params: Value) -> Result<Value, String> {
|
|
175
|
+
let fails = self.fail_counts.lock().await;
|
|
176
|
+
let acts = self.last_activity.lock().await;
|
|
177
|
+
let checks = self.last_check.lock().await;
|
|
178
|
+
|
|
179
|
+
let conn_ids = self.conn_mgr.all_conn_ids().await;
|
|
180
|
+
let status: Vec<Value> = conn_ids
|
|
181
|
+
.iter()
|
|
182
|
+
.map(|id| {
|
|
183
|
+
json!({
|
|
184
|
+
"conn_id": id,
|
|
185
|
+
"fail_count": fails.get(id).copied().unwrap_or(0),
|
|
186
|
+
"last_activity": acts.get(id).copied().unwrap_or(0),
|
|
187
|
+
"last_check": checks.get(id).copied().unwrap_or(0),
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
.collect();
|
|
191
|
+
|
|
192
|
+
Ok(json!({"connections": status}))
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
//! SSH Core RS — 主入口
|
|
2
|
+
//! 对应 Erlang 端的 ssh_core_app.erl + ssh_infra_sup.erl + ssh_ipc_gateway.erl:start_link/1。
|
|
3
|
+
//!
|
|
4
|
+
//! 启动流程:
|
|
5
|
+
//! 1. 生成 auth_token
|
|
6
|
+
//! 2. 删除旧的端点文件
|
|
7
|
+
//! 3. 创建 Gateway(TCP 监听 127.0.0.1:0,分配端口)
|
|
8
|
+
//! 4. 写入端点文件(tcp://127.0.0.1:port\n auth_token)
|
|
9
|
+
//! 5. 创建 ConnManager、Coalescer、ChannelManager、KeepaliveMgr
|
|
10
|
+
//! 6. 注册所有 RPC 路由
|
|
11
|
+
//! 7. 启动 coalesce tick 循环和 keepalive 循环
|
|
12
|
+
//! 8. 进入 gateway accept 循环(阻塞)
|
|
13
|
+
|
|
14
|
+
mod codec;
|
|
15
|
+
mod coalesce;
|
|
16
|
+
mod channel;
|
|
17
|
+
mod conn;
|
|
18
|
+
mod gateway;
|
|
19
|
+
mod handler;
|
|
20
|
+
mod keepalive;
|
|
21
|
+
mod portfwd;
|
|
22
|
+
mod proto;
|
|
23
|
+
mod sftp;
|
|
24
|
+
|
|
25
|
+
use std::path::PathBuf;
|
|
26
|
+
use std::sync::Arc;
|
|
27
|
+
|
|
28
|
+
use serde_json::{json, Value};
|
|
29
|
+
use tracing::{error, info};
|
|
30
|
+
|
|
31
|
+
use channel::ChannelManager;
|
|
32
|
+
use conn::ConnManager;
|
|
33
|
+
use gateway::Gateway;
|
|
34
|
+
use keepalive::KeepaliveMgr;
|
|
35
|
+
use coalesce::Coalescer;
|
|
36
|
+
use portfwd::PortFwdManager;
|
|
37
|
+
use sftp::SftpManager;
|
|
38
|
+
use std::time::Instant;
|
|
39
|
+
|
|
40
|
+
/// 端点文件路径:与 Erlang 端完全一致
|
|
41
|
+
/// Windows: %TEMP%\ssh_core_<USERNAME>.endpoint
|
|
42
|
+
/// Unix: /tmp/ssh_core_<uid>.endpoint
|
|
43
|
+
fn endpoint_file_path() -> PathBuf {
|
|
44
|
+
let tmp = std::env::temp_dir();
|
|
45
|
+
let uid = if cfg!(windows) {
|
|
46
|
+
std::env::var("USERNAME").unwrap_or_else(|_| "default".to_string())
|
|
47
|
+
} else {
|
|
48
|
+
std::env::var("UID").unwrap_or_else(|_| {
|
|
49
|
+
// 尝试通过 id -u 获取 uid
|
|
50
|
+
std::process::Command::new("id")
|
|
51
|
+
.arg("-u")
|
|
52
|
+
.output()
|
|
53
|
+
.ok()
|
|
54
|
+
.and_then(|o| String::from_utf8(o.stdout).ok())
|
|
55
|
+
.map(|s| s.trim().to_string())
|
|
56
|
+
.unwrap_or_else(|| "0".to_string())
|
|
57
|
+
})
|
|
58
|
+
};
|
|
59
|
+
tmp.join(format!("ssh_core_{}.endpoint", uid))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#[tokio::main]
|
|
63
|
+
async fn main() {
|
|
64
|
+
// 初始化日志
|
|
65
|
+
tracing_subscriber::fmt()
|
|
66
|
+
.with_env_filter(
|
|
67
|
+
tracing_subscriber::EnvFilter::try_from_default_env()
|
|
68
|
+
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
|
|
69
|
+
)
|
|
70
|
+
.init();
|
|
71
|
+
|
|
72
|
+
info!("ssh_core_rs starting up...");
|
|
73
|
+
|
|
74
|
+
// 0. 记录启动时间(用于 engine.stats 的 uptime_ms)
|
|
75
|
+
let start_time = Instant::now();
|
|
76
|
+
|
|
77
|
+
// 1. 生成 auth_token
|
|
78
|
+
let auth_token = codec::gen_auth_token();
|
|
79
|
+
|
|
80
|
+
// 2. 删除旧端点文件
|
|
81
|
+
let endpoint_file = endpoint_file_path();
|
|
82
|
+
if endpoint_file.exists() {
|
|
83
|
+
let _ = std::fs::remove_file(&endpoint_file);
|
|
84
|
+
}
|
|
85
|
+
info!("endpoint file: {}", endpoint_file.display());
|
|
86
|
+
|
|
87
|
+
// 3. 创建 Gateway
|
|
88
|
+
let gateway = Gateway::new(auth_token);
|
|
89
|
+
|
|
90
|
+
// 4. 创建各管理器
|
|
91
|
+
let conn_mgr = ConnManager::new(Arc::clone(&gateway));
|
|
92
|
+
let coalesce = Coalescer::new(Arc::clone(&gateway));
|
|
93
|
+
let channel_mgr = ChannelManager::new(Arc::clone(&conn_mgr), Arc::clone(&coalesce));
|
|
94
|
+
let keepalive_mgr = KeepaliveMgr::new(Arc::clone(&conn_mgr), Arc::clone(&gateway));
|
|
95
|
+
let sftp_mgr = SftpManager::new(Arc::clone(&conn_mgr));
|
|
96
|
+
let portfwd_mgr = PortFwdManager::new(Arc::clone(&conn_mgr));
|
|
97
|
+
|
|
98
|
+
// 5. 注册所有 RPC 路由
|
|
99
|
+
register_routes(
|
|
100
|
+
&gateway,
|
|
101
|
+
&conn_mgr,
|
|
102
|
+
&channel_mgr,
|
|
103
|
+
&keepalive_mgr,
|
|
104
|
+
&sftp_mgr,
|
|
105
|
+
&portfwd_mgr,
|
|
106
|
+
start_time,
|
|
107
|
+
)
|
|
108
|
+
.await;
|
|
109
|
+
|
|
110
|
+
// 6. 启动 coalesce tick 循环
|
|
111
|
+
coalesce.start();
|
|
112
|
+
|
|
113
|
+
// 7. 启动 keepalive 循环
|
|
114
|
+
keepalive_mgr.start();
|
|
115
|
+
|
|
116
|
+
// 8. 启动 Gateway(写入端点文件 + accept 循环)
|
|
117
|
+
info!("starting IPC gateway...");
|
|
118
|
+
if let Err(e) = gateway.start(endpoint_file).await {
|
|
119
|
+
error!("gateway failed: {}", e);
|
|
120
|
+
std::process::exit(1);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/// 注册所有 JSON-RPC 路由
|
|
125
|
+
async fn register_routes(
|
|
126
|
+
gateway: &Arc<Gateway>,
|
|
127
|
+
conn_mgr: &Arc<ConnManager>,
|
|
128
|
+
channel_mgr: &Arc<ChannelManager>,
|
|
129
|
+
keepalive_mgr: &Arc<KeepaliveMgr>,
|
|
130
|
+
sftp_mgr: &Arc<SftpManager>,
|
|
131
|
+
portfwd_mgr: &Arc<PortFwdManager>,
|
|
132
|
+
start_time: Instant,
|
|
133
|
+
) {
|
|
134
|
+
// --- 连接管理 ---
|
|
135
|
+
let cm = Arc::clone(conn_mgr);
|
|
136
|
+
gateway
|
|
137
|
+
.register_route("conn.connect", move |params| {
|
|
138
|
+
let cm = Arc::clone(&cm);
|
|
139
|
+
async move { cm.rpc_connect(params).await }
|
|
140
|
+
})
|
|
141
|
+
.await;
|
|
142
|
+
|
|
143
|
+
let cm = Arc::clone(conn_mgr);
|
|
144
|
+
gateway
|
|
145
|
+
.register_route("conn.disconnect", move |params| {
|
|
146
|
+
let cm = Arc::clone(&cm);
|
|
147
|
+
async move { cm.rpc_disconnect(params).await }
|
|
148
|
+
})
|
|
149
|
+
.await;
|
|
150
|
+
|
|
151
|
+
let cm = Arc::clone(conn_mgr);
|
|
152
|
+
gateway
|
|
153
|
+
.register_route("conn.list", move |params| {
|
|
154
|
+
let cm = Arc::clone(&cm);
|
|
155
|
+
async move { cm.rpc_list(params).await }
|
|
156
|
+
})
|
|
157
|
+
.await;
|
|
158
|
+
|
|
159
|
+
let cm = Arc::clone(conn_mgr);
|
|
160
|
+
gateway
|
|
161
|
+
.register_route("conn.reconnect", move |params| {
|
|
162
|
+
let cm = Arc::clone(&cm);
|
|
163
|
+
async move { cm.rpc_reconnect(params).await }
|
|
164
|
+
})
|
|
165
|
+
.await;
|
|
166
|
+
|
|
167
|
+
// --- 通道管理 ---
|
|
168
|
+
let chm = Arc::clone(channel_mgr);
|
|
169
|
+
gateway
|
|
170
|
+
.register_route("channel.open", move |params| {
|
|
171
|
+
let chm = Arc::clone(&chm);
|
|
172
|
+
async move { chm.rpc_open(params).await }
|
|
173
|
+
})
|
|
174
|
+
.await;
|
|
175
|
+
|
|
176
|
+
let chm = Arc::clone(channel_mgr);
|
|
177
|
+
gateway
|
|
178
|
+
.register_route("channel.send", move |params| {
|
|
179
|
+
let chm = Arc::clone(&chm);
|
|
180
|
+
async move { chm.rpc_send(params).await }
|
|
181
|
+
})
|
|
182
|
+
.await;
|
|
183
|
+
|
|
184
|
+
let chm = Arc::clone(channel_mgr);
|
|
185
|
+
gateway
|
|
186
|
+
.register_route("channel.close", move |params| {
|
|
187
|
+
let chm = Arc::clone(&chm);
|
|
188
|
+
async move { chm.rpc_close(params).await }
|
|
189
|
+
})
|
|
190
|
+
.await;
|
|
191
|
+
|
|
192
|
+
let chm = Arc::clone(channel_mgr);
|
|
193
|
+
gateway
|
|
194
|
+
.register_route("channel.window_change", move |params| {
|
|
195
|
+
let chm = Arc::clone(&chm);
|
|
196
|
+
async move { chm.rpc_window_change(params).await }
|
|
197
|
+
})
|
|
198
|
+
.await;
|
|
199
|
+
|
|
200
|
+
// --- 保活管理 ---
|
|
201
|
+
let km = Arc::clone(keepalive_mgr);
|
|
202
|
+
gateway
|
|
203
|
+
.register_route("keepalive.set_interval", move |params| {
|
|
204
|
+
let km = Arc::clone(&km);
|
|
205
|
+
async move { km.rpc_set_interval(params).await }
|
|
206
|
+
})
|
|
207
|
+
.await;
|
|
208
|
+
|
|
209
|
+
let km = Arc::clone(keepalive_mgr);
|
|
210
|
+
gateway
|
|
211
|
+
.register_route("keepalive.get_interval", move |params| {
|
|
212
|
+
let km = Arc::clone(&km);
|
|
213
|
+
async move { km.rpc_get_interval(params).await }
|
|
214
|
+
})
|
|
215
|
+
.await;
|
|
216
|
+
|
|
217
|
+
let km = Arc::clone(keepalive_mgr);
|
|
218
|
+
gateway
|
|
219
|
+
.register_route("keepalive.get_status", move |params| {
|
|
220
|
+
let km = Arc::clone(&km);
|
|
221
|
+
async move { km.rpc_get_status(params).await }
|
|
222
|
+
})
|
|
223
|
+
.await;
|
|
224
|
+
|
|
225
|
+
// --- 引擎管理 ---
|
|
226
|
+
gateway
|
|
227
|
+
.register_route("engine.ping", move |_params| {
|
|
228
|
+
async move { Ok(json!({"ok": true, "timestamp": codec::unix_ms()})) }
|
|
229
|
+
})
|
|
230
|
+
.await;
|
|
231
|
+
|
|
232
|
+
let cm2 = Arc::clone(conn_mgr);
|
|
233
|
+
gateway
|
|
234
|
+
.register_route("engine.stats", move |_params| {
|
|
235
|
+
let cm2 = Arc::clone(&cm2);
|
|
236
|
+
let st = start_time;
|
|
237
|
+
async move {
|
|
238
|
+
let conn_count = cm2.all_conn_ids().await.len();
|
|
239
|
+
let uptime_ms = st.elapsed().as_millis() as u64;
|
|
240
|
+
Ok(json!({
|
|
241
|
+
"connections": conn_count,
|
|
242
|
+
"uptime_ms": uptime_ms
|
|
243
|
+
}))
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
.await;
|
|
247
|
+
|
|
248
|
+
gateway
|
|
249
|
+
.register_route("engine.shutdown", move |_params| {
|
|
250
|
+
async move {
|
|
251
|
+
info!("engine.shutdown received, exiting...");
|
|
252
|
+
tokio::spawn(async {
|
|
253
|
+
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
|
254
|
+
std::process::exit(0);
|
|
255
|
+
});
|
|
256
|
+
Ok(json!({"ok": true}))
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
.await;
|
|
260
|
+
|
|
261
|
+
// --- bye ---
|
|
262
|
+
gateway
|
|
263
|
+
.register_route("bye", move |_params| {
|
|
264
|
+
async move { Ok(json!({"ok": true})) }
|
|
265
|
+
})
|
|
266
|
+
.await;
|
|
267
|
+
|
|
268
|
+
// --- SFTP ---
|
|
269
|
+
let sm = Arc::clone(sftp_mgr);
|
|
270
|
+
gateway
|
|
271
|
+
.register_route("sftp.open", move |params| {
|
|
272
|
+
let sm = Arc::clone(&sm);
|
|
273
|
+
async move { sm.rpc_open(params).await }
|
|
274
|
+
})
|
|
275
|
+
.await;
|
|
276
|
+
|
|
277
|
+
let sm = Arc::clone(sftp_mgr);
|
|
278
|
+
gateway
|
|
279
|
+
.register_route("sftp.list_dir", move |params| {
|
|
280
|
+
let sm = Arc::clone(&sm);
|
|
281
|
+
async move { sm.rpc_list_dir(params).await }
|
|
282
|
+
})
|
|
283
|
+
.await;
|
|
284
|
+
|
|
285
|
+
let sm = Arc::clone(sftp_mgr);
|
|
286
|
+
gateway
|
|
287
|
+
.register_route("sftp.download", move |params| {
|
|
288
|
+
let sm = Arc::clone(&sm);
|
|
289
|
+
async move { sm.rpc_download(params).await }
|
|
290
|
+
})
|
|
291
|
+
.await;
|
|
292
|
+
|
|
293
|
+
let sm = Arc::clone(sftp_mgr);
|
|
294
|
+
gateway
|
|
295
|
+
.register_route("sftp.upload", move |params| {
|
|
296
|
+
let sm = Arc::clone(&sm);
|
|
297
|
+
async move { sm.rpc_upload(params).await }
|
|
298
|
+
})
|
|
299
|
+
.await;
|
|
300
|
+
|
|
301
|
+
let sm = Arc::clone(sftp_mgr);
|
|
302
|
+
gateway
|
|
303
|
+
.register_route("sftp.mkdir", move |params| {
|
|
304
|
+
let sm = Arc::clone(&sm);
|
|
305
|
+
async move { sm.rpc_mkdir(params).await }
|
|
306
|
+
})
|
|
307
|
+
.await;
|
|
308
|
+
|
|
309
|
+
let sm = Arc::clone(sftp_mgr);
|
|
310
|
+
gateway
|
|
311
|
+
.register_route("sftp.remove", move |params| {
|
|
312
|
+
let sm = Arc::clone(&sm);
|
|
313
|
+
async move { sm.rpc_remove(params).await }
|
|
314
|
+
})
|
|
315
|
+
.await;
|
|
316
|
+
|
|
317
|
+
let sm = Arc::clone(sftp_mgr);
|
|
318
|
+
gateway
|
|
319
|
+
.register_route("sftp.stat", move |params| {
|
|
320
|
+
let sm = Arc::clone(&sm);
|
|
321
|
+
async move { sm.rpc_stat(params).await }
|
|
322
|
+
})
|
|
323
|
+
.await;
|
|
324
|
+
|
|
325
|
+
// --- 端口转发 ---
|
|
326
|
+
let pm = Arc::clone(portfwd_mgr);
|
|
327
|
+
gateway
|
|
328
|
+
.register_route("portfwd.add", move |params| {
|
|
329
|
+
let pm = Arc::clone(&pm);
|
|
330
|
+
async move { pm.rpc_add(params).await }
|
|
331
|
+
})
|
|
332
|
+
.await;
|
|
333
|
+
|
|
334
|
+
let pm = Arc::clone(portfwd_mgr);
|
|
335
|
+
gateway
|
|
336
|
+
.register_route("portfwd.remove", move |params| {
|
|
337
|
+
let pm = Arc::clone(&pm);
|
|
338
|
+
async move { pm.rpc_remove(params).await }
|
|
339
|
+
})
|
|
340
|
+
.await;
|
|
341
|
+
|
|
342
|
+
let pm = Arc::clone(portfwd_mgr);
|
|
343
|
+
gateway
|
|
344
|
+
.register_route("portfwd.list", move |params| {
|
|
345
|
+
let pm = Arc::clone(&pm);
|
|
346
|
+
async move { pm.rpc_list(params).await }
|
|
347
|
+
})
|
|
348
|
+
.await;
|
|
349
|
+
|
|
350
|
+
info!("all RPC routes registered");
|
|
351
|
+
}
|