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,12 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
namespace Lagrange.OneBot.Core.Operation.Ability;
[Operation("can_send_image")]
public class CanSendImage : IOperation
{
public Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload) =>
Task.FromResult(new OneBotResult(new JsonObject { { "yes", Constant.CanSendImage } }, 0, "ok"));
}

View File

@@ -0,0 +1,12 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
namespace Lagrange.OneBot.Core.Operation.Ability;
[Operation("can_send_record")]
public class CanSendRecord : IOperation
{
public Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload) =>
Task.FromResult(new OneBotResult(new JsonObject { { "yes", Constant.CanSendRecord } }, 0, "ok"));
}

View File

@@ -0,0 +1,24 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Message.Entity;
namespace Lagrange.OneBot.Core.Operation.Ability;
[Operation("upload_image")]
public class UploadImageOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload?["file"]?.ToString() is { } file && CommonResolver.ResolveStream(file) is { } stream)
{
var entity = new ImageEntity(stream);
var url = await context.UploadImage(entity);
return new OneBotResult(url, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,24 @@
using System.Buffers;
using System.Buffers.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Lagrange.OneBot.Core.Operation.Converters;
public class AutosizeConverter : JsonConverter<bool>
{
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.String when Utf8Parser.TryParse(reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan, out bool value, out _) => value,
JsonTokenType.String when Utf8Parser.TryParse(reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan, out int intValue, out _) => intValue != 0,
JsonTokenType.Number when reader.TryGetInt32(out int val) => Convert.ToBoolean(val),
_ => throw new JsonException()
};
}
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options) => writer.WriteBooleanValue(value);
}

View File

@@ -0,0 +1,25 @@
using System.Buffers;
using System.Buffers.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Lagrange.OneBot.Core.Operation.Converters;
public class BooleanConverter : JsonConverter<bool>
{
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.String when Utf8Parser.TryParse(reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan, out bool value, out _) => value,
_ => throw new JsonException()
};
}
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
{
writer.WriteBooleanValue(value);
}
}

View File

@@ -0,0 +1,20 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Lagrange.OneBot.Core.Operation.Converters;
public class ForwardConverter : JsonConverter<int>
{
public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TokenType switch
{
JsonTokenType.True => 1,
JsonTokenType.False => 0,
JsonTokenType.Number when reader.TryGetInt32(out int intValue) => intValue,
_ => throw new JsonException()
};
}
public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) => writer.WriteNumberValue(value);
}

View File

@@ -0,0 +1,19 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Lagrange.OneBot.Core.Operation.Converters;
public class NullIfEmptyConverter<T> : JsonConverter<T> where T : class
{
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TokenType switch
{
JsonTokenType.String when reader.ValueSpan.Length == 0 => null,
JsonTokenType.StartObject => JsonSerializer.Deserialize<T>(ref reader, options),
_ => throw new JsonException()
};
}
public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) => JsonSerializer.Serialize(writer, value, options);
}

View File

@@ -0,0 +1,13 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Lagrange.OneBot.Core.Operation.Converters;
public static class SerializerOptions
{
public static JsonSerializerOptions DefaultOptions => new()
{
Converters = { new BooleanConverter() },
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
}

View File

@@ -0,0 +1,164 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Entity;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
using Lagrange.OneBot.Core.Entity.File;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Utility;
namespace Lagrange.OneBot.Core.Operation.File;
[Operation("get_group_file_url")]
public class GetGroupFileUrlOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetFileUrl>(SerializerOptions.DefaultOptions) is { } url)
{
string raw = await context.FetchGroupFSDownload(url.GroupId, url.FileId);
return new OneBotResult(new JsonObject { { "url", raw } }, 0, "ok");
}
throw new Exception();
}
}
[Operation("get_group_root_files")]
[Operation("get_group_files_by_folder")]
public class GetGroupRootFilesOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetFiles>(SerializerOptions.DefaultOptions) is { } file)
{
var entries = await context.FetchGroupFSList(file.GroupId, file.FolderId ?? "/");
var files = new List<OneBotFile>();
var folders = new List<OneBotFolder>();
foreach (var entry in entries)
{
switch (entry)
{
case BotFileEntry fileEntry:
{
var members = await context.FetchMembers(file.GroupId);
var member = members.FirstOrDefault(x => x.Uin == fileEntry.UploaderUin);
files.Add(new OneBotFile
{
GroupId = file.GroupId,
FileId = fileEntry.FileId,
FileName = fileEntry.FileName,
BusId = 0,
FileSize = fileEntry.FileSize,
UploadTime = fileEntry.UploadedTime.ToTimestamp(),
DeadTime = fileEntry.ExpireTime.ToTimestamp(),
ModifyTime = fileEntry.ModifiedTime.ToTimestamp(),
DownloadTimes = fileEntry.DownloadedTimes,
Uploader = fileEntry.UploaderUin,
UploaderName = member?.MemberName ?? string.Empty
});
break;
}
case BotFolderEntry folderEntry:
{
var members = await context.FetchMembers(file.GroupId);
var member = members.FirstOrDefault(x => x.Uin == folderEntry.CreatorUin);
folders.Add(new OneBotFolder
{
GroupId = file.GroupId,
FolderId = folderEntry.FolderId,
FolderName = folderEntry.FolderName,
CreateTime = folderEntry.CreateTime.ToTimestamp(),
Creator = folderEntry.CreatorUin,
CreatorName = member?.MemberName ?? string.Empty,
TotalFileCount = folderEntry.TotalFileCount
});
break;
}
}
}
return new OneBotResult(new OneBotGetFilesResponse(files, folders), 0, "ok");
}
throw new Exception();
}
}
[Operation("move_group_file")]
public class MoveGroupFileOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotMoveFile>(SerializerOptions.DefaultOptions) is { } file)
{
var res = await context.GroupFSMove(file.GroupId, file.FileId, file.ParentDirectory, file.TargetDirectory);
return new OneBotResult(new JsonObject { { "msg", res.Item2 } }, res.Item1, res.Item1 == 0 ? "ok" : "failed");
}
throw new Exception();
}
}
[Operation("delete_group_file")]
public class DeleteGroupFileOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotDeleteFile>(SerializerOptions.DefaultOptions) is { } file)
{
var res = await context.GroupFSDelete(file.GroupId, file.FileId);
return new OneBotResult(new JsonObject { { "msg", res.Item2 } }, res.Item1, res.Item1 == 0 ? "ok" : "failed");
}
throw new Exception();
}
}
[Operation("create_group_file_folder")]
public class CreateGroupFileFolderOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotCreateFolder>(SerializerOptions.DefaultOptions) is { } folder)
{
var res = await context.GroupFSCreateFolder(folder.GroupId, folder.Name);
return new OneBotResult(new JsonObject { { "msg", res.Item2 } }, res.Item1, res.Item1 == 0 ? "ok" : "failed");
}
throw new Exception();
}
}
[Operation("delete_group_file_folder")]
public class DeleteGroupFileFolderOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotDeleteFolder>(SerializerOptions.DefaultOptions) is { } folder)
{
var res = await context.GroupFSDeleteFolder(folder.GroupId, folder.FolderId);
return new OneBotResult(new JsonObject { { "msg", res.Item2 } }, res.Item1, res.Item1 == 0 ? "ok" : "failed");
}
throw new Exception();
}
}
[Operation("rename_group_file_folder")]
public class RenameGroupFileFolderOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotRenameFolder>(SerializerOptions.DefaultOptions) is { } folder)
{
var res = await context.GroupFSRenameFolder(folder.GroupId, folder.FolderId, folder.NewFolderName);
return new OneBotResult(new JsonObject { { "msg", res.Item2 } }, res.Item1, res.Item1 == 0 ? "ok" : "failed");
}
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.File;
[Operation("get_private_file_url")]
public class GetPrivateFileUrlOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetPrivateFile>(SerializerOptions.DefaultOptions) is { } url)
{
string raw = await context.FetchPrivateFSDownload(url.FileId, url.FileHash, url.UserId);
return new OneBotResult(new JsonObject { { "url", raw } }, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,27 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.File;
[Operation("upload_group_file")]
public class UploadGroupFileOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotUploadGroupFile>(SerializerOptions.DefaultOptions) is { } file)
{
var entity = new FileEntity(file.File);
if (file.Name != null) entity.FileName = file.Name;
bool result = await context.GroupFSUpload(file.GroupId, entity, file.Folder ?? "/");
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,27 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.File;
[Operation("upload_private_file")]
public class UploadPrivateFile : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotUploadPrivateFile>(SerializerOptions.DefaultOptions) is { } file)
{
var entity = new FileEntity(file.File);
if (file.Name != null) entity.FileName = file.Name;
bool result = await context.UploadFriendFile(file.UserId, entity);
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,24 @@
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.Generic;
[Operation("delete_friend")]
public class DeleteFriendOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotDeleteFriend>(SerializerOptions.DefaultOptions) is {} delete)
{
return await context.DeleteFriend(delete.UserId, delete.Block)
? new OneBotResult(null, 0, "ok")
: new OneBotResult(null, 0, "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,13 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("fetch_custom_face")]
internal class FetchCustomFaceOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload) =>
new(await context.FetchCustomFace(), 0, "ok");
}

View File

@@ -0,0 +1,24 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("fetch_mface_key")]
internal class FetchMFaceKeyOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload?["emoji_ids"]?.Deserialize<string[]>() is { Length: not 0 } emojiIds)
{
if (await context.FetchMarketFaceKey([.. emojiIds]) is { Count: not 0 } keys)
{
return new(keys, 0, "ok");
}
else return new(Array.Empty<string>(), -1, "failed");
}
else throw new Exception();
}
}

View File

@@ -0,0 +1,27 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Message;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation(".join_friend_emoji_chain")]
public class FriendJoinEmojiChainOperation(LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotPrivateJoinEmojiChain>(SerializerOptions.DefaultOptions) is { } data)
{
var message = (MessageChain)database.GetCollection<MessageRecord>().FindById(data.MessageId);
bool res = await context.FriendJoinEmojiChain(data.UserId, data.EmojiId, message.Sequence);
return new OneBotResult(null, res ? 0 : -1, res ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,26 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("get_ai_characters")]
public class GetAiCharacters : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotGetAiCharacters>(SerializerOptions.DefaultOptions)
?? throw new Exception();
var (code, errMsg, result) = await context.GetAiCharacters(message.ChatType, message.GroupId);
if (code != 0) return new(null, -1, "failed");
return result != null
? new OneBotResult(result.Select(x => new OneBotAiCharacters(x)), 0, "ok")
: new OneBotResult(null, -1, "failed");
}
}

View File

@@ -0,0 +1,21 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("get_cookies")]
public class GetCookiesOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload?["domain"]?.ToString() is { } domain)
{
var cookies = await context.FetchCookies([domain]);
return new OneBotResult(new JsonObject { { "cookies", cookies[0] } }, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,28 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Notify;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("get_credentials")]
public class GetCredentialsOperation(TicketService ticket) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload?["domain"]?.ToString() is { } domain)
{
var cookies = await context.FetchCookies([domain]);
int bkn = await ticket.GetCsrfToken();
return new OneBotResult(new JsonObject
{
{ "cookies", cookies[0] },
{ "csrf_token", bkn }
}, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,16 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Notify;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("get_csrf_token")]
public class GetCsrfTokenOperation(TicketService ticket) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
int bkn = await ticket.GetCsrfToken();
return new OneBotResult(new JsonObject { { "token", bkn } }, 0, "ok");
}
}

View File

@@ -0,0 +1,30 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Internal.Event.System;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("get_rkey")]
public class GetRkey : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var fetchRKeyEvent = FetchRKeyEvent.Create();
var events = await context.ContextCollection.Business.SendEvent(fetchRKeyEvent);
var rKeyEvent = (FetchRKeyEvent)events[0];
if (rKeyEvent.ResultCode != 0) return new OneBotResult(null, rKeyEvent.ResultCode, "failed");
var response = new OneBotGetRkeyResponse(rKeyEvent.RKeys.Select(x => new OneBotRkey
{
Type = x.Type == 10
? "private"
: "group",
Rkey = x.Rkey,
CreateTime = x.RkeyCreateTime,
TtlSeconds = x.RkeyTtlSec
})
.ToList());
return new OneBotResult(response, 0, "ok");
}
}

View File

@@ -0,0 +1,27 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Message;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Database;
using LiteDB;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation(".join_group_emoji_chain")]
public class GroupJoinEmojiChainOperation(LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGroupJoinEmojiChain>(SerializerOptions.DefaultOptions) is { } data)
{
var message = (MessageChain)database.GetCollection<MessageRecord>().FindById(data.MessageId);
bool res = await context.GroupJoinEmojiChain(data.GroupId, data.EmojiId, message.Sequence);
return new OneBotResult(null, res ? 0 : -1, res ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,27 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Message.Entity;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Message.Entity;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation(".ocr_image")]
[Operation("ocr_image")]
public class OcrImageOperation() : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotOcrImage>(SerializerOptions.DefaultOptions) is { } data && CommonResolver.ResolveStream(data.Image) is { } stream)
{
var entity = new ImageEntity(stream);
var res = await context.OcrImage(entity);
return new OneBotResult(res, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,24 @@
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.Generic;
[Operation("send_like")]
public class SendLikeOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSendLike>(SerializerOptions.DefaultOptions) is { } like)
{
return await context.Like(like.UserId, like.Times ?? 1) // the times is ignored to simulate the real user behaviour
? new OneBotResult(null, 0, "ok")
: new OneBotResult(null, 0, "user not found in the buffer");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,33 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Internal.Packets;
using Lagrange.Core.Utility.Extension;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation(".send_packet")]
public class SendPacketOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSendPacket>() is { } send)
{
int sequence = context.ContextCollection.Service.GetNewSequence();
var ssoPacket = new SsoPacket(send.Type, send.Command, (uint)sequence, send.Data.UnHex());
var task = await context.ContextCollection.Packet.SendPacket(ssoPacket);
return new OneBotResult(new OneBotSendPacketResponse
{
Sequence = sequence,
RetCode = task.RetCode,
Extra = task.Extra,
Result = task.Payload.Hex()
}, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,27 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.Core.Message.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Message.Entity;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("set_qq_avatar")]
public class SetQQAvatar : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload?["file"]?.ToString() is { } portrait)
{
var image = CommonResolver.ResolveStream(portrait);
if (image == null) throw new Exception();
var imageEntity = new ImageEntity(image);
bool result = await context.SetAvatar(imageEntity);
return new OneBotResult(null, result ? 0 : 1, "");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,23 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Microsoft.Extensions.Hosting;
namespace Lagrange.OneBot.Core.Operation.Generic;
[Operation("set_restart")]
public class SetRestartOperation(IHost host) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
try
{
return new OneBotResult(null, 0, "ok");
}
finally
{
await host.StopAsync();
await host.StartAsync();
}
}
}

View File

@@ -0,0 +1,43 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Notify;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Group;
[Operation("_del_group_notice")]
public class DeleteGroupMemoOperation(TicketService ticket) : IOperation
{
private const string Url = "https://web.qun.qq.com/cgi-bin/announce/del_feed";
private const string Domain = "qun.qq.com";
private async Task<bool> DeleteGroupNotice(OneBotDeleteGroupMemo memo)
{
string url = $"{Url}?fid={memo.NoticeId}&qid={memo.GroupId}&bkn={await ticket.GetCsrfToken()}&ft=23&op=1";
var request = new HttpRequestMessage(HttpMethod.Get, url);
try
{
var response = await ticket.SendAsync(request, Domain);
response.EnsureSuccessStatusCode();
return true;
}
catch
{
return false;
}
}
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotDeleteGroupMemo>(SerializerOptions.DefaultOptions) is { } memo)
{
return await DeleteGroupNotice(memo)
? new OneBotResult(null, 0, "ok")
: new OneBotResult(null, -1, "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.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Group;
[Operation("get_ai_record")]
public class GetAiRecordOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotGetAiRecord>(SerializerOptions.DefaultOptions);
if (message != null)
{
var (code, errMsg, url) = await context.GetGroupGenerateAiRecordUrl(
message.GroupId,
message.Character,
message.Text,
message.ChatType
);
return code != 0 ? new OneBotResult(errMsg, code, "failed") : new OneBotResult(url, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,94 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Notify;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Group;
[Operation("get_group_honor_info")]
public partial class GetGroupHonorInfoOperation(TicketService ticket) : IOperation
{
[GeneratedRegex(@"window\.__INITIAL_STATE__\s*?=\s*?(\{.*?);")]
public static partial Regex HonorRegex();
private static readonly Dictionary<string, string> Keys = new()
{
{ "group_id", "group_id" }, { "current_talkative", "currentTalkative" }, { "talkative_list", "talkativeList" },
{ "performer_list", "" }, { "legend_list", "legendList" }, { "strong_newbie_list", "strongnewbieList" },
{ "emotion_list", "emotionList" }
};
private static readonly Dictionary<string, int> HonorToType = new()
{
{ "talkative", 1 }, { "performer", 2 }, { "legend", 3 }, { "strong_newbie", 5 }, { "emotion", 6 },
};
private static readonly Dictionary<string, string> KeyToOnebot11 = new()
{
{"uin", "user_id"}, {"name", "nickname"}, {"nick", "nickname"}, {"desc", "description"}
};
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotHonorInfo>(SerializerOptions.DefaultOptions) is { } honor)
{
var result = new JsonObject();
var honors = honor.Type == "all"
? HonorToType.Select(x => x.Key).ToArray()
: [honor.Type];
result.TryAdd("group_id", honor.GroupId);
foreach (string honorRaw in honors)
{
string url = $"https://qun.qq.com/interactive/honorlist?gc={honor.GroupId}&type={HonorToType[honorRaw]}";
var response = await ticket.SendAsync(new HttpRequestMessage(HttpMethod.Get, url));
string raw = await response.Content.ReadAsStringAsync();
var match = HonorRegex().Match(raw);
if (JsonSerializer.Deserialize<JsonObject>(match.Groups[1].Value) is { } json) // 神经病
{
foreach (var (key, value) in Keys)
{
if (json.Remove(value, out var node))
{
if (node is JsonObject jsonObject)
{
ProcessJsonObject(jsonObject);
}
else if (node is JsonArray jsonArray)
{
foreach (var subNode in jsonArray)
{
if (subNode is JsonObject subObject)
{
ProcessJsonObject(subObject);
}
}
}
if (key.Contains(honorRaw)) result.TryAdd(key, node);
}
}
}
}
return new OneBotResult(result, 0, "ok");
}
throw new Exception();
}
private static void ProcessJsonObject(JsonObject jsonObject)
{
foreach (var oldKey in KeyToOnebot11.Keys)
{
if (jsonObject.Remove(oldKey, out var nodeValue))
{
jsonObject[KeyToOnebot11[oldKey]] = nodeValue;
}
}
}
}

View File

@@ -0,0 +1,91 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Notify;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Group;
[Operation("_get_group_notice")]
public class GetGroupMemoOperation(TicketService ticket) : IOperation
{
private const string Url = "https://web.qun.qq.com/cgi-bin/announce/get_t_list";
private const string Domain = "qun.qq.com";
private async Task<IEnumerable<OneBotGroupNotice>?> GetGroupNotice(OneBotGetGroupMemo memo)
{
var url = $"{Url}?bkn={await ticket.GetCsrfToken()}&qid={memo.GroupId}&ft=23&ni=1&n=1&i=1&log_read=1&platform=1&s=-1&n=20";
var request = new HttpRequestMessage(HttpMethod.Get, url);
try
{
var response = await ticket.SendAsync(request, Domain);
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
var notices = JsonSerializer.Deserialize<GroupNoticeResponse>(content)!;
return notices.Feeds.Concat(notices.Inst)
.Select(feed => new OneBotGroupNotice(feed.NoticeId, feed.SenderId, feed.PublishTime,
new OneBotGroupNoticeMessage(feed.Message.Text, feed.Message.Images.Select(image => new OneBotGroupNoticeImage(image.Id, image.Height, image.Width)))
));
}
catch
{
return null;
}
}
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetGroupMemo>(SerializerOptions.DefaultOptions) is { } memo)
{
var notices = await GetGroupNotice(memo);
return notices is null
? new OneBotResult(null, -1, "failed")
: new OneBotResult(notices, 0, "ok");
}
throw new Exception();
}
}
[Serializable]
file class GroupNoticeImage
{
[JsonPropertyName("h")] public string Height { get; set; } = string.Empty;
[JsonPropertyName("w")] public string Width { get; set; } = string.Empty;
[JsonPropertyName("id")] public string Id { get; set; } = string.Empty;
}
[Serializable]
file class GroupNoticeMessage
{
[JsonPropertyName("text")] public string Text { get; set; } = string.Empty;
[JsonPropertyName("pics")] public IEnumerable<GroupNoticeImage> Images { get; set; } = [];
}
[Serializable]
file class GroupNoticeFeed
{
[JsonPropertyName("fid")] public string NoticeId { get; set; } = string.Empty;
[JsonPropertyName("u")] public uint SenderId { get; set; }
[JsonPropertyName("pubt")] public long PublishTime { get; set; }
[JsonPropertyName("msg")] public GroupNoticeMessage Message { get; set; } = new();
}
[Serializable]
file class GroupNoticeResponse
{
[JsonPropertyName("feeds")] public IEnumerable<GroupNoticeFeed> Feeds { get; set; } = [];
[JsonPropertyName("inst")] public IEnumerable<GroupNoticeFeed> Inst { get; set; } = [];
}

View File

@@ -0,0 +1,25 @@
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.Group;
[Operation("set_group_admin")]
public class SetGroupAdminOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupAdmin>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.SetGroupAdmin(message.GroupId, message.UserId, message.Enable);
return new OneBotResult(null, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,25 @@
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.Group;
[Operation("set_group_ban")]
public class SetGroupBanOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupBan>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.MuteGroupMember(message.GroupId, message.UserId, message.Duration);
return new OneBotResult(null, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,26 @@
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.Group;
[Operation("set_group_bot_status")]
public class SetGroupBotOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupBot>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.SetGroupBot(message.BotId, message.Enable , message.GroupId);
return new OneBotResult(message.BotId, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,26 @@
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.Group;
[Operation("send_group_bot_callback")]
public class SetGroupBothdOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupBothd>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.SetGroupBotHD(message.BotId, message.GroupId, message.Data_1, message.Data_2);
return new OneBotResult(message.BotId, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,25 @@
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.Group;
[Operation("set_group_card")]
public class SetGroupCardOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupCard>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.RenameGroupMember(message.GroupId, message.UserId, message.Card);
return new OneBotResult(null, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,25 @@
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.Group;
[Operation("set_group_kick")]
public class SetGroupKickOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupKick>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.KickGroupMember(message.GroupId, message.UserId, message.RejectAddRequest);
return new OneBotResult(null, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,25 @@
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.Group;
[Operation("set_group_leave")]
public class SetGroupLeaveOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupLeave>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.LeaveGroup(message.GroupId); // TODO: Figure out is_dismiss
return new OneBotResult(null, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,79 @@
using System.Text;
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.Notify;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Group;
[Operation("_send_group_notice")]
public class SetGroupMemoOperation(TicketService ticket) : IOperation
{
private const string Url = "https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=";
private const string UserAgent = "Dalvik/2.1.0 (Linux; U; Android 7.1.2; PCRT00 Build/N2G48H)";
private const string Domain = "qun.qq.com";
private async Task<string?> SendGroupNoticeSimple(OneBotSetGroupMemo memo)
{
int bkn = await ticket.GetCsrfToken();
string body = $"qid={memo.GroupId}&bkn={bkn}&text={Uri.EscapeDataString(memo.Content)}&pinned=0&type=1&settings={{\"is_show_edit_card\":0,\"tip_window_type\":1,\"confirm_required\":1}}";
string url = Url + bkn;
try
{
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.UserAgent.ParseAdd(UserAgent);
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await ticket.SendAsync(request, Domain);
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
var sendResponse = JsonSerializer.Deserialize<NoticeSendResponse>(content);
return sendResponse?.NoticeId;
}
catch
{
return null;
}
}
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSetGroupMemo>(SerializerOptions.DefaultOptions) is { } memo)
{
var noticeId = string.IsNullOrEmpty(memo.Image)
? await SendGroupNoticeSimple(memo)
: throw new NotImplementedException();
return noticeId is null
? new OneBotResult(null, -1, "failed")
: new OneBotResult(noticeId, 0, "ok");
}
throw new Exception();
}
}
[Serializable]
file class NoticeSendResponse
{
[JsonPropertyName("new_fid")] public string NoticeId { get; set; } = string.Empty;
}
[Serializable]
file class NoticeImageUploadResponse
{
[JsonPropertyName("ec")] public int ErrorCode { get; set; }
[JsonPropertyName("em")] public string ErrorMessage { get; set; } = string.Empty;
[JsonPropertyName("id")] public string Id { get; set; } = string.Empty;
}
[Serializable]
file class GroupNoticeImage
{
[JsonPropertyName("h")] public string Height { get; set; } = string.Empty;
[JsonPropertyName("w")] public string Width { get; set; } = string.Empty;
[JsonPropertyName("id")] public string Id { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,25 @@
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.Group;
[Operation("set_group_name")]
public class SetGroupNameOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupName>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.RenameGroup(message.GroupId, message.GroupName);
return new OneBotResult(null, 0, "ok");
}
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.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Message.Entity;
namespace Lagrange.OneBot.Core.Operation.Group;
[Operation("set_group_portrait")]
public class SetGroupPortraitOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSetGroupPortrait>(SerializerOptions.DefaultOptions) is { } portrait)
{
var image = CommonResolver.ResolveStream(portrait.File);
if (image == null) throw new Exception();
var imageEntity = new ImageEntity(image);
bool result = await context.GroupSetAvatar(portrait.GroupId, imageEntity);
return new OneBotResult(null, result ? 0 : 1, "");
}
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.Group;
[Operation("set_group_reaction")]
public class SetGroupReactionOperation(LiteDatabase database) : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSetGroupReaction>(SerializerOptions.DefaultOptions) is { } data)
{
var message = (MessageChain)database.GetCollection<MessageRecord>().FindById(data.MessageId);
bool result = await context.GroupSetMessageReaction(data.GroupId, message.Sequence, data.Code, data.IsAdd);
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
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.Group;
[Operation("set_group_special_title")]
public class SetGroupSpecialTitleOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSetGroupSpecialTitle>(SerializerOptions.DefaultOptions) is { } title)
{
bool result = await context.GroupSetSpecialTitle(title.GroupId, title.UserId, title.SpecialTitle);
return new OneBotResult(null, result ? 0 : 1, result ? "ok" : "failed");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,25 @@
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.Group;
[Operation("set_group_whole_ban")]
public class SetGroupWholeBanOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var message = payload.Deserialize<OneBotSetGroupWholeBan>(SerializerOptions.DefaultOptions);
if (message != null)
{
bool _ = await context.MuteGroupGlobal(message.GroupId, message.Enable);
return new OneBotResult(null, 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,10 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
namespace Lagrange.OneBot.Core.Operation;
public interface IOperation
{
public Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload);
}

View File

@@ -0,0 +1,21 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_friend_list")]
public class GetFriendListOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload) =>
new((await context.FetchFriends(true)).Select(friend => new OneBotFriend
{
UserId = friend.Uin,
QId = friend.Qid,
NickName = friend.Nickname,
Remark = friend.Remarks,
Group = new(friend.Group.GroupId, friend.Group.GroupName)
}).ToArray(), 0, "ok");
}

View File

@@ -0,0 +1,32 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_group_info")]
public class GetGroupInfoOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetGroupInfo>(SerializerOptions.DefaultOptions) is { } message)
{
var result = (await context.FetchGroups(message.NoCache)).FirstOrDefault(x => x.GroupUin == message.GroupId);
if (result == null && !message.NoCache)
{
result = (await context.FetchGroups(true)).FirstOrDefault(x => x.GroupUin == message.GroupId);
}
return result == null
? new OneBotResult(null, -1, "failed")
: new OneBotResult(new OneBotGroup(result), 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,27 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_group_list")]
public class GetGroupListOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetGroupInfo>(SerializerOptions.DefaultOptions) is { } message)
{
var result = await context.FetchGroups(message.NoCache);
return new OneBotResult(result.Select(x => new OneBotGroup(x)), 0, "ok");
}
else
{
var result = await context.FetchGroups();
return new OneBotResult(result.Select(x => new OneBotGroup(x)), 0, "ok");
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_group_member_info")]
public class GetGroupMemberInfoOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetGroupMemberInfo>(SerializerOptions.DefaultOptions) is { } message)
{
var result = (await context.FetchMembers(message.GroupId, message.NoCache)).FirstOrDefault(x => x.Uin == message.UserId);
return result == null
? new OneBotResult(null, -1, "failed")
: new OneBotResult(new OneBotGroupMember(message.GroupId,
result.Uin,
result.Permission.ToString().ToLower(),
result.GroupLevel.ToString(), result.MemberCard, result.MemberName, result.SpecialTitle,
(uint)new DateTimeOffset(result.JoinTime).ToUnixTimeSeconds(),
(uint)new DateTimeOffset(result.LastMsgTime).ToUnixTimeSeconds()),
0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,24 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_group_member_list")]
public class GetGroupMemberListOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetGroupMemberInfo>(SerializerOptions.DefaultOptions) is { } message)
{
var result = await context.FetchMembers(message.GroupId, message.NoCache);
return new OneBotResult(result.Select(x => new OneBotGroupMember(message.GroupId, x.Uin, x.Permission.ToString().ToLower(), x.GroupLevel.ToString(), x.MemberCard, x.MemberName, x.SpecialTitle, (uint)new DateTimeOffset(x.JoinTime).ToUnixTimeSeconds(), (uint)new DateTimeOffset(x.LastMsgTime).ToUnixTimeSeconds())), 0, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,17 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_login_info")]
public class GetLoginInfoOperation : IOperation
{
public Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var keystore = context.ContextCollection.Keystore;
var result = new OneBotLoginInfoResponse(keystore.Uin, keystore.Info?.Name ?? "");
return Task.FromResult(new OneBotResult(result, 0, "ok"));
}
}

View File

@@ -0,0 +1,18 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_status")]
public class GetStatusOperation : IOperation
{
public Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
return Task.FromResult(new OneBotResult(new OneBotGetStatusResponse
{
Memory = GC.GetTotalMemory(false)
}, 0, "ok"));
}
}

View File

@@ -0,0 +1,126 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.Core.Common.Entity;
using Lagrange.Core.Common.Interface.Api;
using Lagrange.OneBot.Core.Entity;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
using Lagrange.OneBot.Utility;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_stranger_info")]
public class GetStrangerInfoOperation : IOperation
{
private static readonly Dictionary<uint, string> _statusMessage = new()
{
{ 1, "在线" },
{ 3, "离开" },
{ 4, "隐身/离线" },
{ 5, "忙碌" },
{ 6, "Q我吧" },
{ 7, "请勿打扰" },
{ 263169, "听歌中" },
{ 15205121, "我的电量" },
{ 16713473, "做好事" },
{ 13829889, "出去浪" },
{ 14616321, "去旅行" },
{ 14550785, "被掏空" },
{ 14747393, "今日步数" },
{ 394241, "今日天气" },
{ 14878465, "我crush了" },
{ 14026497, "爱你" },
{ 1770497, "恋爱中" },
{ 3081217, "好运锦鲤" },
{ 11600897, "水逆退散" },
{ 2098177, "嗨到飞起" },
{ 2229249, "元气满满" },
{ 2556929, "一言难尽" },
{ 13698817, "难得糊涂" },
{ 7931137, "emo中" },
{ 2491393, "我太难了" },
{ 14485249, "我想开了" },
{ 1836033, "我没事" },
{ 2425857, "想静静" },
{ 2294785, "悠哉哉" },
{ 15926017, "信号弱" },
{ 16253697, "睡觉中" },
{ 14419713, "肝作业" },
{ 16384769, "学习中" },
{ 15140609, "搬砖中" },
{ 1312001, "摸鱼中" },
{ 2360321, "无聊中" },
{ 197633, "timi中" },
{ 15271681, "一起元梦" },
{ 15337217, "求星搭子" },
{ 525313, "熬夜中" },
{ 16581377, "追剧中" },
{ 13633281, "自定义状态"}
};
private static readonly Dictionary<uint, string> _BusinessName = new()
{
{ 113, "QQ大会员" },
{ 1, "QQ会员" },
{ 102, "黄钻" },
{ 117, "QQ集卡" },
{ 119, "情侣会员" },
{ 103, "绿钻" },
{ 4, "腾讯视频" },
{ 108, "大王超级会员" },
{ 104, "情侣个性钻" },
{ 105, "微云会员"},
{ 101, "红钻"},
{ 115, "cf游戏特权"},
{ 118, "蓝钻"},
{ 107, "SVIP+腾讯视频"}
};
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotGetStrangerInfo>(SerializerOptions.DefaultOptions) is { } stranger)
{
if (await context.FetchUserInfo(stranger.UserId, stranger.NoCache) is { } info)
{
return new OneBotResult(new OneBotStranger
{
UserId = info.Uin,
Avatar = info.Avatar,
QId = info.Qid,
NickName = info.Nickname,
Sex = info.Gender.ToOneBotString(),
Age = info.Age,
Level = info.Level,
Sign = info.Sign ?? string.Empty,
Status = new()
{
StatusId = info.Status.StatusId,
FaceId = info.Status.FaceId,
Message = info.Status.StatusId != 13633281
? _statusMessage.GetValueOrDefault(info.Status.StatusId)
: info.Status.Msg
},
RegisterTime = info.RegisterTime,
Business = BusinessList(info.Business)
}, 0, "ok");
}
return new OneBotResult(null, -1, "failed");
}
throw new Exception();
}
private List<OneBotBusiness> BusinessList(List<BusinessCustom> businessCustomList)
{
return businessCustomList.Select(b => new OneBotBusiness
{
Type = b.Type,
Name = (b.IsPro == 1 ? "超级" : "") + (_BusinessName.GetValueOrDefault(b.Type) ?? "未知"),
Level = b.Level,
Icon = b.Icon,
IsPro = b.IsPro,
IsYear = b.IsYear
}).ToList();
}
}

View File

@@ -0,0 +1,18 @@
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Entity.Action.Response;
namespace Lagrange.OneBot.Core.Operation.Info;
[Operation("get_version_info")]
public class GetVersionInfoOperation : IOperation
{
public Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
var appInfo = context.ContextCollection.AppInfo;
string version = $"{appInfo.Os} | {appInfo.CurrentVersion}";
return Task.FromResult(new OneBotResult(new OneBotVersionInfoResponse(version), 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("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();
}
}

View File

@@ -0,0 +1,7 @@
namespace Lagrange.OneBot.Core.Operation;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class OperationAttribute(string api) : Attribute
{
public string Api => api;
}

View File

@@ -0,0 +1,80 @@
using System.Reflection;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Network;
using Lagrange.OneBot.Core.Notify;
using Lagrange.OneBot.Core.Operation.Message;
using Lagrange.OneBot.Message;
using LiteDB;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace Lagrange.OneBot.Core.Operation;
public sealed class OperationService
{
private readonly BotContext _bot;
private readonly ILogger _logger;
private readonly Dictionary<string, Type> _operations;
private readonly ServiceProvider _service;
public OperationService(BotContext bot, ILogger<OperationService> logger, LiteDatabase context, MessageService message)
{
_bot = bot;
_logger = logger;
_operations = new Dictionary<string, Type>();
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
var attributes = type.GetCustomAttributes<OperationAttribute>();
foreach (var attribute in attributes) _operations[attribute.Api] = type;
}
var service = new ServiceCollection();
service.AddSingleton(bot);
service.AddSingleton(context);
service.AddSingleton(logger);
service.AddSingleton(message);
service.AddSingleton<MessageCommon>();
service.AddSingleton<TicketService>();
service.AddLogging();
foreach (var (_, type) in _operations) service.AddScoped(type);
_service = service.BuildServiceProvider();
}
public async Task<OneBotResult?> HandleOperation(MsgRecvEventArgs e)
{
try
{
if (JsonSerializer.Deserialize<OneBotAction>(e.Data) is { } action)
{
try
{
if (_operations.TryGetValue(action.Action, out var type))
{
var handler = (IOperation)_service.GetRequiredService(type);
var result = await handler.HandleOperation(_bot, action.Params);
result.Echo = action.Echo;
return result;
}
return new OneBotResult(null, 404, "failed") { Echo = action.Echo };
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Unexpected error encountered while handling message.");
return new OneBotResult(null, 200, "failed") { Echo = action.Echo };
}
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Json Serialization failed for such action");
}
return null;
}
}

View File

@@ -0,0 +1,22 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Request;
[Operation("set_friend_add_request")]
public class SetFriendAddRequestOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSetRequest>(SerializerOptions.DefaultOptions) is { } request)
{
bool result = await context.ContextCollection.Business.OperationLogic.SetFriendRequest(request.Flag, request.Approve);
return new OneBotResult(null, result ? 0 : 1, "ok");
}
throw new Exception();
}
}

View File

@@ -0,0 +1,32 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Lagrange.Core;
using Lagrange.OneBot.Core.Entity.Action;
using Lagrange.OneBot.Core.Operation.Converters;
namespace Lagrange.OneBot.Core.Operation.Request;
[Operation("set_group_add_request")]
public class SetGroupAddRequestOperation : IOperation
{
public async Task<OneBotResult> HandleOperation(BotContext context, JsonNode? payload)
{
if (payload.Deserialize<OneBotSetRequest>(SerializerOptions.DefaultOptions) is { } request)
{
string[] split = request.Flag.Split('-');
ulong sequence = ulong.Parse(split[0]);
uint groupUin = uint.Parse(split[1]);
uint eventType = uint.Parse(split[2]);
bool isFiltered = Convert.ToBoolean(uint.Parse(split.Length > 3 ? split[3] : "0"));
bool result = isFiltered
? await context.ContextCollection.Business.OperationLogic.SetGroupFilteredRequest(groupUin, sequence,
eventType, request.Approve, request.Reason)
: await context.ContextCollection.Business.OperationLogic.SetGroupRequest(groupUin, sequence, eventType,
request.Approve, request.Reason);
return new OneBotResult(null, result ? 0 : 1, "ok");
}
throw new Exception();
}
}