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)); + } +}