90 lines
3.1 KiB
C#
90 lines
3.1 KiB
C#
using System.Text.Json;
|
|
using IronSnappy;
|
|
|
|
namespace ZB.MOM.NatsNet.Server;
|
|
|
|
/// <summary>
|
|
/// String/JSON helpers for store enums that mirror Go enum methods.
|
|
/// </summary>
|
|
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<byte> b)
|
|
{
|
|
var parsed = JsonSerializer.Deserialize<string>(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));
|
|
}
|
|
}
|
|
}
|