refactor: split node agent and Go control plane
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using ZstdSharp;
|
||||
|
||||
namespace WxAgent.Core;
|
||||
|
||||
/// <summary>Database-backed message with stable identity, sender and timestamps.</summary>
|
||||
public sealed record DbMessage(
|
||||
long LocalId,
|
||||
long ServerId,
|
||||
string ChatId,
|
||||
string? SenderWxId,
|
||||
string? SenderName,
|
||||
string? SenderAvatarUrl,
|
||||
long Type,
|
||||
string Content,
|
||||
DateTimeOffset Timestamp,
|
||||
bool? IsSelf);
|
||||
|
||||
public static class WechatDbMessage
|
||||
{
|
||||
// WeChat 4.x stores message_content as hex; rows with WCDB_CT_message_content=1 are zstd-compressed (magic 28 b5 2f fd).
|
||||
public static string TableNameFor(string chatId) =>
|
||||
"Msg_" + Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes(chatId))).ToLowerInvariant();
|
||||
|
||||
public static string DecodeContent(string hexContent, bool compressed)
|
||||
{
|
||||
if (string.IsNullOrEmpty(hexContent)) return string.Empty;
|
||||
if (hexContent.Length > WechatMergedChatParser.MaxXmlCharacters * 2)
|
||||
throw new InvalidDataException("Database message content exceeds the decoding limit.");
|
||||
byte[] bytes;
|
||||
try
|
||||
{
|
||||
bytes = Convert.FromHexString(hexContent);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (compressed && bytes.Length >= 4 && bytes[0] == 0x28 && bytes[1] == 0xb5 && bytes[2] == 0x2f && bytes[3] == 0xfd)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var source = new MemoryStream(bytes);
|
||||
using var decompressor = new DecompressionStream(source);
|
||||
using var reader = new StreamReader(decompressor, Encoding.UTF8);
|
||||
var decoded = new StringBuilder();
|
||||
var buffer = new char[4096];
|
||||
int read;
|
||||
while ((read = reader.Read(buffer, 0, buffer.Length)) != 0)
|
||||
{
|
||||
if (decoded.Length + read > WechatMergedChatParser.MaxXmlCharacters)
|
||||
throw new InvalidDataException("Decompressed message exceeds the decoding limit.");
|
||||
decoded.Append(buffer, 0, read);
|
||||
}
|
||||
return decoded.ToString();
|
||||
}
|
||||
catch (Exception exception) when (exception is not (OutOfMemoryException or InvalidDataException))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
return compressed ? string.Empty : Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
|
||||
/// <summary>The account root directory name is <wxid>_<random>; the reference project treats the wxid prefix as self.</summary>
|
||||
public static bool? IsSelf(string? senderWxId, string? accountRootDirectoryName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(senderWxId) || string.IsNullOrEmpty(accountRootDirectoryName)) return null;
|
||||
return accountRootDirectoryName.StartsWith(senderWxId + "_", StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user