From 5525dbee241ed006fb0ede2dee512fed9dacd27b Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 1 Jun 2026 01:06:40 -0400 Subject: [PATCH] fix(battle-node): node_server_url matches prod wire format (no scheme, with path) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prod do_matching captures (data_dumps/captures/traffic_prod_tk2_*) send the node URL as host:port/socket.io/ with no scheme prefix — e.g. "node06.shadowverse.jp:13560/socket.io/". BestHTTP's SocketManager expects this exact shape; the leading ws:// we were sending plus the missing /socket.io/ path was preventing the client from completing the post-do_matching connect (eventually times out with "connection timed out"). Update BattleNodeOptions default, Program.cs override, and both controller and bridge tests to use "localhost:5148/socket.io/". Discovered during v1 smoke walkthrough. Co-Authored-By: Claude Opus 4.7 --- SVSim.BattleNode/Bridge/BattleNodeOptions.cs | 7 ++++--- SVSim.EmulatedEntrypoint/Program.cs | 5 +++-- SVSim.UnitTests/BattleNode/Bridge/MatchingBridgeTests.cs | 4 ++-- .../Controllers/ArenaTwoPickBattleControllerTests.cs | 5 ++++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/SVSim.BattleNode/Bridge/BattleNodeOptions.cs b/SVSim.BattleNode/Bridge/BattleNodeOptions.cs index 7210e9f..0e28827 100644 --- a/SVSim.BattleNode/Bridge/BattleNodeOptions.cs +++ b/SVSim.BattleNode/Bridge/BattleNodeOptions.cs @@ -1,10 +1,11 @@ namespace SVSim.BattleNode.Bridge; /// -/// DI-injected options for the battle node. The web host populates these — typically -/// nodeServerUrl is "ws://localhost:5148" matching ASPNETCORE_URLS. +/// DI-injected options for the battle node. NodeServerUrl matches the prod +/// do_matching wire format: host:port/socket.io/, no scheme prefix. +/// BestHTTP's SocketManager parses it as the Socket.IO v2 endpoint URL. /// public sealed class BattleNodeOptions { - public string NodeServerUrl { get; set; } = "ws://localhost:5148"; + public string NodeServerUrl { get; set; } = "localhost:5148/socket.io/"; } diff --git a/SVSim.EmulatedEntrypoint/Program.cs b/SVSim.EmulatedEntrypoint/Program.cs index 0ef2d65..8c9596b 100644 --- a/SVSim.EmulatedEntrypoint/Program.cs +++ b/SVSim.EmulatedEntrypoint/Program.cs @@ -119,8 +119,9 @@ public class Program builder.Services.AddBattleNode(opt => { - // ASPNETCORE_URLS defaults to http://localhost:5148; we map ws:// onto the same host:port. - opt.NodeServerUrl = "ws://localhost:5148"; + // Matches the prod do_matching wire format: host:port/socket.io/, no scheme prefix. + // BestHTTP's SocketManager parses this as the Socket.IO v2 endpoint URL. + opt.NodeServerUrl = "localhost:5148/socket.io/"; }); builder.Services.AddTransient(); diff --git a/SVSim.UnitTests/BattleNode/Bridge/MatchingBridgeTests.cs b/SVSim.UnitTests/BattleNode/Bridge/MatchingBridgeTests.cs index c526ad1..b4c7473 100644 --- a/SVSim.UnitTests/BattleNode/Bridge/MatchingBridgeTests.cs +++ b/SVSim.UnitTests/BattleNode/Bridge/MatchingBridgeTests.cs @@ -11,11 +11,11 @@ public class MatchingBridgeTests public void RegisterPendingBattle_RegistersInStoreAndReturnsNodeUrl() { var store = new InMemoryBattleSessionStore(); - var bridge = new MatchingBridge(store, new BattleNodeOptions { NodeServerUrl = "ws://localhost:5148" }); + var bridge = new MatchingBridge(store, new BattleNodeOptions { NodeServerUrl = "localhost:5148/socket.io/" }); var match = bridge.RegisterPendingBattle(viewerId: 906243102); - Assert.That(match.NodeServerUrl, Is.EqualTo("ws://localhost:5148")); + Assert.That(match.NodeServerUrl, Is.EqualTo("localhost:5148/socket.io/")); Assert.That(match.BattleId, Is.Not.Empty); var pending = store.TryGetPending(match.BattleId); Assert.That(pending, Is.Not.Null); diff --git a/SVSim.UnitTests/Controllers/ArenaTwoPickBattleControllerTests.cs b/SVSim.UnitTests/Controllers/ArenaTwoPickBattleControllerTests.cs index a75d1f9..9aa6b4a 100644 --- a/SVSim.UnitTests/Controllers/ArenaTwoPickBattleControllerTests.cs +++ b/SVSim.UnitTests/Controllers/ArenaTwoPickBattleControllerTests.cs @@ -28,7 +28,10 @@ public class ArenaTwoPickBattleControllerTests var battleId = root.GetProperty("battle_id").GetString(); Assert.That(battleId, Is.Not.Null.And.Not.Empty); var nodeUrl = root.GetProperty("node_server_url").GetString(); - Assert.That(nodeUrl, Does.StartWith("ws://")); + // Matches prod wire format: host:port/socket.io/, no scheme prefix. + Assert.That(nodeUrl, Does.Contain("/socket.io/")); + Assert.That(nodeUrl, Does.Not.StartWith("ws://")); + Assert.That(nodeUrl, Does.Not.StartWith("http://")); // Required when matching_state ∈ {3004,3007,3011} per // DoMatchingBase.SettingCardMasterId; client throws KeyNotFoundException without it. Assert.That(root.GetProperty("card_master_id").GetInt32(), Is.EqualTo(1));