feat: 动态路径系统 - 支持任意用户环境部署
问题: - 100+ 处硬编码路径 /Users/accusys - 无法在不同用户环境部署 - 配置文件路径固定 解决方案: 1. ✅ 创建 paths.rs 模块 - get_home_dir() - 获取用户主目录 - get_momentry_core_root() - Core API 根目录 - get_markbase_root() - MarkBase 根目录 - get_studio_root() - Studio 根目录 - get_storage_root() - 存储根目录 - 环境变量优先 > 用户主目录推断 2. ✅ 修改 main.rs - 移除所有硬编码路径 - 使用动态路径函数 - 支持环境变量配置 3. ✅ 创建配置模板 - admin_config.json.template - .env.template - 使用 {{HOME}} 占位符 4. ✅ 创建自动化脚本 - install.sh - 通用安装脚本 - generate_config.sh - 配置生成脚本 - 自动检测用户环境 特性: - ✅ 支持任意用户环境 - ✅ 自动检测用户主目录 - ✅ 环境变量优先级控制 - ✅ 一键安装部署 测试: - ✅ 编译通过 (cargo check) - ⚠️ 需要在新环境测试 使用方法: 1. 克隆项目 2. ./install.sh 3. 编辑 .env 4. npm run proxy 适用环境: - m5max48: /Users/accusys - m4promini: /Users/nextorageai - 任意 macOS 环境
This commit is contained in:
@@ -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<String>, target_uuid: Option<String>,
|
||||
async fn stop_service(name: String) -> Result<String, String> {
|
||||
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<String, String> {
|
||||
async fn start_service(name: String) -> Result<String, String> {
|
||||
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<String, String> {
|
||||
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<String, String> {
|
||||
}
|
||||
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<Option<db::User>, String>
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn list_client_files(path: String) -> Result<serde_json::Value, 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 = if path.is_empty() || path == "/" { root.clone() } else { root.join(&path) };
|
||||
|
||||
@@ -1501,7 +1531,7 @@ async fn list_client_files(path: String) -> Result<serde_json::Value, String> {
|
||||
|
||||
#[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 {
|
||||
|
||||
101
src-tauri/src/paths.rs
Normal file
101
src-tauri/src/paths.rs
Normal file
@@ -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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user