feat(battle-node): EngineIoFrame parse/encode for EIO3 packets

This commit is contained in:
gamer147
2026-05-31 21:34:11 -04:00
parent a786599416
commit 6c6664f011
4 changed files with 106 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
namespace SVSim.BattleNode.Wire;
/// <summary>
/// Engine.IO v3 packet in WebSocket transport mode. Wire form: <c>&lt;digit&gt;&lt;payload&gt;</c>.
/// </summary>
public sealed record EngineIoFrame(EngineIoPacketType Type, string Payload)
{
public static EngineIoFrame Parse(string raw)
{
if (string.IsNullOrEmpty(raw))
throw new ArgumentException("Empty EIO frame", nameof(raw));
var typeChar = raw[0];
if (typeChar < '0' || typeChar > '6')
throw new ArgumentException($"Invalid EIO type char '{typeChar}'", nameof(raw));
var type = (EngineIoPacketType)(typeChar - '0');
var payload = raw.Length > 1 ? raw.Substring(1) : string.Empty;
return new EngineIoFrame(type, payload);
}
public string Encode() => $"{(int)Type}{Payload}";
}

View File

@@ -0,0 +1,22 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SVSim.BattleNode.Wire;
/// <summary>
/// Payload of an EIO3 Open packet. Sent by the server to the client immediately after the WS upgrade.
/// </summary>
public sealed record EngineIoHandshake(
[property: JsonPropertyName("sid")] string Sid,
[property: JsonPropertyName("upgrades")] string[] Upgrades,
[property: JsonPropertyName("pingInterval")] int PingInterval,
[property: JsonPropertyName("pingTimeout")] int PingTimeout)
{
// Wire-key casing here is bare camelCase — NOT EmulatedEntrypoint's snake_case policy.
private static readonly JsonSerializerOptions Options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};
public string ToJson() => JsonSerializer.Serialize(this, Options);
}

View File

@@ -0,0 +1,12 @@
namespace SVSim.BattleNode.Wire;
public enum EngineIoPacketType
{
Open = 0,
Close = 1,
Ping = 2,
Pong = 3,
Message = 4,
Upgrade = 5,
Noop = 6,
}