gitdataai/libs/git/ssh/server.rs
ZhenYi eeb99bf628
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
refactor(git): drop hook pool, sync execution is now direct and sequential
- Remove entire pool/ directory (RedisConsumer, CpuMonitor, LogStream, HookTask, TaskType)
- Remove Redis distributed lock (acquire_lock/release_lock) — K8s StatefulSet
  scheduling guarantees exclusive access per repo shard
- Remove sync/lock.rs, sync/remote.rs, sync/status.rs (dead code)
- Remove hook/event.rs (GitHookEvent was never used)
- New HookService exposes sync_repo / fsck_repo / gc_repo directly
- ReceiveSyncService now calls HookService inline instead of LPUSH to Redis queue
- sync/mod.rs: git2 operations wrapped in spawn_blocking for Send safety
  (git2 types are not Send — async git2 operations must not cross await points)
- scripts/push.js: drop 'frontend' from docker push list (embedded into static binary)
2026-04-17 12:22:09 +08:00

100 lines
2.9 KiB
Rust

use crate::hook::HookService;
use crate::ssh::ReceiveSyncService;
use crate::ssh::SshTokenService;
use crate::ssh::handle::SSHandle;
use db::cache::AppCache;
use db::database::AppDatabase;
use deadpool_redis::cluster::Pool as RedisPool;
use russh::server::Handler;
use slog::{Logger, info, warn};
use std::io;
use std::net::SocketAddr;
pub struct SSHServer {
pub db: AppDatabase,
pub cache: AppCache,
pub redis_pool: RedisPool,
pub logger: Logger,
pub token_service: SshTokenService,
pub hook: HookService,
}
impl SSHServer {
pub fn new(
db: AppDatabase,
cache: AppCache,
redis_pool: RedisPool,
logger: Logger,
token_service: SshTokenService,
hook: HookService,
) -> Self {
SSHServer {
db,
cache,
redis_pool,
logger,
token_service,
hook,
}
}
}
impl russh::server::Server for SSHServer {
type Handler = SSHandle;
fn new_client(&mut self, addr: Option<SocketAddr>) -> Self::Handler {
if let Some(addr) = addr {
info!(
self.logger,
"New SSH connection from {}:{}",
addr.ip(),
addr.port()
);
} else {
info!(self.logger, "New SSH connection from unknown address");
}
let sync_service = ReceiveSyncService::new(self.hook.clone());
SSHandle::new(
self.db.clone(),
self.cache.clone(),
sync_service,
self.logger.clone(),
self.token_service.clone(),
addr,
)
}
fn handle_session_error(&mut self, error: <Self::Handler as Handler>::Error) {
match error {
russh::Error::Disconnect => {
info!(self.logger, "Connection disconnected by peer");
}
russh::Error::Inconsistent => {
warn!(self.logger, "Protocol inconsistency detected");
}
russh::Error::NotAuthenticated => {
warn!(self.logger, "Authentication failed");
}
russh::Error::IO(ref io_err) => {
let error_msg = format!(
"IO error: kind={:?}, message={}, raw_os_error={:?}",
io_err.kind(),
io_err,
io_err.raw_os_error()
);
warn!(self.logger, "{}", error_msg);
if io_err.kind() == io::ErrorKind::UnexpectedEof {
warn!(
self.logger,
"Client disconnected during handshake or before authentication"
);
}
}
_ => {
let error_msg = format!("SSH session error: {}", error);
warn!(self.logger, "{}", error_msg);
}
}
}
}