From 906fb126f47e7900e9c2a13016236cc039f080c7 Mon Sep 17 00:00:00 2001 From: imengying Date: Tue, 8 Sep 2026 16:56:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B8=85=E7=90=86=E6=97=A7=E7=89=88=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E8=84=9A=E6=9C=AC=E6=AE=8B=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 13 +++----- backend/config.example.toml | 1 - backend/src/config.rs | 16 +++------- backend/src/main.rs | 1 - backend/src/routes/site.rs | 3 -- frontend/src/install.test.ts | 59 +++++++++++++++++++++++++++++++++-- install.ps1 | 3 -- install.sh | 13 ++------ 8 files changed, 69 insertions(+), 40 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 67f2b5a..3cb9723 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -179,8 +179,7 @@ jobs: 'turnstile_secret_key = ""' \ "frontend_dir = \"$GITHUB_WORKSPACE/frontend/dist\"" \ "admin_frontend_dir = \"$GITHUB_WORKSPACE/frontend/admin-dist\"" \ - "theme_dir = \"$sqlite_dir/themes\"" \ - "agent_dir = \"$GITHUB_WORKSPACE/agent\"" > "$sqlite_config" + "theme_dir = \"$sqlite_dir/themes\"" > "$sqlite_config" target/backend/debug/nodeflare --config "$sqlite_config" > "$sqlite_dir/server.log" 2>&1 & sqlite_pid=$! wait_ready http://127.0.0.1:18080 "$sqlite_dir/server.log" "$sqlite_pid" @@ -208,8 +207,7 @@ jobs: 'turnstile_secret_key = ""' \ "frontend_dir = \"$GITHUB_WORKSPACE/frontend/dist\"" \ "admin_frontend_dir = \"$GITHUB_WORKSPACE/frontend/admin-dist\"" \ - "theme_dir = \"$postgres_dir/themes\"" \ - "agent_dir = \"$GITHUB_WORKSPACE/agent\"" > "$postgres_config" + "theme_dir = \"$postgres_dir/themes\"" > "$postgres_config" target/backend/debug/nodeflare --config "$postgres_config" > "$postgres_dir/server.log" 2>&1 & postgres_pid=$! wait_ready http://127.0.0.1:18081 "$postgres_dir/server.log" "$postgres_pid" @@ -757,16 +755,15 @@ jobs: FORMAT: ${{ matrix.format }} run: | set -euo pipefail - mkdir -p package/share/frontend package/share/admin package/share/agent release inputs/frontend/unpacked + mkdir -p package/share/frontend package/share/admin release inputs/frontend/unpacked cp "inputs/server/$BINARY" "package/$PACKAGE_BINARY" tar -xzf "inputs/frontend/nodeflare-frontend-$VERSION.tar.gz" -C inputs/frontend/unpacked cp -a inputs/frontend/unpacked/dist/. package/share/frontend/ cp -a inputs/frontend/unpacked/admin-dist/. package/share/admin/ - cp agent/agent.sh agent/install-macos.sh agent/install-freebsd.sh agent/install.ps1 package/share/agent/ cp deploy/nodeflare.service package/nodeflare.service cp LICENSE package/LICENSE - chmod 0755 "package/$PACKAGE_BINARY" package/share/agent/*.sh - chmod 0644 package/LICENSE package/nodeflare.service package/share/agent/install.ps1 + chmod 0755 "package/$PACKAGE_BINARY" + chmod 0644 package/LICENSE package/nodeflare.service if [ "$FORMAT" = zip ]; then (cd package && zip -qr "../release/$ASSET" .) unzip -tq "release/$ASSET" diff --git a/backend/config.example.toml b/backend/config.example.toml index e7d1fa2..e809a2c 100644 --- a/backend/config.example.toml +++ b/backend/config.example.toml @@ -28,7 +28,6 @@ turnstile_secret_key = "" # 路径相对于本配置文件所在目录 frontend_dir = "../frontend/dist" admin_frontend_dir = "../frontend/admin-dist" -agent_dir = "../agent" # 下载或上传的主题 ZIP 解压目录 theme_dir = "themes" diff --git a/backend/src/config.rs b/backend/src/config.rs index 59a425e..e18793b 100644 --- a/backend/src/config.rs +++ b/backend/src/config.rs @@ -43,8 +43,6 @@ pub struct Config { pub frontend_dir: PathBuf, #[serde(default = "default_admin_frontend_dir")] pub admin_frontend_dir: PathBuf, - #[serde(default = "default_agent_dir")] - pub agent_dir: PathBuf, #[serde(default = "default_theme_dir")] pub theme_dir: PathBuf, #[serde(default = "default_session_hours")] @@ -103,10 +101,6 @@ fn default_admin_frontend_dir() -> PathBuf { default_share_dir().join("admin") } -fn default_agent_dir() -> PathBuf { - default_share_dir().join("agent") -} - fn default_theme_dir() -> PathBuf { default_data_dir().join("themes") } @@ -136,7 +130,6 @@ impl Config { .unwrap_or_else(|| Path::new(".")); config.frontend_dir = resolve_path(base, &config.frontend_dir); config.admin_frontend_dir = resolve_path(base, &config.admin_frontend_dir); - config.agent_dir = resolve_path(base, &config.agent_dir); config.theme_dir = resolve_path(base, &config.theme_dir); config.database_url = resolve_database_url(base, &config.database_url)?; config.session_ttl_hours = config.session_ttl_hours.clamp(1, 24 * 90); @@ -266,10 +259,10 @@ pub fn resolve_database_url(base: &Path, value: &str) -> Result { #[cfg(test)] mod tests { use super::{ - Args, clear_bootstrap_password, default_admin_frontend_dir, default_agent_dir, - default_bind_addr, default_config_path, default_data_dir, default_database_url, - default_public_frontend_dir, default_share_dir, default_theme_dir, is_example_password, - resolve_database_url, update_database_url, + Args, clear_bootstrap_password, default_admin_frontend_dir, default_bind_addr, + default_config_path, default_data_dir, default_database_url, default_public_frontend_dir, + default_share_dir, default_theme_dir, is_example_password, resolve_database_url, + update_database_url, }; use clap::Parser; use std::path::Path; @@ -288,7 +281,6 @@ mod tests { default_admin_frontend_dir(), default_share_dir().join("admin") ); - assert_eq!(default_agent_dir(), default_share_dir().join("agent")); assert_eq!(default_theme_dir(), default_data_dir().join("themes")); } diff --git a/backend/src/main.rs b/backend/src/main.rs index 669572b..15db857 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -190,7 +190,6 @@ async fn main() -> Result<()> { for (label, path) in [ ("public frontend", &config.frontend_dir), ("admin frontend", &config.admin_frontend_dir), - ("Agent installers", &config.agent_dir), ] { if !path.exists() { tracing::warn!(label, path = %path.display(), "asset directory does not exist"); diff --git a/backend/src/routes/site.rs b/backend/src/routes/site.rs index 9e30aa0..22417e3 100644 --- a/backend/src/routes/site.rs +++ b/backend/src/routes/site.rs @@ -18,9 +18,6 @@ pub async fn handle(State(state): State>, OriginalUri(uri): Origin if let Some(relative) = path.strip_prefix("/admin-assets/") { return local_file(&state.config.admin_frontend_dir, relative, false).await; } - if let Some(relative) = path.strip_prefix("/agent/") { - return local_file(&state.config.agent_dir, relative, false).await; - } if let Some(preview) = path.strip_prefix("/__theme-preview/") { let (token, relative) = preview.split_once('/').unwrap_or((preview, "")); let base = match crate::db::queries::theme_preview_url(&state.db, token).await { diff --git a/frontend/src/install.test.ts b/frontend/src/install.test.ts index fca351c..0388b51 100644 --- a/frontend/src/install.test.ts +++ b/frontend/src/install.test.ts @@ -125,7 +125,6 @@ describe("installer port selection", () => { admin_password='TestPassword123' public_frontend_dir=$config_dir/frontend admin_frontend_dir=$config_dir/admin - agent_installer_dir=$config_dir/agent theme_dir=$config_dir/themes prompt_port write_config @@ -162,7 +161,6 @@ describe("server installer update output", () => { share_dir=$install_dir/share public_frontend_dir=$share_dir/frontend admin_frontend_dir=$share_dir/admin - agent_installer_dir=$share_dir/agent server_binary=$install_dir/nodeflare init_system=systemd download_release() { release_version=1.2.3; package_dir=$TEST_DIRECTORY/package; } @@ -201,6 +199,63 @@ describe("server installer update output", () => { } }); +describe("server bundle installation", () => { + for (const separateShare of [false, true]) { + test(`replaces bundled resources without changing agent data (separate share=${separateShare})`, () => { + const directory = mkdtempSync(join(tmpdir(), "nodeflare-bundle-install-")); + const installDir = join(directory, "install"); + const shareDir = join(separateShare ? directory : installDir, "share"); + const configDir = join(directory, "config"); + const packageDir = join(directory, "package"); + try { + for (const path of [installDir, shareDir, join(configDir, "agent"), join(configDir, "themes"), join(packageDir, "share", "frontend"), join(packageDir, "share", "admin")]) { + mkdirSync(path, { recursive: true }); + } + writeFileSync(join(installDir, "agent"), "agent-binary"); + writeFileSync(join(shareDir, "obsolete-resource"), "obsolete"); + writeFileSync(join(configDir, "config.toml"), 'bind_addr = "127.0.0.1:3100"\n'); + writeFileSync(join(configDir, "agent", "remote-tasks.json"), "agent-state"); + writeFileSync(join(configDir, "themes", "theme.txt"), "custom-theme"); + writeFileSync(join(packageDir, "nodeflare"), "server-binary"); + writeFileSync(join(packageDir, "share", "frontend", "index.html"), "public"); + writeFileSync(join(packageDir, "share", "admin", "admin.html"), "admin"); + const start = installer.lastIndexOf("\ndownload_release\n"); + if (start < 0) throw new Error("Missing installer entry point"); + const result = spawnSync("sh", ["-c", ` + set -eu + ${shellFunctions("log", "fail", "print_install_result")} + config_dir=$TEST_DIRECTORY/config + config_file=$config_dir/config.toml + theme_dir=$config_dir/themes + install_dir=$TEST_DIRECTORY/install + share_dir=$TEST_SHARE_DIR + public_frontend_dir=$share_dir/frontend + admin_frontend_dir=$share_dir/admin + server_binary=$install_dir/nodeflare + download_release() { release_version=1.2.3; package_dir=$TEST_DIRECTORY/package; } + snapshot_install() { :; } + stop_server() { :; } + install_service() { :; } + chown() { :; } + start_server() { return 0; } + ${installer.slice(start)} + `], { env: { ...process.env, TEST_DIRECTORY: directory, TEST_SHARE_DIR: shareDir }, encoding: "utf8" }); + expect(result.status).toBe(0); + expect(existsSync(join(shareDir, "obsolete-resource"))).toBe(false); + expect(readFileSync(join(shareDir, "frontend", "index.html"), "utf8")).toBe("public"); + expect(readFileSync(join(shareDir, "admin", "admin.html"), "utf8")).toBe("admin"); + expect(readFileSync(join(installDir, "nodeflare"), "utf8")).toBe("server-binary"); + expect(readFileSync(join(installDir, "agent"), "utf8")).toBe("agent-binary"); + expect(readFileSync(join(configDir, "config.toml"), "utf8")).toBe('bind_addr = "127.0.0.1:3100"\n'); + expect(readFileSync(join(configDir, "agent", "remote-tasks.json"), "utf8")).toBe("agent-state"); + expect(readFileSync(join(configDir, "themes", "theme.txt"), "utf8")).toBe("custom-theme"); + } finally { + rmSync(directory, { recursive: true, force: true }); + } + }); + } +}); + describe("installer menu", () => { function route(input: string, args: string[] = []) { const dispatch = installer.slice(installer.indexOf("\nmode=menu"), installer.indexOf("\nfor required_command")); diff --git a/install.ps1 b/install.ps1 index b77c1a2..3e52438 100644 --- a/install.ps1 +++ b/install.ps1 @@ -126,7 +126,6 @@ function Wait-Server { function Write-Config([string]$Username, [string]$Password, [string]$DatabaseUrl, [int]$Port) { $FrontendDir = (Join-Path $ShareDir "frontend").Replace('\', '/') $AdminDir = (Join-Path $ShareDir "admin").Replace('\', '/') - $AgentDir = (Join-Path $ShareDir "agent").Replace('\', '/') $ThemePath = $ThemeDir.Replace('\', '/') $Lines = @( "database_url = `"$(Escape-Toml $DatabaseUrl)`"" @@ -138,7 +137,6 @@ function Write-Config([string]$Username, [string]$Password, [string]$DatabaseUrl 'turnstile_secret_key = ""' "frontend_dir = `"$FrontendDir`"" "admin_frontend_dir = `"$AdminDir`"" - "agent_dir = `"$AgentDir`"" "theme_dir = `"$ThemePath`"" 'session_ttl_hours = 168' ) @@ -233,7 +231,6 @@ try { $PackageServer, (Join-Path $PackageDir "share\frontend\index.html"), (Join-Path $PackageDir "share\admin\admin.html"), - (Join-Path $PackageDir "share\agent\agent.sh"), (Join-Path $PackageDir "LICENSE") )) { if (-not (Test-Path -LiteralPath $Required -PathType Leaf)) { diff --git a/install.sh b/install.sh index d36d923..e36d695 100755 --- a/install.sh +++ b/install.sh @@ -52,7 +52,6 @@ server_binary=$install_dir/nodeflare theme_dir=$config_dir/themes public_frontend_dir=$share_dir/frontend admin_frontend_dir=$share_dir/admin -agent_installer_dir=$share_dir/agent usage() { printf '%s\n' \ @@ -297,7 +296,6 @@ write_config() { escaped_password=$(toml_escape "$admin_password") escaped_frontend_dir=$(toml_escape "$public_frontend_dir") escaped_admin_dir=$(toml_escape "$admin_frontend_dir") - escaped_agent_dir=$(toml_escape "$agent_installer_dir") escaped_theme_dir=$(toml_escape "$theme_dir") config_temp=$(mktemp "$config_dir/.config.toml.XXXXXX") { @@ -310,7 +308,6 @@ write_config() { printf 'turnstile_secret_key = ""\n' printf 'frontend_dir = "%s"\n' "$escaped_frontend_dir" printf 'admin_frontend_dir = "%s"\n' "$escaped_admin_dir" - printf 'agent_dir = "%s"\n' "$escaped_agent_dir" printf 'theme_dir = "%s"\n' "$escaped_theme_dir" printf 'session_ttl_hours = 168\n' } > "$config_temp" @@ -426,7 +423,6 @@ download_release() { [ -f "$package_dir/nodeflare" ] \ && [ -f "$package_dir/share/frontend/index.html" ] \ && [ -f "$package_dir/share/admin/admin.html" ] \ - && [ -f "$package_dir/share/agent/agent.sh" ] \ && [ -f "$package_dir/LICENSE" ] \ || fail "Release 文件不完整" chmod 0755 "$package_dir/nodeflare" @@ -730,14 +726,11 @@ fi snapshot_install stop_server install -d -m 0700 "$config_dir" "$theme_dir" -install -d -m 0755 "$install_dir" "$share_dir" -rm -rf "$public_frontend_dir" "$admin_frontend_dir" "$agent_installer_dir" -install -d -m 0755 "$public_frontend_dir" "$admin_frontend_dir" "$agent_installer_dir" +install -d -m 0755 "$install_dir" +rm -rf "$share_dir" +install -d -m 0755 "$public_frontend_dir" "$admin_frontend_dir" cp -R "$package_dir/share/frontend/." "$public_frontend_dir/" cp -R "$package_dir/share/admin/." "$admin_frontend_dir/" -cp -R "$package_dir/share/agent/." "$agent_installer_dir/" -chmod 0755 "$agent_installer_dir/"*.sh -chmod 0644 "$agent_installer_dir/install.ps1" install -m 0755 "$package_dir/nodeflare" "$server_binary" install_service