diff --git a/Mirai.Net/Data/Messages/Concretes/ForwardMessage.cs b/Mirai.Net/Data/Messages/Concretes/ForwardMessage.cs index 709956f..04587e0 100644 --- a/Mirai.Net/Data/Messages/Concretes/ForwardMessage.cs +++ b/Mirai.Net/Data/Messages/Concretes/ForwardMessage.cs @@ -19,7 +19,7 @@ public record ForwardMessage : MessageBase /// 点进消息前的显示内容 /// [JsonProperty("display")] - public ForwardDisplay Display { get; set; } = default; + public ForwardDisplay Display { get; set; } /// /// 消息节点 @@ -92,6 +92,27 @@ public record ForwardNode /// public record ForwardDisplay { + /// + /// 生成转发消息的外层显示 + /// + /// + /// + /// + /// + /// + public ForwardDisplay(string title = default, string brief = default, string source = default, IEnumerable preview = default, string summary = default) + { + this.Title = title; + + this.Brief = brief; + + this.Source = source; + + this.Preview = preview; + + this.Summary = summary; + } + /// /// 标题 /// @@ -121,6 +142,5 @@ public record ForwardDisplay /// [JsonProperty("summary")] public string Summary { get; set; } - } } \ No newline at end of file diff --git a/Mirai.Net/Data/Messages/Concretes/MusicShareMessage.cs b/Mirai.Net/Data/Messages/Concretes/MusicShareMessage.cs index 383af24..01af217 100644 --- a/Mirai.Net/Data/Messages/Concretes/MusicShareMessage.cs +++ b/Mirai.Net/Data/Messages/Concretes/MusicShareMessage.cs @@ -13,7 +13,7 @@ public record MusicShareMessage : MessageBase public override Messages Type { get; set; } = Messages.MusicShare; /// - /// 类型 + /// 类型,即分享自的软件平台 /// [JsonProperty("kind")] public string Kind { get; set; } diff --git a/Mirai.Net/Data/Messages/Concretes/PokeMessage.cs b/Mirai.Net/Data/Messages/Concretes/PokeMessage.cs index a4e682d..b6221d4 100644 --- a/Mirai.Net/Data/Messages/Concretes/PokeMessage.cs +++ b/Mirai.Net/Data/Messages/Concretes/PokeMessage.cs @@ -3,7 +3,7 @@ namespace Mirai.Net.Data.Messages.Concretes; /// -/// 我也不知道是啥玩意 +/// 戳一戳系列消息 /// public record PokeMessage : MessageBase { diff --git a/Mirai.Net/Data/Messages/MessageBase.cs b/Mirai.Net/Data/Messages/MessageBase.cs index 1316e6f..55c91aa 100644 --- a/Mirai.Net/Data/Messages/MessageBase.cs +++ b/Mirai.Net/Data/Messages/MessageBase.cs @@ -45,7 +45,7 @@ public string SerializeToMiraiCode() case ImageMessage msg: if (string.IsNullOrEmpty(msg.ImageId)) - throw new("ImageId为空!"); + throw new System.ArgumentNullException("ImageId为空!"); else return $"[mirai:image:{msg.ImageId}]"; @@ -61,7 +61,7 @@ public string SerializeToMiraiCode() case FaceMessage msg: if (string.IsNullOrEmpty(msg.FaceId)) - throw new("FaceId为空!"); + throw new System.ArgumentNullException("FaceId为空!"); else return $"[mirai:face:{msg.FaceId}]"; @@ -82,7 +82,7 @@ public string SerializeToMiraiCode() "FangDaZhao" => "放大招,6,-1", - _ => throw new("该Poke消息还未支持!") + _ => throw new System.NotSupportedException("该Poke消息还未支持!") }; return $"[mirai:poke:{poke}]"; @@ -91,7 +91,7 @@ public string SerializeToMiraiCode() return $"[mirai:dice:{msg.Value}]"; - case MusicShareMessage msg: // MusicShare在mirai的2.15.0-M1版本中显示为[mirai:origin:MUSIC_SHARE]MusicShare(*这里有一长串省略的内容) 与https://github.com/mamoe/mirai/blob/dev/docs/Messages.md中所说的[mirai:musicshare:$args]不符 因此这里先采用后者的方式 使用半角逗号分隔 至少保证序列化的稳定 + case MusicShareMessage msg: // MusicShare在mirai的2.15.0-M1版本中显示为[mirai:origin:MUSIC_SHARE]MusicShare(*这里有一长串省略的内容) 与https://github.com/mamoe/mirai/blob/dev/docs/Messages.md 中所说的[mirai:musicshare:$args]不符 因此这里先采用后者的方式 使用半角逗号分隔 至少保证序列化的稳定 return $"[mirai:musicshare:{msg.Kind},{msg.Title},{msg.Summary},{msg.JumpUrl},{msg.PictureUrl},{msg.MusicUrl},{msg.Brief}]"; @@ -101,7 +101,7 @@ public string SerializeToMiraiCode() default: - throw new("遇到了不支持序列化的消息!"); + throw new System.NotSupportedException("遇到了不支持序列化的消息!"); } } diff --git a/Mirai.Net/Mirai.Net.csproj b/Mirai.Net/Mirai.Net.csproj index 5e2b176..9b39fbe 100644 --- a/Mirai.Net/Mirai.Net.csproj +++ b/Mirai.Net/Mirai.Net.csproj @@ -3,7 +3,7 @@ latest true - 2.4.9 + 2.5.0 Mirai.Net latest 基于mirai-api-http的轻量级mirai社区sdk diff --git a/Mirai.Net/Sessions/Http/Managers/ConsoleManager.cs b/Mirai.Net/Sessions/Http/Managers/ConsoleManager.cs index cd07794..e893309 100644 --- a/Mirai.Net/Sessions/Http/Managers/ConsoleManager.cs +++ b/Mirai.Net/Sessions/Http/Managers/ConsoleManager.cs @@ -1,12 +1,14 @@ using Manganese.Array; using Mirai.Net.Data.Events; using Mirai.Net.Data.Messages; +using Mirai.Net.Data.Messages.Concretes; using Mirai.Net.Data.Sessions; using Mirai.Net.Utils.Internal; using Newtonsoft.Json; using System.Collections.Generic; using System.Reactive; using System.Threading.Tasks; +using System.Linq; namespace Mirai.Net.Sessions.Http.Managers { @@ -14,42 +16,113 @@ namespace Mirai.Net.Sessions.Http.Managers /// /// 控制台管理器 /// - /// 在功能稳定前保持可见性为 internal - [Experimental] -#if DEBUG public static class ConsoleManager -#else - internal static class ConsoleManager -#endif { +#nullable enable + /// + /// 登录指令 + /// 登录后的账号会生成新的SessionKey 使用已有的MiraiBot实例是无法连接到该账号的 + /// 如果配置相同(QQ Address VerifyKey)可以再次在同一个MiraiBot上使用LaunchAsync方法之后就可以正常使用了 + /// 在LaunchAsync之前使用的任何Subscribe方法都不会应用于新登录的账号 必须重新Subscribe + /// + /// + /// + /// + /// + public static async Task LoginAsync(string qq, string password, Protocol? protocol = null) + { + var command = protocol is null + ? new PlainMessage[] { $"/login {qq} {password}" } + : new PlainMessage[] { $"/login {qq} {password} {protocol.ToString()}" }; + + await HttpEndpoints.ExecuteCommand.PostJsonAsync(new + { + command + }); + } +#nullable restore /// - /// 内部小把戏 + /// 关闭指令 /// - /// 在功能稳定前使用此方法加入内部事件类型 - static ConsoleManager() + /// + public static async Task StopAsync() { - var field = typeof(ReflectionUtils).GetField("EventBases", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); - if (field != null) + var command = new PlainMessage[] { "/stop" }; + + await HttpEndpoints.ExecuteCommand.PostJsonAsync(new { - if (field.GetValue(null) == null) - { - field.SetValue(null, ReflectionUtils.GetDefaultInstances("Mirai.Net.Data.Events.Concretes")); - } - var eventBases = field.GetValue(null); - ((IEnumerable)eventBases).Add(new EventBase[] { new CommandExecutedEvent() }); - } + command + }); + } + + /// + /// 登出指令 + /// + /// + /// + public static async Task LogoutAsync(string qq) + { + var command = new PlainMessage[] { $"/logout {qq}" }; + + await HttpEndpoints.ExecuteCommand.PostJsonAsync(new + { + command + }); } /// /// 执行命令 /// - /// + /// /// 命令与参数 + /// + /// + public static async Task ExecuteCommandAsync(string commands) + { + var command = new PlainMessage[] { commands }; + + await HttpEndpoints.ExecuteCommand.PostJsonAsync(new + { + command + }); + } + + /// + /// 执行命令 + /// + /// + /// 命令与参数 + /// + /// + public static async Task ExecuteCommandAsync(params string[] commands) + { + var builder = new System.Text.StringBuilder(); + + foreach (var item in commands) + { + builder.Append(item); + + builder.Append(' '); + } + + var command = new PlainMessage[] { builder.ToString().Trim() }; + + await HttpEndpoints.ExecuteCommand.PostJsonAsync(new + { + command + }); + } + + /// + /// 使用消息执行命令 + /// + /// + /// 命令与参数 如果使用纯文本的话需要将整条命令写在同一个PlainMessage中 /// 控制台支持以不同消息类型作为指令的参数, 执行命令需要以消息类型作为参数, 若执行纯文本的命令, 构建多个文本格式的消息控制台会将第一个消息作为指令名, 后续消息作为参数 /// /// - public static async Task ExecuteCommandAsync(MessageBase[] command) + public static async Task ExecuteMessageCommandAsync(IEnumerable command) { await HttpEndpoints.ExecuteCommand.PostJsonAsync(new { @@ -87,9 +160,8 @@ public static async Task RegisterCommandAsync(Command command) } /// - /// 命令 + /// 注册用的命令 /// - /// 在功能稳定前保持此类为内部类 public record Command { @@ -103,7 +175,7 @@ public record Command /// 指令别名 /// [JsonProperty("alias")] - public string[] Alias { get; set; } + public IEnumerable Alias { get; set; } /// /// 使用说明 @@ -121,7 +193,6 @@ public record Command /// /// 命令被执行 /// - /// 在功能稳定前保持此类为内部类 public record CommandExecutedEvent : EventBase { /// @@ -132,23 +203,44 @@ public record CommandExecutedEvent : EventBase /// /// 命令名称 /// - [JsonProperty("name")] public string Name { get; private set; } - + [JsonProperty("name")] public string Name { get; set; } +#nullable enable /// /// 发送命令的好友, 从控制台发送为 null /// - [JsonProperty("friend")] public string FriendId { get; private set; } + [JsonProperty("friend")] public string? FriendId { get; set; } /// - /// 发送命令的群成员, 从控制台发送为 nul + /// 发送命令的群成员, 从控制台发送为 null /// - [JsonProperty("member")] public string MemberId { get; private set; } - + [JsonProperty("member")] public string? MemberId { get; set; } +#nullable restore /// /// 指令的参数, 以消息类型传递 /// - [JsonProperty("args")] public dynamic Args { get; private set; } + [JsonProperty("args")] public dynamic Args { get; set; } } } + + /// + /// 可选的登录协议 + /// + public enum Protocol + { + /// + /// 安卓手机 + /// + ANDROID_PHONE, + + /// + /// 安卓平板 + /// + ANDROID_PAD, + + /// + /// 安卓手表 + /// + ANDROID_WATCH + } } diff --git a/Mirai.Net/Utils/Scaffolds/MessageChain.cs b/Mirai.Net/Utils/Scaffolds/MessageChain.cs index 729685c..4928a78 100644 --- a/Mirai.Net/Utils/Scaffolds/MessageChain.cs +++ b/Mirai.Net/Utils/Scaffolds/MessageChain.cs @@ -30,6 +30,29 @@ public MessageChain() : base() { } + /// + /// 运行时安全的Mirai码 + /// + public string MiraiCode + { + get + { + System.Text.StringBuilder builder = new(); + + this.ForEach(x => + { + try + { + builder.Append(x.SerializeToMiraiCode()); + } + catch + {} + }); + + return builder.ToString(); + } + } + /// /// 获取消息链中的纯文本消息 /// @@ -46,16 +69,16 @@ public string GetPlainMessage() #nullable enable /// - /// 获取该消息的消息来源 如果没有引用则返回null + /// 获取该消息的消息来源 如果有多个来源返回最后一个 如果没有来源则返回null /// /// - public SourceMessage? GetSourceMessage() => this.OfType().FirstOrDefault(); + public SourceMessage? GetSourceMessage() => this.OfType().LastOrDefault(); /// - /// 获取该消息的消息来源 如果没有引用则返回null + /// 获取该消息的消息引用 如果有多个引用返回最后一个 如果没有引用则返回null /// /// - public QuoteMessage? GetQuoteMessage() => this.OfType().FirstOrDefault(); + public QuoteMessage? GetQuoteMessage() => this.OfType().LastOrDefault(); #nullable disable @@ -103,7 +126,7 @@ public async Task SendToAsync(TempMessageReceiver receiver) } /// - /// 将该消息链序列化为mirai码 + /// 将该消息链序列化为mirai码 不会捕获异常 /// /// public string SerializeToMiraiCode() @@ -169,27 +192,27 @@ public string SerializeToMiraiCode() /// public static bool operator ==(MessageChain left, MessageChain right) { - if (left.Count != right.Count) return false; + left = left.Where(x => x is not SourceMessage).ToMessageChain(); - if ((left.OfType().FirstOrDefault()?.Code ?? left.SerializeToMiraiCode()) == (right.OfType().FirstOrDefault()?.Code ?? right.SerializeToMiraiCode())) - return true; + right = right.Where(x => x is not SourceMessage).ToMessageChain(); + + if (left.Count != right.Count) return false; for (int i = 0; i < left.Count; i++) { if (left[i].Type != right[i].Type) return false; - if (left[i].Type == Messages.Source || right[i].Type == Messages.Source) - continue; - // 这段代码用了一种极其诡异的方法判断是否相等 - // 首先检查能否转换为图片消息然后挨个判断四个属性 都不相等就返回false 有一个相等就返回true + // 首先检查能否转换为图片消息或者语音消息然后挨个判断四个属性 都不相等就返回false 有一个相等就返回true // 然后看不能转换的时候利用record直接判左右相等 // 最后把前面所有的一切套进if里顺便加反转 如果为true什么都不做 如果为false直接返回false if (!((left[i], right[i]) switch { - (ImageMessage leftmsg, ImageMessage rightmsg) => (leftmsg.ImageId != rightmsg.ImageId && leftmsg.Url != rightmsg.Url && leftmsg.Path != rightmsg.Path && leftmsg.Base64 != rightmsg.Base64) ? false : true, + (ImageMessage leftmsg, ImageMessage rightmsg) => !(leftmsg.ImageId != rightmsg.ImageId && leftmsg.Url != rightmsg.Url && leftmsg.Path != rightmsg.Path && leftmsg.Base64 != rightmsg.Base64), + + (VoiceMessage leftmsg, VoiceMessage rightmsg) => !(leftmsg.VoiceId != rightmsg.VoiceId && leftmsg.Url != rightmsg.Url && leftmsg.Path != rightmsg.Path && leftmsg.Base64 != rightmsg.Base64), - (var leftmsg, var rightmsg) => leftmsg == rightmsg ? true : false + (var leftmsg, var rightmsg) => leftmsg == rightmsg })) return false; } @@ -203,7 +226,7 @@ public string SerializeToMiraiCode() /// /// /// - public static bool operator !=(MessageChain left, MessageChain right) => left == right ? false : true; + public static bool operator !=(MessageChain left, MessageChain right) => !(left == right); /// /// diff --git a/README.md b/README.md index 7cb42dd..373ca61 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Mirai.Net 2.4.8 +# Mirai.Net 2.5.0 Mirai.NET 是基于 [mirai-api-http] 实现的 C# 版轻量级 [mirai] 社区 SDK。