using System.Text.Json; using IronSnappy; namespace ZB.MOM.NatsNet.Server; /// /// String/JSON helpers for store enums that mirror Go enum methods. /// public static class StoreEnumExtensions { public static string String(this StoreCipher cipher) => cipher switch { StoreCipher.ChaCha => "ChaCha20-Poly1305", StoreCipher.Aes => "AES-GCM", StoreCipher.NoCipher => "None", _ => "Unknown StoreCipher", }; public static string String(this StoreCompression alg) => alg switch { StoreCompression.NoCompression => "None", StoreCompression.S2Compression => "S2", _ => "Unknown StoreCompression", }; public static byte[] MarshalJSON(this StoreCompression alg) => alg switch { StoreCompression.NoCompression => JsonSerializer.SerializeToUtf8Bytes("none"), StoreCompression.S2Compression => JsonSerializer.SerializeToUtf8Bytes("s2"), _ => throw new InvalidOperationException("unknown compression algorithm"), }; public static void UnmarshalJSON(this ref StoreCompression alg, ReadOnlySpan b) { var parsed = JsonSerializer.Deserialize(b); if (parsed == null) throw new InvalidDataException("compression value must be a JSON string"); alg = parsed switch { "none" => StoreCompression.NoCompression, "s2" => StoreCompression.S2Compression, _ => throw new InvalidOperationException("unknown compression algorithm"), }; } public static void UnmarshalJSON(this ref StoreCompression alg, byte[] b) { ArgumentNullException.ThrowIfNull(b); UnmarshalJSON(ref alg, b.AsSpan()); } public static (byte[]? Buffer, Exception? Error) Compress(this StoreCompression alg, byte[] buf) { ArgumentNullException.ThrowIfNull(buf); const int checksumSize = FileStoreDefaults.RecordHashSize; if (buf.Length < checksumSize) return (null, new InvalidDataException("uncompressed buffer is too short")); return alg switch { StoreCompression.NoCompression => (buf, null), StoreCompression.S2Compression => CompressS2(buf, checksumSize), _ => (null, new InvalidOperationException("compression algorithm not known")), }; } private static (byte[]? Buffer, Exception? Error) CompressS2(byte[] buf, int checksumSize) { try { var bodyLength = buf.Length - checksumSize; var compressedBody = Snappy.Encode(buf.AsSpan(0, bodyLength)); var output = new byte[compressedBody.Length + checksumSize]; Buffer.BlockCopy(compressedBody, 0, output, 0, compressedBody.Length); Buffer.BlockCopy(buf, bodyLength, output, compressedBody.Length, checksumSize); return (output, null); } catch (Exception ex) { return (null, new IOException("error writing to compression writer", ex)); } } }