mirror of
https://github.com/Corfirean/coa-server-manager.git
synced 2026-11-12 20:11:02 +00:00
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
4eda03ab63
commit
db16d95558
7 files changed
+49
-6
No files matched your search
Generated
+3
-3
@@ -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",
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
|
||||
@@ -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<bool> {
|
||||
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();
|
||||
|
||||
+1
-1
@@ -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": {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -55,6 +55,7 @@ export function FriendsPage({ serverId }: { serverId: string }) {
|
||||
const [error, setError] = useState<UiError | null>(null);
|
||||
const [note, setNote] = useState<string | null>(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 && <p className="mt-4 text-sm text-ok" role="status">{note}</p>}
|
||||
{needsRestart && st.server_running && (
|
||||
<Button
|
||||
className="mt-3"
|
||||
size="sm"
|
||||
variant="primary"
|
||||
disabled={!!busy}
|
||||
onClick={() =>
|
||||
void run("restart", async () => {
|
||||
await api.stop(serverId);
|
||||
await api.start(serverId);
|
||||
setNeedsRestart(false);
|
||||
})
|
||||
}
|
||||
>
|
||||
{busy === "restart" && <Loader2 className="h-4 w-4 animate-spin" aria-hidden />}
|
||||
{t("set.restartNow")}
|
||||
</Button>
|
||||
)}
|
||||
{error && <p className="mt-4 text-sm text-bad" role="alert">{error.human.code === "unknown" ? error.technical : human(error.human).message}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user