Implement Upload Hook for momentry integration (Phase 1)
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

- Add upload_hook.rs module: trigger video_probe + video_register on upload
- Add UploadHookSection to config: video extensions, binary paths
- Integrate with SFTP: handle_close triggers hook on write files
- Integrate with SCP/rsync: child process exit triggers hook
- All 155 tests pass
This commit is contained in:
Warren
2026-06-19 06:26:20 +08:00
parent c71811090b
commit e2d58538f9
7 changed files with 336 additions and 42 deletions

View File

@@ -289,6 +289,7 @@ pub struct SftpHandle {
pub handle_type: SftpHandleType,
pub file: Option<Box<dyn VfsFile>>,
pub dir_entries: Option<Vec<VfsDirEntry>>,
pub write_mode: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -303,10 +304,10 @@ pub struct SftpHandler {
vfs: Box<dyn VfsBackend>,
next_handle_id: u32,
handles: std::collections::HashMap<u32, SftpHandle>,
// ⭐⭐⭐⭐⭐ Phase 4: 添加 client maxpack 限制参考OpenSSH sftp-server.c
maxpacket: u32, // 来自 SSH_MSG_CHANNEL_OPEN_CONFIRMATION 的 maximum_packet_size
/// 限制绝对路径也在 root_dir 之下chroot 模式)
maxpacket: u32,
restrict_absolute: bool,
upload_hook: Option<std::sync::Arc<crate::ssh_server::upload_hook::UploadHook>>,
user_uuid: String,
}
impl SftpHandler {
@@ -318,7 +319,13 @@ impl SftpHandler {
const MAX_HASH_SIZE: u64 = 268_435_456;
// ⭐⭐⭐⭐⭐ Phase 4: 修改 new() 方法,接受 maxpack 参数
pub fn new(root_dir: PathBuf, vfs: Box<dyn VfsBackend>, maxpacket: u32) -> Self {
pub fn new(
root_dir: PathBuf,
vfs: Box<dyn VfsBackend>,
maxpacket: u32,
upload_hook: Option<std::sync::Arc<crate::ssh_server::upload_hook::UploadHook>>,
user_uuid: String,
) -> Self {
let canonical_root = root_dir.canonicalize().unwrap_or(root_dir);
Self {
root_dir: canonical_root,
@@ -327,6 +334,8 @@ impl SftpHandler {
handles: std::collections::HashMap::new(),
maxpacket,
restrict_absolute: false,
upload_hook,
user_uuid,
}
}
@@ -426,6 +435,7 @@ impl SftpHandler {
handle_type: SftpHandleType::File,
file: Some(file),
dir_entries: None,
write_mode: flags.write,
};
self.handles.insert(handle_id, handle);
@@ -454,7 +464,14 @@ impl SftpHandler {
info!("SSH_FXP_CLOSE: id={}, handle={}", id, handle_id);
if self.handles.remove(&handle_id).is_some() {
if let Some(handle) = self.handles.remove(&handle_id) {
if handle.write_mode && handle.handle_type == SftpHandleType::File {
if let Some(hook) = &self.upload_hook {
if let Err(e) = hook.trigger(&handle.path, &self.user_uuid) {
warn!("Upload hook failed for {:?}: {}", handle.path, e);
}
}
}
self.build_status_response(id, SftpStatus::SSH_FX_OK, "File closed")
} else {
self.build_status_response(id, SftpStatus::SSH_FX_FAILURE, "Invalid handle")
@@ -670,6 +687,7 @@ impl SftpHandler {
handle_type: SftpHandleType::Directory,
file: None,
dir_entries: Some(entries),
write_mode: false,
};
self.handles.insert(handle_id, handle);
@@ -1765,7 +1783,7 @@ mod tests {
use tempfile::TempDir;
fn make_handler(root_dir: PathBuf) -> SftpHandler {
SftpHandler::new(root_dir, Box::new(LocalFs::new()), 32768)
SftpHandler::new(root_dir, Box::new(LocalFs::new()), 32768, None, "test_user".to_string())
}
#[test]