From db16d95558910d4cdc97edbce97ec78aaf535a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 30 Sep 2026 19:51:07 +0500 Subject: [PATCH] v0.1.4: keep BindIP open for shared servers before every start, restart button after enabling friends mode Co-Authored-By: Claude Sonnet 5.5 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- crates/coa-core/src/friends.rs | 21 +++++++++++++++++++++ package.json | 2 +- src-tauri/src/lib.rs | 2 ++ src-tauri/tauri.conf.json | 2 +- src/screens/FriendsPage.tsx | 20 ++++++++++++++++++++ 7 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96e64f4..3eaa521 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -347,7 +347,7 @@ dependencies = [ [[package]] name = "coa-core" -version = "0.1.3" +version = "0.1.4" dependencies = [ "base64 0.22.1", "chrono", @@ -375,7 +375,7 @@ dependencies = [ [[package]] name = "coa-release" -version = "0.1.3" +version = "0.1.4" dependencies = [ "chrono", "coa-core", @@ -384,7 +384,7 @@ dependencies = [ [[package]] name = "coa-server-manager" -version = "0.1.3" +version = "0.1.4" dependencies = [ "coa-core", "serde", diff --git a/Cargo.toml b/Cargo.toml index 864976f..f917913 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = ["crates/coa-core", "crates/coa-release", "src-tauri"] [workspace.package] -version = "0.1.3" +version = "0.1.4" edition = "2021" license = "AGPL-3.0-only" diff --git a/crates/coa-core/src/friends.rs b/crates/coa-core/src/friends.rs index e87fda7..14d785f 100644 --- a/crates/coa-core/src/friends.rs +++ b/crates/coa-core/src/friends.rs @@ -109,6 +109,17 @@ pub fn apply_realm_address(root: &Path, host: &str) -> Result<()> { Ok(()) } +/// Before every server start: when the owner shares the server with friends, make sure the login and world servers +/// listen on all addresses. The launcher's own tools (for example switching detailed logging off) restore the config +/// templates from older copies and would silently put `BindIP` back to 127.0.0.1 while the realm list still advertises +/// the shared address - the game then shows the realm and drops back to the login screen without any message. +pub fn ensure_bind(root: &Path, meta: &Path) -> Result { + match load(meta).mode { + Mode::Local => Ok(false), + _ => set_open(root, meta, true), + } +} + /// After every server start: put the chosen address back into the realm list (the launcher resets it to 127.0.0.1). pub fn reapply(root: &Path, meta: &Path) -> Result<()> { let s = load(meta); @@ -189,6 +200,16 @@ mod tests { assert!(fs::read_to_string(root.join("Core/configs/worldserver.conf")).unwrap().contains("BindIP = \"127.0.0.1\"")); } + #[test] + fn a_shared_server_gets_its_bind_address_back_before_start_and_a_local_one_is_left_alone() { + let (_d, root, meta) = setup(); + assert!(!ensure_bind(&root, &meta).unwrap(), "local mode: nothing to do"); + save(&meta, &Settings { mode: Mode::Private, host: Some("100.64.1.2".into()) }).unwrap(); + assert!(ensure_bind(&root, &meta).unwrap(), "templates were reset to 127.0.0.1 -> reopened"); + assert!(bind_is_open(&root)); + assert!(!ensure_bind(&root, &meta).unwrap(), "already open: idempotent"); + } + #[test] fn settings_round_trip_and_default_to_local() { let d = tempfile::tempdir().unwrap(); diff --git a/package.json b/package.json index 28a21ef..e085248 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coa-server-manager", "private": true, - "version": "0.1.3", + "version": "0.1.4", "license": "AGPL-3.0-only", "type": "module", "scripts": { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 2f455f8..22f12bb 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -195,6 +195,8 @@ async fn start_server(state: State<'_, AppState>, id: String) -> std::result::Re if meta.kind == coa_core::registry::InstallKind::New { coa_core::config::materialize_module_configs(&root)?; } + let dir = meta_dir(&root)?; + coa_core::friends::ensure_bind(&root, &dir)?; Ok::<(), Error>(()) }) .await; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 7a7fe33..367237b 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "CoA Server Manager", - "version": "0.1.3", + "version": "0.1.4", "identifier": "com.coa.servermanager", "build": { "beforeDevCommand": "npm run dev", diff --git a/src/screens/FriendsPage.tsx b/src/screens/FriendsPage.tsx index e723f20..0239645 100644 --- a/src/screens/FriendsPage.tsx +++ b/src/screens/FriendsPage.tsx @@ -55,6 +55,7 @@ export function FriendsPage({ serverId }: { serverId: string }) { const [error, setError] = useState(null); const [note, setNote] = useState(null); const [copied, setCopied] = useState(false); + const [needsRestart, setNeedsRestart] = useState(false); const refresh = useCallback(() => api.friendsStatus(serverId).then(setSt).catch((e) => setError(asUiError(e))), [serverId]); useEffect(() => { @@ -84,6 +85,7 @@ export function FriendsPage({ serverId }: { serverId: string }) { const enable = (mode: FriendsMode) => run(`enable-${mode}`, async () => { const r = await api.friendsEnable(serverId, mode, net?.public_ip ?? undefined, mode === "direct" && !!net?.router_found); + setNeedsRestart(r.restart_required); return [r.restart_required ? t("fr.restartToApply") : null, r.note].filter(Boolean).join(" ") || t("fr.ready"); }); @@ -199,6 +201,24 @@ export function FriendsPage({ serverId }: { serverId: string }) { )} {note &&

{note}

} + {needsRestart && st.server_running && ( + + )} {error &&

{error.human.code === "unknown" ? error.technical : human(error.human).message}

} );