diff --git a/HeyBoxChatBotCs.Api/Features/Bot/Bot.cs b/HeyBoxChatBotCs.Api/Features/Bot/Bot.cs index 051f2b4..a6b88a4 100644 --- a/HeyBoxChatBotCs.Api/Features/Bot/Bot.cs +++ b/HeyBoxChatBotCs.Api/Features/Bot/Bot.cs @@ -1,3 +1,4 @@ +using System.Text.Encodings.Web; using System.Text.Json; using HeyBoxChatBotCs.Api.Commands.CommandSystem; using HeyBoxChatBotCs.Api.Enums; @@ -8,6 +9,11 @@ namespace HeyBoxChatBotCs.Api.Features.Bot; public class Bot { + public static readonly JsonSerializerOptions BotActionJsonSerializerOptions = new() + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + public static Bot? Instance { get; private set; } public Bot(string id, string token) @@ -68,10 +74,11 @@ public void Close() IsRunning = false; BotWebSocket?.Dispose(); Log.Info("已关闭Bot,即将退出程序!"); - Misc.Misc.Exit(0); + Misc.Misc.Exit(); } - protected async Task BotSendAction(object body, BotAction action) + protected async Task?> BotSendAction(object body, BotAction action, + string contentType = "application/json") { if (!BotRequestUrl.TryGetUri(action, out Uri? uri)) { @@ -79,11 +86,12 @@ public void Close() return default; } - Log.Debug("BOT动作的JSON为:" + body); - return await HttpRequest.Post(uri!, JsonSerializer.Serialize(body), new Dictionary() + string json = JsonSerializer.Serialize(body, BotActionJsonSerializerOptions); + Log.Debug("BOT动作的JSON为:" + json); + return await HttpRequest.Post(uri!, json, new Dictionary { { "token", Token } - }); + }, contentType: contentType); } public async void SendMessage(MessageBase message) @@ -96,14 +104,22 @@ public async void SendMessage(MessageBase message) try { - SendMessageResult? result = await BotSendAction(message, BotAction.SendMessage); - if (result is null) + HttpResponseMessageValue? result = + await BotSendAction(message, BotAction.SendMessage); + if (result?.Value is null) { Log.Error("发送信息后返回的数据为空!"); return; } - Log.Debug($"发送信息 \"{result.Message}\" 成功,状态:{result.Status}."); + if (!result.Response.IsSuccessStatusCode) + { + Log.Error($"发送信息失败,返回信息:{result.Value.Message}!"); + } + else + { + Log.Debug($"发送信息返回,信息:\"{result.Value.Message}\",状态:{result.Value.Status}."); + } } catch (Exception exception) { diff --git a/HeyBoxChatBotCs.Api/Features/Message/ImageMessage.cs b/HeyBoxChatBotCs.Api/Features/Message/ImageMessage.cs new file mode 100644 index 0000000..4496b7f --- /dev/null +++ b/HeyBoxChatBotCs.Api/Features/Message/ImageMessage.cs @@ -0,0 +1,29 @@ +using System.Net.Mime; +using System.Text.Json.Serialization; +using HeyBoxChatBotCs.Api.Enums; + +namespace HeyBoxChatBotCs.Api.Features.Message; + +public class ImageMessage : MessageBase +{ + public ImageMessage(string image, string channelId, string roomId, string replyMessageId = "", string? ackId = null) + : this(new Uri(image), + channelId, roomId, replyMessageId, ackId) + { + } + + public ImageMessage(Uri image, Channel channelId, Room roomId, string replyMessageId = "", string? ackId = null) : + this(image, + channelId.Id, roomId.Id, replyMessageId, ackId) + { + } + + public ImageMessage(Uri image, string channelId, string roomId, string replyMessageId = "", + string? ackId = null) : base( + ackId ?? MessageAck.GetAckId(), MessageType.Image, channelId, roomId, replyMessageId) + { + Uri = image; + } + + [JsonPropertyName("img")] public Uri Uri { get; init; } +} \ No newline at end of file diff --git a/HeyBoxChatBotCs.Api/Features/Message/MarkdownMessage.cs b/HeyBoxChatBotCs.Api/Features/Message/MarkdownMessage.cs index b2f44c6..9060f66 100644 --- a/HeyBoxChatBotCs.Api/Features/Message/MarkdownMessage.cs +++ b/HeyBoxChatBotCs.Api/Features/Message/MarkdownMessage.cs @@ -8,7 +8,7 @@ public class MarkdownMessage : MessageBase { public MarkdownMessage(string message, Room room, Channel channel, string replyMessageId = "", User[]? atUser = null, - string[]? atRole = null, Channel[]? mentionChannel = null, MarkdownMessageAddition? addition = null, + string[]? atRole = null, Channel[]? mentionChannel = null, MessageAddition? addition = null, string? ackId = null) : this( message, room.Id, channel.Id, replyMessageId, atUser?.Select(x => x.UserId.ToString()).ToArray(), atRole, @@ -18,54 +18,21 @@ public MarkdownMessage(string message, Room room, Channel channel, string replyM public MarkdownMessage(string message, string roomId, string channelId, string replyMessageId = "", string[]? atUser = null, - string[]? atRole = null, string[]? mentionChannelId = null, MarkdownMessageAddition? addition = null, + string[]? atRole = null, string[]? mentionChannelId = null, MessageAddition? addition = null, string? ackId = null) : base( ackId ?? MessageAck.GetAckId(), - MessageType.MarkdownPing, channelId, roomId) + MessageType.MarkdownPing, channelId, roomId, replyMessageId, addition) { Message = message; - ReplyMessageId = replyMessageId; AtUserId = string.Join(',', atUser ?? []); AtRoleId = string.Join(',', atRole ?? []); MentionChannelId = string.Join(',', mentionChannelId ?? []); - Addition = JsonSerializer.Serialize(addition ?? new MarkdownMessageAddition()); } [JsonPropertyName("msg")] public string Message { get; init; } - [JsonPropertyName("reply_id")] public string ReplyMessageId { get; init; } [JsonPropertyName("at_user_id")] public string AtUserId { get; init; } [JsonPropertyName("at_role_id")] public string AtRoleId { get; init; } [JsonPropertyName("mention_channel_id")] public string MentionChannelId { get; init; } - - [JsonPropertyName("addition")] public string Addition { get; init; } -} - -public class MarkdownMessageAddition -{ - public MarkdownMessageAddition(MarkdownMessageAdditionImage[]? additionImages = null) - { - ImageFilesInfo = additionImages ?? []; - } - - [JsonPropertyName("img_files_info")] public MarkdownMessageAdditionImage[] ImageFilesInfo { get; init; } - - public class MarkdownMessageAdditionImage - { - public MarkdownMessageAdditionImage(string uri, int width, int height) : this(new Uri(uri), width, height) - { - } - - public MarkdownMessageAdditionImage(Uri uri, int width, int height) - { - Uri = uri; - Width = width; - Height = height; - } - - [JsonPropertyName("uri")] public Uri Uri { get; init; } - [JsonPropertyName("width")] public int Width { get; init; } - [JsonPropertyName("height")] public int Height { get; init; } - } } \ No newline at end of file diff --git a/HeyBoxChatBotCs.Api/Features/Message/MessageBase.cs b/HeyBoxChatBotCs.Api/Features/Message/MessageBase.cs index 178a88c..1796831 100644 --- a/HeyBoxChatBotCs.Api/Features/Message/MessageBase.cs +++ b/HeyBoxChatBotCs.Api/Features/Message/MessageBase.cs @@ -1,20 +1,60 @@ -using System.Text.Json.Serialization; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; using HeyBoxChatBotCs.Api.Enums; namespace HeyBoxChatBotCs.Api.Features.Message; +[JsonDerivedType(typeof(MarkdownMessage))] +[JsonDerivedType(typeof(ImageMessage))] public abstract class MessageBase { - protected MessageBase(string ackId, MessageType type, string channelId, string roomId) + protected MessageBase(string ackId, MessageType type, string channelId, string roomId, string replyMessageId = "", + MessageAddition? addition = null) { + ReplyMessageId = replyMessageId; AckId = ackId; Type = type; ChannelId = channelId; RoomId = roomId; + Addition = JsonSerializer.Serialize(addition ?? new MessageAddition(), Bot.Bot.BotActionJsonSerializerOptions); } + + [JsonPropertyName("reply_id")] public string ReplyMessageId { get; init; } [JsonPropertyName("heychat_ack_id")] public string AckId { get; init; } [JsonPropertyName("msg_type")] public MessageType Type { get; init; } [JsonPropertyName("channel_id")] public string ChannelId { get; init; } [JsonPropertyName("room_id")] public string RoomId { get; init; } + + [JsonPropertyName("addition")] public string Addition { get; init; } +} + +public class MessageAddition +{ + public MessageAddition(MessageAdditionImage[]? additionImages = null) + { + ImageFilesInfo = additionImages ?? []; + } + + [JsonPropertyName("img_files_info")] public MessageAdditionImage[] ImageFilesInfo { get; init; } +} + +public class MessageAdditionImage +{ + public MessageAdditionImage(string uri, int width, int height) : this(new Uri(uri), width, + height) + { + } + + public MessageAdditionImage(Uri uri, int width, int height) + { + Uri = uri; + Width = width; + Height = height; + } + + [JsonPropertyName("uri")] public Uri Uri { get; init; } + [JsonPropertyName("width")] public int Width { get; init; } + [JsonPropertyName("height")] public int Height { get; init; } } \ No newline at end of file diff --git a/HeyBoxChatBotCs.Api/Features/Network/HttpRequest.cs b/HeyBoxChatBotCs.Api/Features/Network/HttpRequest.cs index e8f794b..5d034ea 100644 --- a/HeyBoxChatBotCs.Api/Features/Network/HttpRequest.cs +++ b/HeyBoxChatBotCs.Api/Features/Network/HttpRequest.cs @@ -7,48 +7,62 @@ namespace HeyBoxChatBotCs.Api.Features.Network; public delegate void SendingNetworkRequest(); -public class HttpRequest +public static class HttpRequest { public static JsonSerializerOptions HttpRequestJsonSerializerOptions { get; } = JsonSerializerOptions.Default; public static event SendingNetworkRequest? OnSendingNetworkRequest; - public static async Task Get(Uri uri, Type type, IReadOnlyDictionary? headers = null + public static async Task Get(Uri uri, Type type, + Dictionary? headers = null ) { - return JsonSerializer.Deserialize(await Get(uri, headers), type); + HttpResponseMessageValue ret = await Get(uri, headers); + return new HttpResponseMessageValue(ret.Response, + ret.Value is null ? default : JsonSerializer.Deserialize(ret.Value, type)); } - public static async Task Get(Uri uri, IReadOnlyDictionary? headers = null) + public static async Task> Get(Uri uri, Dictionary? headers = null) { - return JsonSerializer.Deserialize(await Get(uri, headers)); + HttpResponseMessageValue ret = await Get(uri, headers); + return new HttpResponseMessageValue(ret.Response, + ret.Value is null ? default : JsonSerializer.Deserialize(ret.Value)); } - public static async Task Get(Uri uri, IReadOnlyDictionary? headers = null) + public static async Task> Get(Uri uri, Dictionary? headers = null) { - return await GetResponseMessageAsync(uri, headers).Result.Content.ReadAsStringAsync(); + var ret = await GetResponseMessageAsync(uri, headers); + return new HttpResponseMessageValue(ret, await ret.Content.ReadAsStringAsync()); } - public static async Task Get(string uri, Type type, IReadOnlyDictionary? headers = null, + public static async Task Get(string uri, Type type, + Dictionary? headers = null, string? path = null, NameValueCollection? query = null ) { - return JsonSerializer.Deserialize(await Get(uri, headers, path, query), type); + HttpResponseMessageValue ret = await Get(uri, headers, path, query); + return new HttpResponseMessageValue(ret.Response, + ret.Value is null ? default : JsonSerializer.Deserialize(ret.Value, type)); } - public static async Task Get(string uri, IReadOnlyDictionary? headers = null, + public static async Task> Get(string uri, + Dictionary? headers = null, string? path = null, NameValueCollection? query = null) { - return JsonSerializer.Deserialize(await Get(uri, headers, path, query)); + HttpResponseMessageValue ret = await Get(uri, headers, path, query); + return new HttpResponseMessageValue(ret.Response, + ret.Value is null ? default : JsonSerializer.Deserialize(ret.Value)); } - public static async Task Get(string uri, IReadOnlyDictionary? headers = null, + public static async Task> Get(string uri, + Dictionary? headers = null, string? path = null, NameValueCollection? query = null) { - return await GetResponseMessageAsync(uri, headers, path, query).Result.Content.ReadAsStringAsync(); + var ret = await GetResponseMessageAsync(uri, headers, path, query); + return new HttpResponseMessageValue(ret, await ret.Content.ReadAsStringAsync()); } internal static async Task GetResponseMessageAsync(Uri uri, - IReadOnlyDictionary? headers) + Dictionary? headers) { using HttpClient httpClient = new HttpClient(); if (headers is not null) @@ -64,7 +78,7 @@ internal static async Task GetResponseMessageAsync(Uri uri, } internal static async Task GetResponseMessageAsync(string uri, - IReadOnlyDictionary? headers, string? path, NameValueCollection? query) + Dictionary? headers, string? path, NameValueCollection? query) { using HttpClient httpClient = new HttpClient(); if (headers is not null) @@ -80,49 +94,56 @@ internal static async Task GetResponseMessageAsync(string u } - public static async Task Post(Uri uri, string body, Type type, + public static async Task Post(Uri uri, string body, Type type, Dictionary? headers = null, string contentType = "application/json", Encoding? encoding = null) { - return JsonSerializer.Deserialize(await Post(uri, body, headers, contentType, encoding), type); + HttpResponseMessageValue ret = await Post(uri, body, headers, contentType, encoding); + return new HttpResponseMessageValue(ret.Response, + ret.Value is null ? default : JsonSerializer.Deserialize(ret.Value, type)); } - public static async Task Post(Uri uri, string body, + public static async Task> Post(Uri uri, string body, Dictionary? headers = null, string contentType = "application/json", Encoding? encoding = null) { - return JsonSerializer.Deserialize(await Post(uri, body, headers, contentType, encoding)); + HttpResponseMessageValue ret = await Post(uri, body, headers, contentType, encoding); + return new HttpResponseMessageValue(ret.Response, + ret.Value is null ? default : JsonSerializer.Deserialize(ret.Value)); } - public static async Task Post(Uri uri, string body, + public static async Task> Post(Uri uri, string body, Dictionary? headers = null, string contentType = "application/json", Encoding? encoding = null) { - return await PostResponseMessageAsync(uri, body, headers, contentType, encoding).Result - .Content - .ReadAsStringAsync(); + HttpResponseMessage ret = await PostResponseMessageAsync(uri, body, headers, contentType, encoding); + return new HttpResponseMessageValue(ret, await ret.Content.ReadAsStringAsync()); } - public static async Task Post(string uri, IReadOnlyDictionary body, Type type, - IReadOnlyDictionary? headers = null, string? path = null, NameValueCollection? query = null, + public static async Task Post(string uri, Dictionary body, Type type, + Dictionary? headers = null, string? path = null, NameValueCollection? query = null, string contentType = "application/json", Encoding? encoding = null) { - return JsonSerializer.Deserialize(await Post(uri, body, headers, path, query, contentType, encoding), type); + HttpResponseMessageValue ret = await Post(uri, body, headers, path, query, contentType, encoding); + return new HttpResponseMessageValue(ret.Response, + ret.Value is null ? default : JsonSerializer.Deserialize(ret.Value, type)); } - public static async Task Post(string uri, IReadOnlyDictionary body, - IReadOnlyDictionary? headers = null, string? path = null, NameValueCollection? query = null, + public static async Task> Post(string uri, Dictionary body, + Dictionary? headers = null, string? path = null, NameValueCollection? query = null, string contentType = "application/json", Encoding? encoding = null) { - return JsonSerializer.Deserialize(await Post(uri, body, headers, path, query, contentType, encoding)); + HttpResponseMessageValue ret = await Post(uri, body, headers, path, query, contentType, encoding); + return new HttpResponseMessageValue(ret.Response, + ret.Value is null ? default : JsonSerializer.Deserialize(ret.Value)); } - public static async Task Post(string uri, IReadOnlyDictionary body, - IReadOnlyDictionary? headers = null, string? path = null, NameValueCollection? query = null, + public static async Task> Post(string uri, Dictionary body, + Dictionary? headers = null, string? path = null, NameValueCollection? query = null, string contentType = "application/json", Encoding? encoding = null) { - return await PostResponseMessageAsync(uri, body, headers, path, query, contentType, encoding).Result.Content - .ReadAsStringAsync(); + var ret = await PostResponseMessageAsync(uri, body, headers, path, query, contentType, encoding); + return new HttpResponseMessageValue(ret, await ret.Content.ReadAsStringAsync()); } internal static async Task PostResponseMessageAsync(Uri uri, @@ -146,7 +167,7 @@ internal static async Task PostResponseMessageAsync(Uri uri } internal static async Task PostResponseMessageAsync(string uri, - IReadOnlyDictionary body, IReadOnlyDictionary? headers, string? path, + Dictionary body, Dictionary? headers, string? path, NameValueCollection? query, string contentType, Encoding? encoding) { @@ -165,4 +186,28 @@ internal static async Task PostResponseMessageAsync(string encoding ?? Encoding.UTF8, contentType); return await httpClient.PostAsync(HttpMisc.ConstructUrl(uri, path, query), stringContent); } +} + +public class HttpResponseMessageValue +{ + public HttpResponseMessageValue(HttpResponseMessage response, object? value) + { + Response = response; + Value = value; + } + + public HttpResponseMessage Response { get; init; } + public object? Value { get; init; } +} + +public class HttpResponseMessageValue +{ + public HttpResponseMessageValue(HttpResponseMessage response, TValue value) + { + Response = response; + Value = value; + } + + public HttpResponseMessage Response { get; init; } + public TValue Value { get; init; } } \ No newline at end of file