From c0c2bb5772c5f7b1ecad3304f75e61f8d3f800a1 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Sun, 31 May 2026 21:58:06 -0400 Subject: [PATCH] =?UTF-8?q?feat(battle-node):=20MsgPayloadCodec=20encodes/?= =?UTF-8?q?decodes=20msgpack=E2=86=94envelope=20chain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SVSim.BattleNode/Protocol/MsgPayloadCodec.cs | 26 +++++++++ .../Protocol/MsgPayloadCodecTests.cs | 53 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 SVSim.BattleNode/Protocol/MsgPayloadCodec.cs create mode 100644 SVSim.UnitTests/BattleNode/Protocol/MsgPayloadCodecTests.cs diff --git a/SVSim.BattleNode/Protocol/MsgPayloadCodec.cs b/SVSim.BattleNode/Protocol/MsgPayloadCodec.cs new file mode 100644 index 0000000..5e5095c --- /dev/null +++ b/SVSim.BattleNode/Protocol/MsgPayloadCodec.cs @@ -0,0 +1,26 @@ +using MessagePack; +using SVSim.BattleNode.Wire; + +namespace SVSim.BattleNode.Protocol; + +/// +/// Full chain between an envelope and the bytes that ride as a SocketIO binary attachment. +/// Inbound: bytes → msgpack-string → NodeCrypto.Decrypt → JSON → MsgEnvelope +/// Outbound: MsgEnvelope → JSON → NodeCrypto.Encrypt → msgpack-bytes +/// +public static class MsgPayloadCodec +{ + public static MsgEnvelope Decode(byte[] msgpackBytes) + { + var encryptedString = MessagePackSerializer.Deserialize(msgpackBytes); + var json = NodeCrypto.DecryptForNode(encryptedString); + return MsgEnvelope.FromJson(json); + } + + public static byte[] Encode(MsgEnvelope envelope, string key) + { + var json = MsgEnvelope.ToJson(envelope); + var encryptedString = NodeCrypto.EncryptForNode(json, key); + return MessagePackSerializer.Serialize(encryptedString); + } +} diff --git a/SVSim.UnitTests/BattleNode/Protocol/MsgPayloadCodecTests.cs b/SVSim.UnitTests/BattleNode/Protocol/MsgPayloadCodecTests.cs new file mode 100644 index 0000000..afbfb75 --- /dev/null +++ b/SVSim.UnitTests/BattleNode/Protocol/MsgPayloadCodecTests.cs @@ -0,0 +1,53 @@ +using NUnit.Framework; +using SVSim.BattleNode.Protocol; + +namespace SVSim.UnitTests.BattleNode.Protocol; + +[TestFixture] +public class MsgPayloadCodecTests +{ + private static string FreshKey() + { + var seq = 0; + return SVSim.BattleNode.Wire.NodeCrypto.GenerateKey(() => (seq++ * 7) % 16); + } + + [Test] + public void Roundtrip_PreservesEnvelope() + { + var env = new MsgEnvelope( + Uri: NetworkBattleUri.Loaded, + ViewerId: 906243102, + Uuid: "udid", + Bid: "1234", + Try: 0, + Cat: EmitCategory.Battle, + PubSeq: 3, + PlaySeq: null, + Body: new Dictionary()); + + var bytes = MsgPayloadCodec.Encode(env, key: FreshKey()); + var back = MsgPayloadCodec.Decode(bytes); + + Assert.That(back.Uri, Is.EqualTo(NetworkBattleUri.Loaded)); + Assert.That(back.PubSeq, Is.EqualTo(3)); + Assert.That(back.Bid, Is.EqualTo("1234")); + } + + [Test] + public void Decode_KnownEnvelope_ReturnsExpectedUriAndBody() + { + // The captures only contain decoded JSON, so we build the encrypted-msgpack representation + // ourselves with the same JSON and a known key — this confirms the full chain end-to-end. + var key = FreshKey(); + var originalJson = "{\"uri\":\"InitNetwork\",\"viewerId\":1,\"uuid\":\"u\",\"try\":0,\"cat\":99,\"resultCode\":1}"; + var encrypted = SVSim.BattleNode.Wire.NodeCrypto.EncryptForNode(originalJson, key); + var bytes = MessagePack.MessagePackSerializer.Serialize(encrypted); + + var env = MsgPayloadCodec.Decode(bytes); + + Assert.That(env.Uri, Is.EqualTo(NetworkBattleUri.InitNetwork)); + Assert.That(env.Cat, Is.EqualTo(EmitCategory.General)); + Assert.That(env.Body["resultCode"], Is.EqualTo(1L)); + } +}