submodule对gitea不管用,所以直接拉了一份拉格兰

This commit is contained in:
2025-02-04 16:29:43 +08:00
parent b0bfc803e3
commit d149a2ea0f
1023 changed files with 43308 additions and 18 deletions

View File

@@ -0,0 +1,28 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("delete_essence_msg")]
public class DeleteEssenceMessageOperation(LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetMessage>(SerializerOptions.DefaultOptions) is { } getMsg)
{
var record = database.GetCollection<MessageRecord>().FindById(getMsg.MessageId);
var chain = (MessageChain)record;
bool result = await context.RemoveEssenceMessage(chain);
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,29 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("delete_msg")]
public class DeleteMessageOperation(LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetMessage>(SerializerOptions.DefaultOptions) is { } getMsg)
{
var record = database.GetCollection<MessageRecord>().FindById(getMsg.MessageId);
var chain = (MessageChain)record;
if (chain.IsGroup && await context.RecallGroupMessage(chain)) return new OneBotResult(null, 0, "ok");
if (!chain.IsGroup && await context.RecallFriendMessage(chain)) return new OneBotResult(null, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("friend_poke")]
public class FriendPokeOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotFriendPoke>(SerializerOptions.DefaultOptions) is { } poke)
{
bool result = await context.FriendPoke(poke.UserId);
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,128 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Message;
using Lagrange.OneBot.Core.Notify;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using Lagrange.OneBot.Message.Entity;
#pragma warning disable CS8618
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("get_essence_msg_list")]
public class GetEssenceMessageListOperation(TicketService ticket) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotEssenceMessage>(SerializerOptions.DefaultOptions) is { } essenceMsg)
{
int bkn = await ticket.GetCsrfToken();
int page = 0;
var essence = new List<OneBotEssenceMessageSegment>();
while (true)
{
string url = $"https://qun.qq.com/cgi-bin/group_digest/digest_list?random=7800&X-CROSS-ORIGIN=fetch&group_code={essenceMsg.GroupId}&page_start={page}&page_limit=20&bkn={bkn}";
var response = await ticket.SendAsync(new HttpRequestMessage(HttpMethod.Get, url));
string raw = await response.Content.ReadAsStringAsync();
var @object = JsonSerializer.Deserialize<RequestBody>(raw);
if (@object?.Data.MsgList == null) break;
foreach (var msg in @object.Data.MsgList)
{
essence.Add(new OneBotEssenceMessageSegment
{
SenderId = uint.Parse(msg.SenderUin),
SenderNick = msg.SenderNick,
SenderTime = msg.SenderTime,
OperatorId = uint.Parse(msg.AddDigestUin),
OperatorNick = msg.AddDigestNick,
OperatorTime = msg.AddDigestTime,
MessageId = MessageRecord.CalcMessageHash(msg.MsgRandom, msg.MsgSeq),
Content = ConvertToSegment(msg.MsgContent)
});
}
if (@object.Data.IsEnd) break;
page++;
}
return new OneBotResult(essence, 0, "ok");
}
throw new Exception();
}
private static List<OneBotSegment> ConvertToSegment(IEnumerable<JsonObject> elements)
{
var segments = new List<OneBotSegment>();
foreach (var msg in elements)
{
uint type = msg["msg_type"]?.GetValue<uint>() ?? throw new InvalidDataException("Invalid type");
var segment = type switch
{
1 => new OneBotSegment("text", new TextSegment(msg["text"]?.GetValue<string>() ?? "")),
2 => new OneBotSegment("face", new FaceSegment(msg["face_index"]?.GetValue<int?>() ?? 0)),
3 => new OneBotSegment("image", new ImageSegment(msg["image_url"]?.GetValue<string>() ?? "", "")),
4 => new OneBotSegment("video", new VideoSegment(msg["file_thumbnail_url"]?.GetValue<string>() ?? "")),
_ => throw new InvalidDataException("Unknown type found in essence msg")
};
segments.Add(segment);
}
return segments;
}
}
[Serializable]
file class RequestBody
{
[JsonPropertyName("retcode")] public long Retcode { get; set; }
[JsonPropertyName("retmsg")] public string Retmsg { get; set; }
[JsonPropertyName("data")] public Data Data { get; set; }
}
[Serializable]
file class Data
{
[JsonPropertyName("msg_list")] public MsgList[]? MsgList { get; set; }
[JsonPropertyName("is_end")] public bool IsEnd { get; set; }
[JsonPropertyName("group_role")] public long GroupRole { get; set; }
[JsonPropertyName("config_page_url")] public Uri ConfigPageUrl { get; set; }
}
[Serializable]
file class MsgList
{
[JsonPropertyName("group_code")] public string GroupCode { get; set; }
[JsonPropertyName("msg_seq")] public uint MsgSeq { get; set; }
[JsonPropertyName("msg_random")] public uint MsgRandom { get; set; }
[JsonPropertyName("sender_uin")] public string SenderUin { get; set; }
[JsonPropertyName("sender_nick")] public string SenderNick { get; set; }
[JsonPropertyName("sender_time")] public uint SenderTime { get; set; }
[JsonPropertyName("add_digest_uin")] public string AddDigestUin { get; set; }
[JsonPropertyName("add_digest_nick")] public string AddDigestNick { get; set; }
[JsonPropertyName("add_digest_time")] public uint AddDigestTime { get; set; }
[JsonPropertyName("msg_content")] public JsonObject[] MsgContent { get; set; }
[JsonPropertyName("can_be_removed")] public bool CanBeRemoved { get; set; }
}

View File

@@ -0,0 +1,42 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Entity.Message;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Message;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("get_forward_msg")]
public class GetForwardMsgOperation(MessageService service) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetForwardMsg>(SerializerOptions.DefaultOptions) is { } forwardMsg)
{
var (code, chains) = await context.GetMessagesByResId(forwardMsg.Id);
if (code != 0) return new OneBotResult(null, code, "failed");
var nodes = new List<OneBotSegment>();
if (chains == null) return new OneBotResult(new OneBotGetForwardMsgResponse(nodes), 0, "ok");
foreach (var chain in chains)
{
var parsed = service.Convert(chain);
var nickname = string.IsNullOrEmpty(chain.FriendInfo?.Nickname)
? chain.GroupMemberInfo?.MemberName
: chain.FriendInfo?.Nickname;
var node = new OneBotNode(chain.FriendUin.ToString(), nickname ?? "", parsed);
nodes.Add(new OneBotSegment("node", node));
}
return new OneBotResult(new OneBotGetForwardMsgResponse(nodes), 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,39 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Message;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using Lagrange.OneBot.Message;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("get_friend_msg_history")]
public class GetFriendMessageHistoryOperation(LiteDatabase database, MessageService message) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotFriendMsgHistory>(SerializerOptions.DefaultOptions) is { } history)
{
var collection = database.GetCollection<MessageRecord>();
var record = history.MessageId == 0
? collection.Find(x => x.FriendUin == history.UserId).OrderByDescending(x => x.Time).First()
: collection.FindById(history.MessageId);
var chain = (MessageChain)record;
if (await context.GetRoamMessage(chain, history.Count) is { } results)
{
var messages = results
.Select(x => message.ConvertToPrivateMsg(context.BotUin, x))
.ToList();
return new OneBotResult(new OneBotFriendMsgHistoryResponse(messages), 0, "ok");
}
}
throw new Exception();
}
}

View File

@@ -0,0 +1,39 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Message;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using Lagrange.OneBot.Message;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("get_group_msg_history")]
public class GetGroupMessageHistoryOperation(LiteDatabase database, MessageService message) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGroupMsgHistory>(SerializerOptions.DefaultOptions) is { } history)
{
var collection = database.GetCollection<MessageRecord>();
var record = history.MessageId == 0
? collection.Find(x => x.GroupUin == history.GroupId).OrderByDescending(x => x.Time).First()
: collection.FindById(history.MessageId);
var chain = (MessageChain)record;
if (await context.GetGroupMessage(history.GroupId, (uint)(chain.Sequence - history.Count + 1), chain.Sequence) is { } results)
{
var messages = results
.Select(x => message.ConvertToGroupMsg(context.BotUin, x))
.ToList();
return new OneBotResult(new OneBotGroupMsgHistoryResponse(messages), 0, "ok");
}
}
throw new Exception();
}
}

View File

@@ -0,0 +1,41 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Entity;
using Lagrange.Core.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Entity.Message;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using Lagrange.OneBot.Message;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("get_msg")]
public class GetMessageOperation(LiteDatabase database, MessageService service) : IOperation
{
public Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetMessage>(SerializerOptions.DefaultOptions) is { } getMsg)
{
var record = database.GetCollection<MessageRecord>().FindById(getMsg.MessageId);
var chain = (MessageChain)record;
OneBotSender sender = chain switch
{
{ GroupMemberInfo: BotGroupMember g } => new(g.Uin, g.MemberName),
{ FriendInfo: BotFriend f } => new(f.Uin, f.Nickname),
_ => new(chain.FriendUin, "")
};
var elements = service.Convert(chain);
var response = new OneBotGetMessageResponse(chain.Time, chain.IsGroup ? "group" : "private", record.MessageHash, sender, elements);
return Task.FromResult(new OneBotResult(response, 0, "ok"));
}
throw new Exception();
}
}

View File

@@ -0,0 +1,99 @@
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Common;
using Lagrange.OneBot.Core.Notify;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("get_music_ark")]
public class GetMusicArkOperation(TicketService ticket) : IOperation
{
private static readonly JsonSerializerOptions _options = new() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault };
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetMusicArk>(SerializerOptions.DefaultOptions) is not { } musicArk) throw new Exception();
var request = new HttpRequestMessage(HttpMethod.Get, "https://docs.qq.com/api/user/qq/login")
{
Headers =
{
{ "Accept", "application/json, text/plain, * /*" },
{ "referer", "https://docs.qq.com" },
}
};
using var response = await ticket.SendAsync(request, "docs.qq.com");
var json = await response.Content.ReadFromJsonAsync<JsonObject>();
string? uid = json?["result"]?["uid"]?.ToString();
string? uidKey = json?["result"]?["uid_key"]?.ToString();
if (string.IsNullOrEmpty(uid) || string.IsNullOrEmpty(uidKey)) throw new Exception();
var docsArk = new LightApp
{
App = "com.tencent.tdoc.qqpush",
Config = new Config
{
Ctime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Forward = 1,
Token = "",
Type = "normal",
},
Extra = new Extra
{
AppId = 1,
AppType = 0,
Uin = context.BotUin
},
Meta = new Meta
{
Music = new Music
{
Action = "",
AndroidPkgName = "",
AppType = 1,
AppId = 0,
Ctime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Desc = musicArk.Desc,
JumpUrl = musicArk.JumpUrl, // 在 ntqqpc 可正常使用 手机 噗叽 pia 了
MusicUrl = musicArk.MusicUrl, // 在 手机 可正常使用 ntqqpc 噗叽 pia 了
Preview = musicArk.Preview, // 需白
SourceMsgId = "0",
SourceIcon = musicArk.SourceIcon, // 需白
SourceUrl = "",
Tag = musicArk.Tag,
Title = musicArk.Title,
Uin = context.BotUin
}
},
Prompt = $"[分享]{musicArk.Title}",
Ver = "0.0.0.1",
View = "music"
};
var arksRequest = new HttpRequestMessage(HttpMethod.Post, "https://docs.qq.com/v2/push/ark_sig")
{
Headers =
{
{ "Cookie", (await ticket.GetCookies("docs.qq.com")) + $"uid={uid}; uid_key={uidKey}" }
},
Content = JsonContent.Create(new JsonObject {
{"ark", JsonSerializer.Serialize(docsArk, _options)},
{"object_id", "YjONkUwkdtFr"}
})
};
using var arksResponse = await ticket.SendAsync(arksRequest);
var arksJson = await arksResponse.Content.ReadFromJsonAsync<JsonObject>();
string? arkWithSig = arksJson?["result"]?["ark_with_sig"]?.ToString();
return arkWithSig != null ? new OneBotResult(arkWithSig, 0, "ok") : new OneBotResult(null, arksJson!["retcode"]!.GetValue<int>(), arksJson!["msg"]!.ToString());
}
}

View File

@@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("group_poke")]
public class GroupPokeOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGroupPoke>(SerializerOptions.DefaultOptions) is { } poke)
{
bool result = await context.GroupPoke(poke.GroupId, poke.UserId);
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,28 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("mark_msg_as_read")]
internal class MarkMsgAsReadOperation(LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetMessage>(SerializerOptions.DefaultOptions) is { } getMsg)
{
var record = database.GetCollection<MessageRecord>().FindById(getMsg.MessageId);
var chain = (MessageChain)record;
bool result = await context.MarkAsRead(chain);
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,256 @@
using System.Reflection;
using System.Text.Json;
using System.Text.RegularExpressions;
using Lagrange.Core;
using Lagrange.Core.Message;
using Lagrange.Core.Utility.Extension;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Message;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Message;
using LiteDB;
using Microsoft.Extensions.Logging;
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace Lagrange.OneBot.Core.Operation.Message;
public partial class MessageCommon
{
private readonly ILogger<MessageCommon> _logger;
private readonly Dictionary<string, SegmentBase> _typeToSegment;
public MessageCommon(LiteDatabase database, ILogger<MessageCommon> logger)
{
_logger = logger;
_typeToSegment = new Dictionary<string, SegmentBase>();
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
if (type.GetCustomAttribute<SegmentSubscriberAttribute>() is { } attribute)
{
var instance = (SegmentBase)type.CreateInstance(false);
instance.Database = database;
_typeToSegment[attribute.SendType] = instance;
}
}
}
public MessageBuilder ParseFakeChain(OneBotFakeNode message)
{
var builder = MessageBuilder.Friend(uint.Parse(message.Uin)).FriendName(message.Name);
BuildMessages(builder, message.Content);
return builder;
}
public MessageBuilder ParseFakeChain(OneBotFakeNodeSimple message)
{
var builder = MessageBuilder.Friend(uint.Parse(message.Uin)).FriendName(message.Name);
BuildMessages(builder, message.Content);
return builder;
}
public MessageBuilder ParseFakeChain(OneBotFakeNodeText message)
{
var builder = MessageBuilder.Friend(uint.Parse(message.Uin)).FriendName(message.Name);
BuildMessages(builder, message.Content);
return builder;
}
public MessageBuilder ParseChain(OneBotMessage message)
{
var builder = message.MessageType == "private" || message.GroupId == null
? MessageBuilder.Friend(message.UserId ?? 0)
: MessageBuilder.Group(message.GroupId.Value);
BuildMessages(builder, message.Messages);
return builder;
}
public MessageBuilder ParseChain(OneBotMessageSimple message)
{
var builder = message.MessageType == "private" || message.GroupId == null
? MessageBuilder.Friend(message.UserId ?? 0)
: MessageBuilder.Group(message.GroupId.Value);
BuildMessages(builder, message.Messages);
return builder;
}
public MessageBuilder ParseChain(OneBotMessageText message)
{
var builder = message.MessageType == "private" || message.GroupId == null
? MessageBuilder.Friend(message.UserId ?? 0)
: MessageBuilder.Group(message.GroupId.Value);
if (message.AutoEscape == true)
{
builder.Text(message.Messages);
}
else
{
BuildMessages(builder, message.Messages);
}
return builder;
}
public MessageBuilder ParseChain(OneBotPrivateMessage message)
{
var builder = MessageBuilder.Friend(message.UserId);
BuildMessages(builder, message.Messages);
return builder;
}
public MessageBuilder ParseChain(OneBotPrivateMessageSimple message)
{
var builder = MessageBuilder.Friend(message.UserId);
BuildMessages(builder, message.Messages);
return builder;
}
public MessageBuilder ParseChain(OneBotPrivateMessageText message)
{
var builder = MessageBuilder.Friend(message.UserId);
if (message.AutoEscape == true)
{
builder.Text(message.Messages);
}
else
{
BuildMessages(builder, message.Messages);
}
return builder;
}
public MessageBuilder ParseChain(OneBotGroupMessage message)
{
var builder = MessageBuilder.Group(message.GroupId);
BuildMessages(builder, message.Messages);
return builder;
}
public MessageBuilder ParseChain(OneBotGroupMessageSimple message)
{
var builder = MessageBuilder.Group(message.GroupId);
BuildMessages(builder, message.Messages);
return builder;
}
public MessageBuilder ParseChain(OneBotGroupMessageText message)
{
var builder = MessageBuilder.Group(message.GroupId);
if (message.AutoEscape == true)
{
builder.Text(message.Messages);
}
else
{
BuildMessages(builder, message.Messages);
}
return builder;
}
[GeneratedRegex(@"\[CQ:([^,\]]+)(?:,([^,\]]+))*\]")]
private static partial Regex CQCodeRegex();
private static string UnescapeCQ(string str) => str.Replace("&#91;", "[")
.Replace("&#93;", "]")
.Replace("&#44;", ",")
.Replace("&amp;", "&");
private static string UnescapeText(string str) => str.Replace("&#91;", "[")
.Replace("&#93;", "]")
.Replace("&amp;", "&");
private void BuildMessages(MessageBuilder builder, string message)
{
var matches = CQCodeRegex().Matches(message);
int textStart = 0;
foreach (var match in matches.Cast<Match>())
{
if (match.Index > textStart) builder.Text(UnescapeText(message[textStart..match.Index]));
textStart = match.Index + match.Length;
string type = match.Groups[1].Value;
if (_typeToSegment.TryGetValue(type, out var instance))
{
var data = new Dictionary<string, string>();
foreach (var capture in match.Groups[2].Captures.Cast<Capture>())
{
var pair = capture.Value.Split('=', 2);
if (pair.Length == 2) data[pair[0]] = UnescapeCQ(pair[1]);
}
if (JsonSerializer.SerializeToElement(data).Deserialize(instance.GetType(), SerializerOptions.DefaultOptions) is SegmentBase cast) instance.Build(builder, cast);
else Log.LogCQFailed(_logger, type, string.Empty);
}
}
if (textStart < message.Length) builder.Text(UnescapeText(message[textStart..]));
}
private void BuildMessages(MessageBuilder builder, List<OneBotSegment> segments)
{
foreach (var segment in segments)
{
if (_typeToSegment.TryGetValue(segment.Type, out var instance))
{
if (((JsonElement)segment.Data).Deserialize(instance.GetType(), SerializerOptions.DefaultOptions) is SegmentBase cast) instance.Build(builder, cast);
else Log.LogCQFailed(_logger, segment.Type, string.Empty);
}
}
}
private void BuildMessages(MessageBuilder builder, OneBotSegment segment)
{
if (_typeToSegment.TryGetValue(segment.Type, out var instance))
{
if (((JsonElement)segment.Data).Deserialize(instance.GetType(), SerializerOptions.DefaultOptions) is SegmentBase cast)
{
instance.Build(builder, cast);
}
else
{
Log.LogCQFailed(_logger, segment.Type, string.Empty);
}
}
}
public List<MessageChain> BuildForwardChains(BotContext context, OneBotForward forward)
{
List<MessageChain> chains = [];
foreach (var segment in forward.Messages)
{
if (((JsonElement)segment.Data).Deserialize<OneBotFakeNodeBase>(SerializerOptions.DefaultOptions) is { } element)
{
var chain = element switch
{
OneBotFakeNode message => ParseFakeChain(message).Build(),
OneBotFakeNodeSimple messageSimple => ParseFakeChain(messageSimple).Build(),
OneBotFakeNodeText messageText => ParseFakeChain(messageText).Build(),
_ => throw new Exception()
};
chains.Add(chain); // as fake is constructed, use uid from bot itself to upload image
}
}
return chains;
}
private static partial class Log
{
[LoggerMessage(EventId = 1, Level = LogLevel.Warning, Message = "Segment {type} Deserialization failed for code {code}")]
public static partial void LogCQFailed(ILogger logger, string type, string code);
}
}

View File

@@ -0,0 +1,32 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Internal.Event.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Message;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("send_forward_msg")]
public class SendForwardMessageOperation(MessageCommon common) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotForward>(SerializerOptions.DefaultOptions) is { } forward)
{
var chains = common.BuildForwardChains(context, forward);
var @event = MultiMsgUploadEvent.Create(null, chains);
var result = await context.ContextCollection.Business.SendEvent(@event);
if (result.Count != 0 && result[0] is MultiMsgUploadEvent res)
{
return new OneBotResult(res.ResId, 0, "ok");
}
return new OneBotResult(null, 404, "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,34 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("send_group_ai_record")]
public class SendGroupAiRecordOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotGetAiRecord>(SerializerOptions.DefaultOptions);
if (message != null)
{
(int code, string _, var recordEntity) = await context.GetGroupGenerateAiRecord(
message.GroupId,
message.Character,
message.Text,
message.ChatType
);
return recordEntity != null && code == 0
? new OneBotResult(new OneBotMessageResponse(0), code, "ok")
: new OneBotResult(null, code, "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,37 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.Core.Message.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("send_group_forward_msg")]
public class SendGroupForwardOperation(MessageCommon common) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGroupForward>(SerializerOptions.DefaultOptions) is { } forward)
{
var chains = common.BuildForwardChains(context, forward);
var multi = new MultiMsgEntity(chains);
var chain = MessageBuilder.Group(forward.GroupId).Add(multi).Build();
var ret = await context.SendMessage(chain);
if (ret.Result != 0) return new OneBotResult(null, (int)ret.Result, "failed");
if (ret.Sequence == null || ret.Sequence == 0) return new OneBotResult(null, 9000, "failed");
int hash = MessageRecord.CalcMessageHash(chain.MessageId, ret.Sequence ?? 0);
return new OneBotResult(new OneBotForwardResponse(hash, multi.ResId ?? ""), (int)ret.Result, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,34 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("send_group_msg")]
public sealed class SendGroupMessageOperation(MessageCommon common) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var chain = payload.Deserialize<OneBotGroupMessageBase>(SerializerOptions.DefaultOptions) switch
{
OneBotGroupMessage message => common.ParseChain(message).Build(),
OneBotGroupMessageSimple messageSimple => common.ParseChain(messageSimple).Build(),
OneBotGroupMessageText messageText => common.ParseChain(messageText).Build(),
_ => throw new Exception()
};
var result = await context.SendMessage(chain);
if (result.Result != 0) return new OneBotResult(null, (int)result.Result, "failed");
if (result.Sequence == null || result.Sequence == 0) return new OneBotResult(null, 9000, "failed");
int hash = MessageRecord.CalcMessageHash(chain.MessageId, result.Sequence ?? 0);
return new OneBotResult(new OneBotMessageResponse(hash), (int)result.Result, "ok");
}
}

View File

@@ -0,0 +1,55 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("send_msg")]
public sealed class SendMessageOperation(MessageCommon common, LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var chain = payload.Deserialize<OneBotMessageBase>(SerializerOptions.DefaultOptions) switch
{
OneBotMessage message => common.ParseChain(message).Build(),
OneBotMessageSimple messageSimple => common.ParseChain(messageSimple).Build(),
OneBotMessageText messageText => common.ParseChain(messageText).Build(),
_ => throw new Exception()
};
var result = await context.SendMessage(chain);
if (result.Result != 0) return new OneBotResult(null, (int)result.Result, "failed");
if (result.Sequence == null || result.Sequence == 0) return new OneBotResult(null, 9000, "failed");
int hash = MessageRecord.CalcMessageHash(result.MessageId, result.Sequence ?? 0);
if (!chain.IsGroup) database.GetCollection<MessageRecord>().Insert(hash, new()
{
FriendUin = context.BotUin,
Sequence = result.Sequence ?? 0,
ClientSequence = result.ClientSequence,
Time = DateTimeOffset.FromUnixTimeSeconds(result.Timestamp).LocalDateTime,
MessageId = result.MessageId,
FriendInfo = new(
context.BotUin,
context.ContextCollection.Keystore.Uid ?? string.Empty,
context.BotName ?? string.Empty,
string.Empty,
string.Empty,
string.Empty
),
Entities = chain,
MessageHash = hash,
TargetUin = chain.FriendUin
});
return new OneBotResult(new OneBotMessageResponse(hash), 0, "ok");
}
}

View File

@@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("send_poke")]
public class SendPokeOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSendPoke>(SerializerOptions.DefaultOptions) is { } poke)
{
bool result = poke.GroupId.HasValue ? await context.GroupPoke(poke.GroupId.Value, poke.UserId) : await context.FriendPoke(poke.UserId);
return new OneBotResult(null, result ? 0 : -1, result ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,59 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.Core.Message.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("send_private_forward_msg")]
public class SendPrivateForwardOperation(MessageCommon common, LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotPrivateForward>(SerializerOptions.DefaultOptions) is { } forward)
{
var chains = common.BuildForwardChains(context, forward);
var multi = new MultiMsgEntity([.. chains]);
var chain = MessageBuilder.Friend(forward.UserId).Add(multi).Build();
var result = await context.SendMessage(chain);
if (result.Result != 0) return new OneBotResult(null, (int)result.Result, "failed");
if (result.Sequence == null || result.Sequence == 0) return new OneBotResult(null, 9000, "failed");
int hash = MessageRecord.CalcMessageHash(result.MessageId, result.Sequence ?? 0);
database.GetCollection<MessageRecord>().Insert(hash, new()
{
FriendUin = context.BotUin,
Sequence = result.Sequence ?? 0,
ClientSequence = result.ClientSequence,
Time = DateTimeOffset.FromUnixTimeSeconds(result.Timestamp).LocalDateTime,
MessageId = result.MessageId,
FriendInfo = new(
context.BotUin,
context.ContextCollection.Keystore.Uid ?? string.Empty,
context.BotName ?? string.Empty,
string.Empty,
string.Empty,
string.Empty
),
Entities = chain,
MessageHash = hash,
TargetUin = chain.FriendUin
});
return new OneBotResult(new OneBotForwardResponse(hash, multi.ResId ?? ""), 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,55 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("send_private_msg")]
public sealed class SendPrivateMessageOperation(MessageCommon common, LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var chain = payload.Deserialize<OneBotPrivateMessageBase>(SerializerOptions.DefaultOptions) switch
{
OneBotPrivateMessage message => common.ParseChain(message).Build(),
OneBotPrivateMessageSimple messageSimple => common.ParseChain(messageSimple).Build(),
OneBotPrivateMessageText messageText => common.ParseChain(messageText).Build(),
_ => throw new Exception()
};
var result = await context.SendMessage(chain);
if (result.Result != 0) return new OneBotResult(null, (int)result.Result, "failed");
if (result.Sequence == null || result.Sequence == 0) return new OneBotResult(null, 9000, "failed");
int hash = MessageRecord.CalcMessageHash(result.MessageId, result.Sequence ?? 0);
database.GetCollection<MessageRecord>().Insert(hash, new()
{
FriendUin = context.BotUin,
Sequence = result.Sequence ?? 0,
ClientSequence = result.ClientSequence,
Time = DateTimeOffset.FromUnixTimeSeconds(result.Timestamp).LocalDateTime,
MessageId = result.MessageId,
FriendInfo = new(
context.BotUin,
context.ContextCollection.Keystore.Uid ?? string.Empty,
context.BotName ?? string.Empty,
string.Empty,
string.Empty,
string.Empty
),
Entities = chain,
MessageHash = hash,
TargetUin = chain.FriendUin
});
return new OneBotResult(new OneBotMessageResponse(hash), 0, "ok");
}
}

View File

@@ -0,0 +1,28 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Message;
[Operation("set_essence_msg")]
public class SetEssenceMessageOperation(LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetMessage>(SerializerOptions.DefaultOptions) is { } getMsg)
{
var record = database.GetCollection<MessageRecord>().FindById(getMsg.MessageId);
var chain = (MessageChain)record;
bool result = await context.SetEssenceMessage(chain);
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
throw new Exception();
}
}