Files
markbase/markbase-core/src/ssh_server/upload_hook.rs

164 lines
5.1 KiB
Rust

use std::path::{Path, PathBuf};
use std::process::Command;
use anyhow::{anyhow, Result};
use log::{info, error};
pub struct UploadHook {
enabled: bool,
video_probe_path: PathBuf,
video_register_cli: PathBuf,
video_register_dir: PathBuf,
video_extensions: Vec<String>,
}
impl UploadHook {
pub fn new(
enabled: bool,
video_probe_path: PathBuf,
video_register_cli: PathBuf,
video_register_dir: PathBuf,
video_extensions: Vec<String>,
) -> Self {
Self {
enabled,
video_probe_path,
video_register_cli,
video_register_dir,
video_extensions,
}
}
pub fn trigger(&self, file_path: &Path, user_uuid: &str) -> Result<()> {
if !self.enabled {
return Ok(());
}
if !self.is_video_file(file_path) {
info!("UploadHook: Skipping non-video file: {:?}", file_path);
return Ok(());
}
info!("UploadHook: Triggering for file {:?} (user={})", file_path, user_uuid);
let probe_json = self.run_video_probe(file_path)?;
let video_uuid = self.run_video_register(&probe_json, user_uuid)?;
info!("UploadHook: Video registered successfully (UUID={})", video_uuid);
Ok(())
}
fn run_video_probe(&self, file_path: &Path) -> Result<PathBuf> {
info!("UploadHook: Running video_probe on {:?}", file_path);
let output = Command::new(&self.video_probe_path)
.arg(file_path)
.output()
.map_err(|e| anyhow!("Failed to execute video_probe: {}", e))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
error!("UploadHook: video_probe failed: {}", stderr);
return Err(anyhow!("video_probe failed with status {}", output.status));
}
let stdout = String::from_utf8_lossy(&output.stdout);
info!("UploadHook: video_probe output: {}", stdout);
let probe_json = file_path.with_extension("probe.json");
Ok(probe_json)
}
fn run_video_register(&self, probe_json: &Path, user_uuid: &str) -> Result<String> {
info!("UploadHook: Running video_register on {:?}", probe_json);
let output = Command::new("python3")
.arg(&self.video_register_cli)
.arg("register")
.arg(probe_json)
.current_dir(&self.video_register_dir)
.env("USER_UUID", user_uuid)
.output()
.map_err(|e| anyhow!("Failed to execute video_register: {}", e))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
error!("UploadHook: video_register failed: {}", stderr);
return Err(anyhow!("video_register failed with status {}", output.status));
}
let stdout = String::from_utf8_lossy(&output.stdout);
info!("UploadHook: video_register output: {}", stdout);
let uuid = stdout
.lines()
.find(|line| line.contains("UUID:") || line.contains("uuid"))
.and_then(|line| {
if line.contains("UUID:") {
line.split(':').nth(1).map(|s| s.trim().to_string())
} else {
Some(line.trim().to_string())
}
})
.unwrap_or_else(|| "unknown".to_string());
Ok(uuid)
}
fn is_video_file(&self, path: &Path) -> bool {
path.extension()
.and_then(|e| e.to_str())
.map(|ext| self.video_extensions.contains(&ext.to_lowercase()))
.unwrap_or(false)
}
}
impl Default for UploadHook {
fn default() -> Self {
Self::new(
false,
PathBuf::from("/Users/accusys/momentry_core_project/video_probe/target/release/video_probe"),
PathBuf::from("cli.py"),
PathBuf::from("/Users/accusys/momentry_core_project/video_register"),
vec![
"mp4".to_string(),
"mov".to_string(),
"avi".to_string(),
"mkv".to_string(),
"webm".to_string(),
"flv".to_string(),
"wmv".to_string(),
"m4v".to_string(),
],
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_video_file() {
let hook = UploadHook::default();
assert!(hook.is_video_file(Path::new("test.mp4")));
assert!(hook.is_video_file(Path::new("test.MOV")));
assert!(hook.is_video_file(Path::new("test.avi")));
assert!(!hook.is_video_file(Path::new("test.txt")));
assert!(!hook.is_video_file(Path::new("test.jpg")));
}
#[test]
fn test_disabled_hook() {
let hook = UploadHook::new(
false,
PathBuf::from("/tmp/video_probe"),
PathBuf::from("cli.py"),
PathBuf::from("/tmp/video_register"),
vec!["mp4".to_string()],
);
let result = hook.trigger(Path::new("/tmp/test.mp4"), "user123");
assert!(result.is_ok());
}
}