diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..76e02c0 --- /dev/null +++ b/.env.template @@ -0,0 +1,107 @@ +# Momentry Studio - 环境变量模板 +# 复制此文件为 .env 并根据实际环境修改 + +# ======================================== +# 用户主目录(自动检测,通常不需要设置) +# ======================================== +# HOME=/Users/your_username + +# ======================================== +# 项目根目录 +# ======================================== +# 默认: $HOME/momentry_core +MOMENTRY_CORE_ROOT=${HOME}/momentry_core + +# 默认: $HOME/markbase +MARKBASE_ROOT=${HOME}/markbase + +# 默认: $HOME/momentry_studio +MOMENTRY_STUDIO_ROOT=${HOME}/momentry_studio + +# 默认: $HOME/momentry +MOMENTRY_ROOT=${HOME}/momentry + +# 默认: $HOME/MarkBaseEngine +MARKBASE_ENGINE_ROOT=${HOME}/MarkBaseEngine + +# ======================================== +# 存储路径 +# ======================================== +# 默认: $HOME/momentry/var/sftpgo/data +STORAGE_ROOT=${HOME}/momentry/var/sftpgo/data + +# 默认: $HOME/momentry/output +OUTPUT_DIR=${HOME}/momentry/output + +# 默认: $HOME/momentry/backup +BACKUP_DIR=${HOME}/momentry/backup + +# ======================================== +# 数据库 +# ======================================== +# SQLite 数据库目录 +MOMENTRY_DATA_DIR=${HOME}/momentry_studio/data/users + +# PostgreSQL 连接字符串 +DATABASE_URL=postgres://$(whoami)@localhost:5432/momentry + +# Qdrant +QDRANT_URL=http://localhost:6333 +QDRANT_API_KEY=your_qdrant_api_key_here + +# Redis (可选) +REDIS_URL=redis://localhost:6379 + +# ======================================== +# API Keys +# ======================================== +# Momentry Core API Key +MOMENTRY_API_KEY=your_momentry_api_key_here + +# ======================================== +# 工具路径 +# ======================================== +# Python (用于脚本) +PYTHON_PATH=/opt/homebrew/bin/python3.11 + +# FFmpeg (用于视频处理) +FFMPEG_PATH=/opt/homebrew/bin/ffmpeg + +# ======================================== +# 服务配置 +# ======================================== +# Core API 端口 +MOMENTRY_SERVER_PORT=3002 + +# Studio Proxy 端口 +STUDIO_PROXY_PORT=8888 + +# MarkBase 端口 +MARKBASE_PORT=11438 + +# ======================================== +# LLM 服务 +# ======================================== +# VLM Vision API +MOMENTRY_LLM_VISION_URL=http://localhost:8080/v1/chat/completions + +# LLM Chat API +MOMENTRY_LLM_CHAT_URL=http://localhost:8080/v1/chat/completions + +# ======================================== +# 外部服务 URL +# ======================================== +# Media Base URL +MEDIA_BASE_URL=https://wp.momentry.ddns.net + +# Serve Base URL +SERVE_BASE_URL=https://m5wp.momentry.ddns.net/files + +# ======================================== +# 说明 +# ======================================== +# 1. 复制此文件: cp .env.template .env +# 2. 编辑 .env 文件,填入实际值 +# 3. 加载环境变量: source .env +# 4. 运行配置生成: ./generate_config.sh +# 5. 启动服务: npm run proxy \ No newline at end of file diff --git a/config/admin_config.json.template b/config/admin_config.json.template new file mode 100644 index 0000000..54ed72f --- /dev/null +++ b/config/admin_config.json.template @@ -0,0 +1,84 @@ +{ + "vlm_prompts": { + "scene": { + "system_prompt": "Analyze this video frame and provide a detailed description.", + "user_prompt_template": "Describe the scene in detail, including environment, objects, and activities.", + "max_tokens": 500, + "temperature": 0.7, + "output_language": "en" + }, + "trace": { + "system_prompt": "Describe the person's appearance and clothing in this frame.", + "user_prompt_template": "Describe the person, focusing on clothing, accessories, and notable features.", + "max_tokens": 300, + "temperature": 0.6, + "output_language": "en" + } + }, + "llm_config": { + "model": "gpt-4o", + "max_tokens": 2000, + "temperature": 0.7, + "api_base": "http://localhost:8080/v1" + }, + "processor_config": { + "asr": { + "enabled": true, + "language": "auto", + "model": "large-v3" + }, + "ocr": { + "enabled": true, + "languages": ["en", "zh"], + "min_confidence": 0.5 + }, + "face": { + "enabled": true, + "min_confidence": 0.7, + "min_size": 32 + } + }, + "filter_config": { + "face": { + "min_confidence": 50.0, + "min_size": 32, + "min_capture_quality": 30.0 + } + }, + "paths": { + "output_dir": "{{HOME}}/momentry/output", + "backup_dir": "{{HOME}}/momentry/backup", + "scripts_dir": "{{HOME}}/momentry_core/scripts", + "python_path": "{{PYTHON_PATH}}", + "ffmpeg_path": "{{FFMPEG_PATH}}" + }, + "concurrency": { + "max_concurrent_jobs": 6, + "poll_interval": 10, + "batch_size": 10, + "processor_timeout_secs": 3600 + }, + "feature_flags": { + "cache_enabled": true, + "auto_pipeline_enabled": false, + "watcher_auto_register": false, + "summary_enabled": true + }, + "server": { + "port": 3002, + "media_base_url": "{{MEDIA_BASE_URL}}", + "serve_base_url": "{{SERVE_BASE_URL}}", + "storage_root": "{{HOME}}/momentry/var/sftpgo/data" + }, + "admin_settings": { + "session_timeout": 3600, + "max_login_attempts": 5, + "api_key_expiry_days": 365, + "system_stats_refresh_sec": 5 + }, + "face_filter_defaults": { + "min_confidence": 50.0, + "min_size": 32, + "min_capture_quality": 25.0 + } +} \ No newline at end of file diff --git a/generate_config.sh b/generate_config.sh new file mode 100755 index 0000000..f8db95f --- /dev/null +++ b/generate_config.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# Momentry Studio - 配置文件生成脚本 +# 用途: 根据当前用户环境生成 admin_config.json +# 使用: ./generate_config.sh + +set -e + +# 获取用户主目录 +USER_HOME="${HOME:-$(pwd)}" +STUDIO_ROOT="$(cd "$(dirname "$0")" && pwd)" + +echo "================================================================================" +echo " Momentry Studio - 配置文件生成" +echo "================================================================================" +echo "" +echo "用户主目录: ${USER_HOME}" +echo "Studio 根目录: ${STUDIO_ROOT}" +echo "" + +# 设置默认值 +PYTHON_PATH="${PYTHON_PATH:-/opt/homebrew/bin/python3.11}" +FFMPEG_PATH="${FFMPEG_PATH:-/opt/homebrew/bin/ffmpeg}" +MEDIA_BASE_URL="${MEDIA_BASE_URL:-https://wp.momentry.ddns.net}" +SERVE_BASE_URL="${SERVE_BASE_URL:-https://m5wp.momentry.ddns.net/files}" + +# 检查模板文件 +TEMPLATE_FILE="${STUDIO_ROOT}/config/admin_config.json.template" +if [ ! -f "${TEMPLATE_FILE}" ]; then + echo "❌ 错误: 找不到模板文件 ${TEMPLATE_FILE}" + exit 1 +fi + +echo "配置值:" +echo " - Python: ${PYTHON_PATH}" +echo " - FFmpeg: ${FFMPEG_PATH}" +echo " - Media Base URL: ${MEDIA_BASE_URL}" +echo " - Serve Base URL: ${SERVE_BASE_URL}" +echo "" + +# 生成配置文件 +OUTPUT_FILE="${STUDIO_ROOT}/config/admin_config.json" + +echo "生成配置文件..." +sed -e "s|{{HOME}}|${USER_HOME}|g" \ + -e "s|{{PYTHON_PATH}}|${PYTHON_PATH}|g" \ + -e "s|{{FFMPEG_PATH}}|${FFMPEG_PATH}|g" \ + -e "s|{{MEDIA_BASE_URL}}|${MEDIA_BASE_URL}|g" \ + -e "s|{{SERVE_BASE_URL}}|${SERVE_BASE_URL}|g" \ + "${TEMPLATE_FILE}" > "${OUTPUT_FILE}" + +if [ $? -eq 0 ]; then + echo "✅ 配置文件已生成: ${OUTPUT_FILE}" + echo "" + echo "生成的路径:" + echo " - Output Dir: ${USER_HOME}/momentry/output" + echo " - Backup Dir: ${USER_HOME}/momentry/backup" + echo " - Scripts Dir: ${USER_HOME}/momentry_core/scripts" + echo " - Storage Root: ${USER_HOME}/momentry/var/sftpgo/data" +else + echo "❌ 配置文件生成失败" + exit 1 +fi + +echo "" +echo "================================================================================" +echo " ✅ 完成" +echo "================================================================================" +echo "" +echo "下一步:" +echo " 1. 检查生成的配置: cat ${OUTPUT_FILE}" +echo " 2. 如需自定义,设置环境变量后重新运行:" +echo " export PYTHON_PATH=/your/path" +echo " export FFMPEG_PATH=/your/path" +echo " ./generate_config.sh" +echo "" \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..a10f797 --- /dev/null +++ b/install.sh @@ -0,0 +1,171 @@ +#!/bin/bash + +# Momentry Studio - 通用安装脚本 +# 适用于任何用户环境 +# 使用: ./install.sh + +set -e + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_step() { + echo -e "${BLUE}[STEP]${NC} $1" +} + +# 获取脚本所在目录 +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +USER_HOME="${HOME:-$(pwd)}" + +echo "================================================================================" +echo " Momentry Studio - 安装向导" +echo "================================================================================" +echo "" +echo "检测到的环境:" +echo " 用户主目录: ${USER_HOME}" +echo " Studio 根目录: ${SCRIPT_DIR}" +echo " 用户名: $(whoami)" +echo "" + +# 步骤 1: 检查依赖 +log_step "步骤 1/6: 检查依赖..." + +check_command() { + local cmd=$1 + local name=$2 + if command -v $cmd &> /dev/null; then + log_info "✅ $name: $(command -v $cmd)" + else + log_error "❌ $name 未安装" + return 1 + fi +} + +check_command "node" "Node.js" || exit 1 +check_command "npm" "npm" || exit 1 +check_command "rustc" "Rust" || exit 1 +check_command "cargo" "Cargo" || exit 1 + +echo "" + +# 步骤 2: 创建环境变量文件 +log_step "步骤 2/6: 创建环境变量文件..." + +if [ -f "${SCRIPT_DIR}/.env" ]; then + log_warn ".env 文件已存在,跳过创建" +else + cp "${SCRIPT_DIR}/.env.template" "${SCRIPT_DIR}/.env" + log_info "✅ 已创建 .env 文件" + log_warn "请编辑 .env 文件,填入实际的 API Keys" +fi + +echo "" + +# 步骤 3: 生成配置文件 +log_step "步骤 3/6: 生成配置文件..." + +chmod +x "${SCRIPT_DIR}/generate_config.sh" +"${SCRIPT_DIR}/generate_config.sh" + +echo "" + +# 步骤 4: 创建数据目录 +log_step "步骤 4/6: 创建数据目录..." + +mkdir -p "${USER_HOME}/momentry/output" +mkdir -p "${USER_HOME}/momentry/backup" +mkdir -p "${USER_HOME}/momentry/var/sftpgo/data" +mkdir -p "${SCRIPT_DIR}/data/users" + +log_info "✅ 已创建数据目录:" +log_info " - Output: ${USER_HOME}/momentry/output" +log_info " - Backup: ${USER_HOME}/momentry/backup" +log_info " - Storage: ${USER_HOME}/momentry/var/sftpgo/data" +log_info " - Database: ${SCRIPT_DIR}/data/users" + +echo "" + +# 步骤 5: 安装依赖并构建 +log_step "步骤 5/6: 安装依赖并构建..." + +cd "${SCRIPT_DIR}" + +log_info "安装 Node.js 依赖..." +npm install + +log_info "构建前端..." +npm run build + +log_info "构建 Rust 代理..." +cd src-tauri +cargo build --release +cd .. + +log_info "✅ 构建完成" + +echo "" + +# 步骤 6: 创建启动脚本 +log_step "步骤 6/6: 创建启动脚本..." + +cat > "${SCRIPT_DIR}/start.sh" << STARTSCRIPT +#!/bin/bash +# Momentry Studio 启动脚本 + +# 加载环境变量 +if [ -f "${SCRIPT_DIR}/.env" ]; then + source "${SCRIPT_DIR}/.env" +fi + +# 设置必要的环境变量 +export MOMENTRY_API_KEY=\${MOMENTRY_API_KEY:-your_api_key_here} +export MOMENTRY_DATA_DIR=\${MOMENTRY_DATA_DIR:-${SCRIPT_DIR}/data/users} + +# 启动代理 +cd "${SCRIPT_DIR}" +./src-tauri/target/release/momentry-proxy +STARTSCRIPT + +chmod +x "${SCRIPT_DIR}/start.sh" + +log_info "✅ 已创建启动脚本: start.sh" + +echo "" + +# 总结 +echo "================================================================================" +echo " ✅ 安装完成" +echo "================================================================================" +echo "" +echo "安装位置:" +echo " Studio 根目录: ${SCRIPT_DIR}" +echo " 配置文件: ${SCRIPT_DIR}/config/admin_config.json" +echo " 环境变量: ${SCRIPT_DIR}/.env" +echo " 数据目录: ${SCRIPT_DIR}/data/users" +echo "" +echo "下一步:" +echo " 1. 编辑环境变量: vim ${SCRIPT_DIR}/.env" +echo " 2. 加载环境变量: source ${SCRIPT_DIR}/.env" +echo " 3. 启动服务: ${SCRIPT_DIR}/start.sh" +echo " 4. 访问: http://localhost:8888" +echo "" +echo "或者使用 npm 命令:" +echo " npm run proxy # 启动代理服务" +echo "" +echo "================================================================================" \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index e0d0f4e..7c939fc 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -5,6 +5,19 @@ use markbase_core::vfs::VfsBackend; mod proxy; mod db; mod validate; +mod paths; + +// Import path helper functions +use paths::{ + get_home_dir, + get_momentry_core_root, + get_markbase_root, + get_studio_root, + get_momentry_root, + get_storage_root, + get_markbase_engine_root, + get_worker_pid_file, +}; use serde::Serialize; use base64::{Engine as _, engine::general_purpose::STANDARD}; @@ -1330,9 +1343,15 @@ async fn merge_history(source_uuid: Option, target_uuid: Option, async fn stop_service(name: String) -> Result { if name == "Worker" || name == "worker" { // Worker has no port — stop via pidfile / pkill + let pid_file = get_worker_pid_file(); + let core_root = get_momentry_core_root(); + let cmd = format!( + "sleep 0.5; WPID=$(cat {} 2>/dev/null); if [ -n \"$WPID\" ]; then pkill -P $WPID 2>/dev/null; kill -9 $WPID 2>/dev/null; fi; pkill -9 -f 'target/release/momentry worker' 2>/dev/null; rm -f {}; echo 'stopped'", + pid_file, pid_file + ); let output = std::process::Command::new("sh") .arg("-c") - .arg("sleep 0.5; WPID=$(cat /Users/accusys/momentry_core/logs/worker_3002.pid 2>/dev/null); if [ -n \"$WPID\" ]; then pkill -P $WPID 2>/dev/null; kill -9 $WPID 2>/dev/null; fi; pkill -9 -f 'target/release/momentry worker' 2>/dev/null; rm -f /Users/accusys/momentry_core/logs/worker_3002.pid; echo 'stopped'") + .arg(&cmd) .output() .map_err(|e| format!("Failed to stop worker: {}", e))?; let stdout = String::from_utf8_lossy(&output.stdout).to_string(); @@ -1360,9 +1379,11 @@ async fn stop_service(name: String) -> Result { async fn start_service(name: String) -> Result { if name == "Worker" || name == "worker" { // Worker has no port — verify via pidfile instead of lsof + let core_root = get_momentry_core_root(); + let cmd = format!("cd {} && nohup bash run-worker-3002.sh > /tmp/momentry_worker.log 2>&1 &", core_root); let output = std::process::Command::new("sh") .arg("-c") - .arg("cd /Users/accusys/momentry_core && nohup bash run-worker-3002.sh > /tmp/momentry_worker.log 2>&1 &") + .arg(&cmd) .output() .map_err(|e| format!("Failed to start worker: {}", e))?; if !output.status.success() { @@ -1370,9 +1391,11 @@ async fn start_service(name: String) -> Result { return Err(format!("Worker start failed: {}", stderr)); } tokio::time::sleep(std::time::Duration::from_secs(3)).await; + let pid_file = get_worker_pid_file(); + let check_cmd = format!("WPID=$(cat {} 2>/dev/null); [ -n \"$WPID\" ] && kill -0 $WPID 2>/dev/null && echo alive", pid_file); let check = std::process::Command::new("sh") .arg("-c") - .arg("WPID=$(cat /Users/accusys/momentry_core/logs/worker_3002.pid 2>/dev/null); [ -n \"$WPID\" ] && kill -0 $WPID 2>/dev/null && echo alive") + .arg(&check_cmd) .output() .map_err(|e| format!("Worker check failed: {}", e))?; if String::from_utf8_lossy(&check.stdout).contains("alive") { @@ -1382,22 +1405,29 @@ async fn start_service(name: String) -> Result { } let cmd = match name.as_str() { "MarkBase" | "markbase" => { - "mkdir -p /Users/accusys/markbase/data && cd /Users/accusys/markbase && nohup ./target/release/markbase-core web-start --port 11438 > /tmp/markbase_web.log 2>&1 &" + let markbase_root = get_markbase_root(); + format!("mkdir -p {}/data && cd {} && nohup ./target/release/markbase-core web-start --port 11438 > /tmp/markbase_web.log 2>&1 &", markbase_root, markbase_root) } "Core API" | "core" => { - "cd /Users/accusys/momentry_core && nohup bash run-server-3002.sh > /tmp/momentry_start.log 2>&1 &" + let core_root = get_momentry_core_root(); + format!("cd {} && nohup bash run-server-3002.sh > /tmp/momentry_start.log 2>&1 &", core_root) } "Proxy" | "proxy" => { - "cd /Users/accusys/momentry_studio/src-tauri && nohup ./target/debug/momentry-proxy > /tmp/momentry_proxy.log 2>&1 &" + let studio_root = get_studio_root(); + format!("cd {}/src-tauri && nohup ./target/debug/momentry-proxy > /tmp/momentry_proxy.log 2>&1 &", studio_root) } "MarkBaseEngine" | "mbe" => { - "cd /Users/accusys/MarkBaseEngine && nohup .build/debug/MarkBaseServer > /tmp/markbase_engine.log 2>&1 &" + let engine_root = get_markbase_engine_root(); + format!("cd {} && nohup .build/debug/MarkBaseServer > /tmp/markbase_engine.log 2>&1 &", engine_root) } "SFTP" => { - "cd /Users/accusys/markbase && nohup cargo run --bin markbase-core -- ssh-start --port 2024 > /tmp/markbase_ssh.log 2>&1 &" + let markbase_root = get_markbase_root(); + format!("cd {} && nohup cargo run --bin markbase-core -- ssh-start --port 2024 > /tmp/markbase_ssh.log 2>&1 &", markbase_root) } "SMB" => { - "cd /Users/accusys/markbase && nohup cargo run --bin markbase-core --features smb-server -- smb-start --port 4445 --share-name markbase --root /Users/accusys/momentry/var/sftpgo/data --user demo:demo123 > /tmp/markbase_smb.log 2>&1 &" + let markbase_root = get_markbase_root(); + let storage_root = get_storage_root(); + format!("cd {} && nohup cargo run --bin markbase-core --features smb-server -- smb-start --port 4445 --share-name markbase --root {} --user demo:demo123 > /tmp/markbase_smb.log 2>&1 &", markbase_root, storage_root) } _ => return Err(format!("Unknown service: {}", name)), }; @@ -1476,7 +1506,7 @@ async fn get_current_user(username: String) -> Result, String> #[tauri::command(rename_all = "camelCase")] async fn list_client_files(path: String) -> Result { - let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("/Users/accusys")); + let home = get_home_dir(); let root = home.join("momentry/var/sftpgo/data/demo"); let full_path = if path.is_empty() || path == "/" { root.clone() } else { root.join(&path) }; @@ -1501,7 +1531,7 @@ async fn list_client_files(path: String) -> Result { #[tauri::command(rename_all = "camelCase")] async fn mkdir_client(path: String) -> Result<(), String> { - let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("/Users/accusys")); + let home = get_home_dir(); let root = home.join("momentry/var/sftpgo/data/demo"); let full_path = root.join(&path); @@ -1513,7 +1543,7 @@ async fn mkdir_client(path: String) -> Result<(), String> { #[tauri::command(rename_all = "camelCase")] async fn rm_client(path: String) -> Result<(), String> { - let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("/Users/accusys")); + let home = get_home_dir(); let root = home.join("momentry/var/sftpgo/data/demo"); let full_path = root.join(&path); @@ -1542,13 +1572,11 @@ fn main() { if let Ok(output) = check { if output.stdout.is_empty() { - let cmd = "mkdir -p /Users/accusys/markbase/data && \ - cd /Users/accusys/markbase && \ - nohup ./target/release/markbase-core web-start --port 11438 \ - > /tmp/markbase_web.log 2>&1 &"; + let markbase_root = get_markbase_root(); + let cmd = format!("mkdir -p {}/data && cd {} && nohup ./target/release/markbase-core web-start --port 11438 > /tmp/markbase_web.log 2>&1 &", markbase_root, markbase_root); let _ = std::process::Command::new("sh") .arg("-c") - .arg(cmd) + .arg(&cmd) .spawn(); eprintln!("[startup] MarkBase started on port 11438"); } else { diff --git a/src-tauri/src/paths.rs b/src-tauri/src/paths.rs new file mode 100644 index 0000000..221ecb8 --- /dev/null +++ b/src-tauri/src/paths.rs @@ -0,0 +1,101 @@ +// Helper functions to get directory paths dynamically +// Priority: Environment Variable > User Home Directory + Standard Path + +use std::env; +use std::path::PathBuf; + +/// Get user home directory +pub fn get_home_dir() -> PathBuf { + dirs::home_dir() + .unwrap_or_else(|| PathBuf::from(".")) +} + +/// Get Momentry Core root directory +/// Priority: MOMENTRY_CORE_ROOT env var > ~/momentry_core +pub fn get_momentry_core_root() -> String { + env::var("MOMENTRY_CORE_ROOT") + .unwrap_or_else(|_| { + format!("{}/momentry_core", get_home_dir().display()) + }) +} + +/// Get MarkBase root directory +/// Priority: MARKBASE_ROOT env var > ~/markbase +pub fn get_markbase_root() -> String { + env::var("MARKBASE_ROOT") + .unwrap_or_else(|_| { + format!("{}/markbase", get_home_dir().display()) + }) +} + +/// Get Studio root directory +/// Priority: MOMENTRY_STUDIO_ROOT env var > ~/momentry_studio +pub fn get_studio_root() -> String { + env::var("MOMENTRY_STUDIO_ROOT") + .unwrap_or_else(|_| { + format!("{}/momentry_studio", get_home_dir().display()) + }) +} + +/// Get Momentry root directory +/// Priority: MOMENTRY_ROOT env var > ~/momentry +pub fn get_momentry_root() -> String { + env::var("MOMENTRY_ROOT") + .unwrap_or_else(|_| { + format!("{}/momentry", get_home_dir().display()) + }) +} + +/// Get storage root directory +/// Priority: STORAGE_ROOT env var > ~/momentry/var/sftpgo/data +pub fn get_storage_root() -> String { + env::var("STORAGE_ROOT") + .unwrap_or_else(|_| { + format!("{}/momentry/var/sftpgo/data", get_home_dir().display()) + }) +} + +/// Get MarkBaseEngine root directory +/// Priority: MARKBASE_ENGINE_ROOT env var > ~/MarkBaseEngine +pub fn get_markbase_engine_root() -> String { + env::var("MARKBASE_ENGINE_ROOT") + .unwrap_or_else(|_| { + format!("{}/MarkBaseEngine", get_home_dir().display()) + }) +} + +/// Get worker PID file path +pub fn get_worker_pid_file() -> String { + format!("{}/logs/worker_3002.pid", get_momentry_core_root()) +} + +/// Get worker log file path +pub fn get_worker_log_file() -> String { + format!("{}/logs/worker_3002.log", get_momentry_core_root()) +} + +#[cfg(test)] +mod path_tests { + use super::*; + + #[test] + fn test_get_home_dir() { + let home = get_home_dir(); + assert!(home.exists() || home.to_str() == Some(".")); + } + + #[test] + fn test_get_momentry_core_root_without_env() { + env::remove_var("MOMENTRY_CORE_ROOT"); + let root = get_momentry_core_root(); + assert!(root.contains("momentry_core")); + } + + #[test] + fn test_get_momentry_core_root_with_env() { + env::set_var("MOMENTRY_CORE_ROOT", "/custom/path/core"); + let root = get_momentry_core_root(); + assert_eq!(root, "/custom/path/core"); + env::remove_var("MOMENTRY_CORE_ROOT"); + } +} \ No newline at end of file