diff --git a/.gitignore b/.gitignore index d36957e..12e22ad 100644 --- a/.gitignore +++ b/.gitignore @@ -340,4 +340,5 @@ ASALocalRun/ healthchecksdb DevIcon.* Test -nuget.config \ No newline at end of file +nuget.config +*.cd \ No newline at end of file diff --git a/AuroraNative/API/Api.cs b/AuroraNative/API/Api.cs index 6f57e84..7542b9c 100644 --- a/AuroraNative/API/Api.cs +++ b/AuroraNative/API/Api.cs @@ -1,7 +1,11 @@ using AuroraNative.EventArgs; +using AuroraNative.Exceptions; using AuroraNative.WebSockets; +using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -10,7 +14,7 @@ namespace AuroraNative /// /// API 类 /// - public class Api + public sealed class Api { #region --变量-- @@ -18,20 +22,37 @@ public class Api /// 任务队列 /// internal static JObject TaskList = new JObject(); + internal static MemoryCache Cache = new MemoryCache(new MemoryCacheOptions()); private readonly BaseWebSocket WebSocket; #endregion + #region --属性-- + + /// + /// 获取API实例 + /// + public static Api CurrentApi => (Api)Cache.Get($"API{AppDomain.CurrentDomain.Id}"); + + #endregion + #region --构造函数-- /// /// 构建函数 /// /// WebSocket句柄 - public Api(BaseWebSocket WebSocket) + private Api(BaseWebSocket WebSocket) { - this.WebSocket = WebSocket; + if (WebSocket != null) + { + this.WebSocket = WebSocket; + } + else + { + throw new WebSocketException(-1, "传入的WebSocket不可为空"); + } } #endregion @@ -41,15 +62,15 @@ public Api(BaseWebSocket WebSocket) /// /// 发送私聊消息 /// - /// 接受者QQ号 + /// 接受者QQ号 /// 信息内容 /// 是否转义默认:false /// 返回消息ID,错误返回-1 - public async Task SendPrivateMessage(long QID, string Message, bool AutoEscape = false) + public async Task SendPrivateMessage(long UserID, string Message, bool AutoEscape = false) { JObject Params = new JObject { - { "user_id", QID }, + { "user_id", UserID }, { "message", Message }, { "auto_escape", AutoEscape } }; @@ -89,7 +110,7 @@ public void SendGroupForwardMessage(long GroupID, JArray Message) { "group_id", GroupID }, { "messages", Message } }; - + //TODO 需要做CQ码转换 SendCallVoid(new BaseAPI("send_group_forward_msg", Params, "SendGroupForwardMessage:" + Utils.NowTimeSteamp())); } @@ -98,11 +119,11 @@ public void SendGroupForwardMessage(long GroupID, JArray Message) /// /// 信息内容 /// 信息类型私聊:private群聊:group - /// QQ号 + /// QQ号 /// 群号 /// 是否转义默认:false /// 错误返回-1,成功返回信息ID - public async Task SendMsg(string Message, string MessageType = null, long QID = 0, long GroupID = 0, bool AutoEscape = false) + public async Task SendMsg(string Message, string MessageType = null, long UserID = 0, long GroupID = 0, bool AutoEscape = false) { JObject Params = new JObject() { { "message", Message}, @@ -112,21 +133,23 @@ public async Task SendMsg(string Message, string MessageType = null, lon switch (MessageType) { case "private": - Params.Add("user_id", QID); + Params.Add("user_id", UserID); break; case "group": Params.Add("group_id", GroupID); break; - default: - if (QID != 0) + case null: + if (UserID != 0) { - Params.Add("user_id", QID); + Params.Add("user_id", UserID); } else if (GroupID != 0) { Params.Add("group_id", GroupID); } break; + default: + throw new Exceptions.JsonException(-1, "传入的参数不符合预期"); } return await SendCallMessageID(new BaseAPI("send_msg", Params, "SendMsg:" + Utils.NowTimeSteamp())); @@ -146,9 +169,18 @@ public void DeleteMessage(int MessageID) /// /// 消息ID /// 错误返回null,成功返回JObject - public async Task GetMsg(string MessageID) + public async Task> GetMsg(string MessageID) { - return await SendCallObject(new BaseAPI("get_msg", new JObject() { { "message_id", MessageID } }, "GetMsg:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_msg", new JObject() { { "message_id", MessageID } }, "GetMsg:" + Utils.NowTimeSteamp())); + + return new Dictionary() { + {"MessageID",Json.Value("message_id")}, + {"RealID",Json.Value("real_id")}, + {"Sender",Json.Value("sender")}, + {"Time",Json.Value("time")}, + {"Message",Json.Value("message")}, + {"RawMessage",Json.Value("raw_message")} + }; } /// @@ -158,6 +190,7 @@ public async Task GetMsg(string MessageID) /// 错误返回null,成功返回JObject public async Task GetForwardMsg(string MessageID) { + //TODO 等转发合并消息做完后需要修改这个方法的返回类型 return await SendCallObject(new BaseAPI("get_forward_msg", new JObject() { { "message_id", MessageID } }, "GetForwardMsg:" + Utils.NowTimeSteamp())); } @@ -166,26 +199,33 @@ public async Task GetForwardMsg(string MessageID) /// /// 图片缓存文件名,带不带后缀你喜欢就好 /// 错误返回null,成功返回JObject - public async Task GetImage(string Filename) + public async Task> GetImage(string Filename) { if (!Filename.Contains(".image")) { Filename += ".image"; } - return await SendCallObject(new BaseAPI("get_image", new JObject() { { "file", Filename } }, "GetImage:" + Utils.NowTimeSteamp())); + + JObject Json = await SendCallObject(new BaseAPI("get_image", new JObject() { { "file", Filename } }, "GetImage:" + Utils.NowTimeSteamp())); + + return new Dictionary() { + {"Size",Json.Value("size")}, + {"FileName",Json.Value("filename")}, + {"Url",Json.Value("url")} + }; } /// /// 群组踢人 /// /// 群号 - /// QQ号 + /// QQ号 /// 是否自动拒绝此人加群申请默认:false - public void SetGroupKick(long GroupID, long QID, bool RejectAddRequest = false) + public void SetGroupKick(long GroupID, long UserID, bool RejectAddRequest = false) { JObject Params = new JObject { - { "user_id", QID }, + { "user_id", UserID }, { "group_id", GroupID }, { "reject_add_request", RejectAddRequest } }; @@ -197,13 +237,13 @@ public void SetGroupKick(long GroupID, long QID, bool RejectAddRequest = false) /// 群组单人禁言 /// /// 群号 - /// QQ号 + /// QQ号 /// 禁言时间,单位秒默认:30分钟(1800秒) - public void SetGroupBan(long GroupID, long QID, int Duration = 1800) + public void SetGroupBan(long GroupID, long UserID, int Duration = 1800) { JObject Params = new JObject { - { "user_id", QID }, + { "user_id", UserID }, { "group_id", GroupID }, { "duration", Duration } }; @@ -258,13 +298,13 @@ public void SetGroupWholeBan(long GroupID, bool Enable = true) /// 设置群管理员 /// /// 群号 - /// QQ号 + /// QQ号 /// 是否设置为管理员默认:true - public void SetGroupAdmin(long GroupID, long QID, bool Enable = true) + public void SetGroupAdmin(long GroupID, long UserID, bool Enable = true) { JObject Params = new JObject { - { "user_id", QID }, + { "user_id", UserID }, { "group_id", GroupID }, { "enable", Enable } }; @@ -276,13 +316,13 @@ public void SetGroupAdmin(long GroupID, long QID, bool Enable = true) /// 设置群名片 /// /// 群号 - /// QQ号 + /// QQ号 /// 群名片内容默认:null(删除群名片) - public void SetGroupCard(long GroupID, long QID, string Card = null) + public void SetGroupCard(long GroupID, long UserID, string Card = null) { JObject Params = new JObject { - { "user_id", QID }, + { "user_id", UserID }, { "group_id", GroupID }, { "card", Card } }; @@ -326,14 +366,14 @@ public void SetGroupLeave(long GroupID, bool IsDismiss = false) /// 设置群组专属头衔 /// /// 群号 - /// QQ号 + /// QQ号 /// 群名片内容默认:null(删除群名片) /// 专属头衔有效期, 单位秒, 不过此项似乎没有效果, 可能是只有某些特殊的时间长度有效, 有待测试默认:-1(永久) - public void SetGroupSpecialTitle(long GroupID, long QID, string SpecialTitle = null, int Duration = -1) + public void SetGroupSpecialTitle(long GroupID, long UserID, string SpecialTitle = null, int Duration = -1) { JObject Params = new JObject { - { "user_id", QID }, + { "user_id", UserID }, { "group_id", GroupID }, { "duration", Duration }, { "special_title", SpecialTitle } @@ -384,35 +424,48 @@ public void SetGroupAddRequest(string Flag, string SubType, bool Approve = true, /// 获取登录号信息 /// /// 错误返回null,成功返回JObject - public async Task GetLoginInfo() + public async Task> GetLoginInfo() { - return await SendCallObject(new BaseAPI("get_login_info", null, "GetLoginInfo:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_login_info", null, "GetLoginInfo:" + Utils.NowTimeSteamp())); + + return new Dictionary() { + {"UserID",Json.Value("user_id")}, + {"NickName",Json.Value("nickname")} + }; } /// /// 获取陌生人信息 /// - /// QQ号 + /// QQ号 /// 是否使用缓存,使用缓存响应快但是可能更新不及时默认:false /// 错误返回null,成功返回JObject - public async Task GetStrangerInfo(long QID, bool Cache = false) + public async Task> GetStrangerInfo(long UserID, bool Cache = false) { JObject Params = new JObject { - { "user_id", QID }, + { "user_id", UserID }, { "no_cache ", Cache } }; - return await SendCallObject(new BaseAPI("get_stranger_info", Params, "GetStrangerInfo:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_stranger_info", Params, "GetStrangerInfo:" + Utils.NowTimeSteamp())); + + return new Dictionary() { + {"UserID",Json.Value("user_id")}, + {"NickName",Json.Value("nickname")}, + {"Sex",Json.Value("sex")}, + {"Age",Json.Value("age")}, + {"QID",Json.Value("qid")} + }; } /// /// 获取好友列表 /// /// 错误返回null,成功返回JObject - public async Task GetFriendList() + public async Task> GetFriendList() { - return await SendCallObject(new BaseAPI("get_friend_list", null, "GetFriendList:" + Utils.NowTimeSteamp())); + return (await SendCallArray(new BaseAPI("get_friend_list", null, "GetFriendList:" + Utils.NowTimeSteamp()))).ToObject>(); } /// @@ -421,7 +474,7 @@ public async Task GetFriendList() /// 群号 /// 是否使用缓存,使用缓存响应快但是可能更新不及时默认:false /// 错误返回null,成功返回JObject - public async Task GetGroupInfo(long GroupID, bool Cache = false) + public async Task GetGroupInfo(long GroupID, bool Cache = false) { JObject Params = new JObject { @@ -429,35 +482,35 @@ public async Task GetGroupInfo(long GroupID, bool Cache = false) { "no_cache ", Cache } }; - return await SendCallObject(new BaseAPI("get_group_info", Params, "GetGroupInfo:" + Utils.NowTimeSteamp())); + return (await SendCallObject(new BaseAPI("get_group_info", Params, "GetGroupInfo:" + Utils.NowTimeSteamp()))).ToObject(); } /// /// 获取群列表 /// /// 错误返回null,成功返回JObject - public async Task GetGroupList() + public async Task> GetGroupList() { - return await SendCallObject(new BaseAPI("get_group_list", null, "GetGroupList:" + Utils.NowTimeSteamp())); + return (await SendCallObject(new BaseAPI("get_group_list", null, "GetGroupList:" + Utils.NowTimeSteamp()))).ToObject>(); } /// /// 获取群成员信息 /// /// 群号 - /// QQ号 + /// QQ号 /// 是否使用缓存,使用缓存响应快但是可能更新不及时默认:false /// 错误返回null,成功返回JObject - public async Task GetGroupMemberInfo(long GroupID, long QID, bool Cache = false) + public async Task GetGroupMemberInfo(long GroupID, long UserID, bool Cache = false) { JObject Params = new JObject { { "group_id", GroupID }, - { "user_id", QID }, + { "user_id", UserID }, { "no_cache ", Cache } }; - return await SendCallObject(new BaseAPI("get_group_member_info", Params, "GetGroupMemberInfo:" + Utils.NowTimeSteamp())); + return (await SendCallObject(new BaseAPI("get_group_member_info", Params, "GetGroupMemberInfo:" + Utils.NowTimeSteamp()))).ToObject(); } /// @@ -465,9 +518,9 @@ public async Task GetGroupMemberInfo(long GroupID, long QID, bool Cache /// /// 群号 /// 错误返回null,成功返回JObject - public async Task GetGroupMemberList(long GroupID) + public async Task> GetGroupMemberList(long GroupID) { - return await SendCallObject(new BaseAPI("get_group_member_info", new JObject { { "group_id", GroupID } }, "GetGroupMemberInfo:" + Utils.NowTimeSteamp())); + return (await SendCallObject(new BaseAPI("get_group_member_info", new JObject { { "group_id", GroupID } }, "GetGroupMemberInfo:" + Utils.NowTimeSteamp()))).ToObject>(); } /// @@ -476,7 +529,7 @@ public async Task GetGroupMemberList(long GroupID) /// 群号 /// 要获取的群荣誉类型talkative/performer/legend/strong_newbie/emotion/all /// 错误返回null,成功返回JObject - public async Task GetGroupHonorInfo(long GroupID, string Type) + public async Task> GetGroupHonorInfo(long GroupID, string Type) { JObject Params = new JObject { @@ -484,7 +537,22 @@ public async Task GetGroupHonorInfo(long GroupID, string Type) { "type ", Type } }; - return await SendCallObject(new BaseAPI("get_group_honor_info", Params, "GetGroupHonorInfo:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_group_honor_info", Params, "GetGroupHonorInfo:" + Utils.NowTimeSteamp())); + List Result = new List(); + + foreach (string i in new string[] { "talkative", "performer", "legend", "strong_newbie", "emotion" }) + { + if (Json.TryGetValue("current_talkative", out JToken Cache)) + { + Result.Add(Cache.ToObject()); + } + if (Json.TryGetValue(i + "_list", out Cache)) + { + Result.Add(Cache.ToObject()); + } + } + + return Result; } /// @@ -509,9 +577,26 @@ public async Task CanSendRecord() /// 获取版本信息 /// /// 错误返回null,成功返回JObject - public async Task GetVersionInfo() + public async Task> GetVersionInfo() { - return await SendCallObject(new BaseAPI("get_version_info", null, "GetVersionInfo:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_version_info", null, "GetVersionInfo:" + Utils.NowTimeSteamp())); + + return new Dictionary() { + {"AppFullName",Json.Value("app_full_name")}, + {"AppName",Json.Value("app_name")}, + {"AppVersion",Json.Value("app_version")}, + {"CQDirectory",Json.Value("coolq_directory")}, + {"CQEdition",Json.Value("coolq_edition")}, + {"IsGoCqhttp",Json.Value("go-cqhttp")}, + {"PluginBuildConfiguration",Json.Value("plugin_build_configuration")}, + {"PluginBuildNumber",Json.Value("plugin_build_number")}, + {"PluginVersion",Json.Value("plugin_version")}, + {"Protocol",Json.Value("protocol")}, + {"ProtocolVersion",Json.Value("protocol_version")}, + {"RuntimeOS",Json.Value("runtime_os")}, + {"RuntimeVersion",Json.Value("runtime_version")}, + {"Version",Json.Value("version")} + }; } /// @@ -556,18 +641,20 @@ public async Task GetWordSlices(string Content) /// /// 图片ID /// 错误返回null,成功返回JObject - public async Task OCRImage(string Image) + public async Task<(List, string)> OCRImage(string Image) { - return await SendCallObject(new BaseAPI("ocr_image", new JObject { { "image", Image } }, "OCRImage:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("ocr_image", new JObject { { "image", Image } }, "OCRImage:" + Utils.NowTimeSteamp())); + return (Json.Value("texts").ToObject>(), Json.Value("language")); } /// /// 获取群系统消息 /// /// 错误或不存在任何消息返回null,成功返回JObject - public async Task GetGroupSystemMsg() + public async Task<(List, List)> GetGroupSystemMsg() { - return await SendCallObject(new BaseAPI("get_group_system_msg", null, "GetGroupSystemMsg:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_group_system_msg", null, "GetGroupSystemMsg:" + Utils.NowTimeSteamp())); + return (Json.Value("invited_requests").ToObject>(), Json.Value("join_requests").ToObject>()); } /// @@ -595,9 +682,16 @@ public void UploadGroupFile(long GroupID, string FilePath, string SaveName, stri /// /// 群号 /// 错误返回null,成功返回JObject - public async Task GetGroupFileSystemInfo(long GroupID) + public async Task> GetGroupFileSystemInfo(long GroupID) { - return await SendCallObject(new BaseAPI("get_group_file_system_info", new JObject { { "group_id", GroupID } }, "GetGroupFileSystemInfo:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_group_file_system_info", new JObject { { "group_id", GroupID } }, "GetGroupFileSystemInfo:" + Utils.NowTimeSteamp())); + + return new Dictionary { + { "FileCount",Json.Value("file_count")}, + { "LimitCount",Json.Value("limit_count")}, + { "UsedSpace",Json.Value("used_space")}, + { "TotalSpace",Json.Value("total_space")} + }; } /// @@ -605,9 +699,11 @@ public async Task GetGroupFileSystemInfo(long GroupID) /// /// 群号 /// 错误返回null,成功返回JObject - public async Task GetGroupRootFiles(long GroupID) + public async Task<(List, List)> GetGroupRootFiles(long GroupID) { - return await SendCallObject(new BaseAPI("get_group_root_files", new JObject { { "group_id", GroupID } }, "GetGroupRootFiles:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_group_root_files", new JObject { { "group_id", GroupID } }, "GetGroupRootFiles:" + Utils.NowTimeSteamp())); + + return (Json.Value("files").ToObject>(), Json.Value("folders").ToObject>()); } /// @@ -616,7 +712,7 @@ public async Task GetGroupRootFiles(long GroupID) /// 群号 /// 文件夹ID /// 错误返回null,成功返回JObject - public async Task GetGroupFilesByFolder(long GroupID, string FolderID) + public async Task<(List, List)> GetGroupFilesByFolder(long GroupID, string FolderID) { JObject Params = new JObject { @@ -624,7 +720,9 @@ public async Task GetGroupFilesByFolder(long GroupID, string FolderID) { "folder_id ", FolderID } }; - return await SendCallObject(new BaseAPI("get_group_files_by_folder", Params, "GetGroupFilesByFolder:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_group_files_by_folder", Params, "GetGroupFilesByFolder:" + Utils.NowTimeSteamp())); + + return (Json.Value("files").ToObject>(), Json.Value("folders").ToObject>()); } /// @@ -650,9 +748,10 @@ public async Task GetGroupFilesURL(long GroupID, string FileID, int BusI /// 获取状态 /// /// 错误返回null,成功返回JObject - public async Task GetStatus() + public async Task<(bool, Statistics)> GetStatus() { - return await SendCallObject(new BaseAPI("get_group_info", null, "GetGroupInfo:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_group_info", null, "GetGroupInfo:" + Utils.NowTimeSteamp())); + return (Json.Value("online"), Json.Value("stat")); } /// @@ -660,9 +759,15 @@ public async Task GetStatus() /// /// 群号 /// 错误返回null,成功返回JObject - public async Task GetGroupAtAllRemain(long GroupID) + public async Task> GetGroupAtAllRemain(long GroupID) { - return await SendCallObject(new BaseAPI("get_group_at_all_remain", new JObject { { "group_id", GroupID } }, "GetGroupAtAllRemain:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("get_group_at_all_remain", new JObject { { "group_id", GroupID } }, "GetGroupAtAllRemain:" + Utils.NowTimeSteamp())); + + return new Dictionary() { + { "CanAtAll",Json.Value("can_at_all")}, + { "GroupAdminAtAllCount",Json.Value("remain_at_all_count_for_group")}, + { "BotAtAllCount",Json.Value("remain_at_all_count_for_uin")} + }; } /// @@ -684,11 +789,21 @@ public void HandleQuickOperation(object Context, object Operation) /// /// 获取VIP信息 /// - /// QQ号 + /// QQ号 /// 错误返回null,成功返回JObject - public async Task GetVIPInfo(long QID) + public async Task> GetVIPInfo(long UserID) { - return await SendCallObject(new BaseAPI("_get_vip_info", new JObject { { "user_id", QID } }, "GetGroupAtAllRemain:" + Utils.NowTimeSteamp())); + JObject Json = await SendCallObject(new BaseAPI("_get_vip_info", new JObject { { "user_id", UserID } }, "GetGroupAtAllRemain:" + Utils.NowTimeSteamp())); + + return new Dictionary() { + { "UserID",Json.Value("user_id")}, + { "NickName",Json.Value("nickname")}, + { "Level",Json.Value("level")}, + { "LevelSpeed",Json.Value("level_speed")}, + { "VipLevel",Json.Value("vip_level")}, + { "VipGrowthSpeed",Json.Value("vip_growth_speed")}, + { "VipGrowthTotal",Json.Value("vip_growth_total")} + }; } /// @@ -739,9 +854,9 @@ public async Task DownloadFile(string URL, int ThreadCount, string[] Hea /// /// 是否无视缓存 /// 错误返回null,成功返回JObject - public async Task GetOnlineClients(bool Cache) + public async Task> GetOnlineClients(bool Cache) { - return await SendCallObject(new BaseAPI("get_online_clients", new JObject { { "no_cache ", Cache } }, "GetOnlineClients:" + Utils.NowTimeSteamp())); + return (await SendCallObject(new BaseAPI("get_online_clients", new JObject { { "no_cache ", Cache } }, "GetOnlineClients:" + Utils.NowTimeSteamp()))).Value("clients").ToObject>(); } /// @@ -750,15 +865,21 @@ public async Task GetOnlineClients(bool Cache) /// 起始消息序号 /// 群号 /// 错误返回null,成功返回JObject - public async Task GetGroupMsgHistory(long MessageSeq, long GroupID) + public async Task> GetGroupMsgHistory(long GroupID, long MessageSeq = 0) { JObject Params = new JObject { { "message_seq", MessageSeq }, - { "group_id ", GroupID } + { "group_id", GroupID } }; - return await SendCallObject(new BaseAPI("get_group_msg_history", Params, "GetGroupMsgHistory:" + Utils.NowTimeSteamp())); + if (MessageSeq == 0) + { + Params.Remove("message_seq"); + } + + JObject Json = await SendCallObject(new BaseAPI("get_group_msg_history", Params, "GetGroupMsgHistory:" + Utils.NowTimeSteamp())); + return Json.Value("messages").ToObject>(); } /// @@ -784,9 +905,9 @@ public void DelEssenceMsg(string MessageID) /// /// 群号 /// 错误返回null,成功返回JObject - public async Task GetEssenceMsgList(long GroupID) + public async Task> GetEssenceMsgList(long GroupID) { - return await SendCallObject(new BaseAPI("get_essence_msg_list", new JObject { { "group_id", GroupID } }, "GetEssenceMsgList:" + Utils.NowTimeSteamp())); + return (await SendCallObject(new BaseAPI("get_essence_msg_list", new JObject { { "group_id", GroupID } }, "GetEssenceMsgList:" + Utils.NowTimeSteamp()))).ToObject>(); } /// @@ -807,8 +928,7 @@ public async Task CheckURLSafely(string URL) private async Task SendCallMessageID(BaseAPI Params) { - WebSocket.Send(Params); - TaskList.Add(Params.UniqueCode, "Sended"); + SendCall(Params); string Result = "-1"; await Task.Run(() => { Result = FeedbackMessageID(Params.UniqueCode); }); @@ -817,14 +937,32 @@ private async Task SendCallMessageID(BaseAPI Params) private async Task SendCallObject(BaseAPI Params) { - WebSocket.Send(Params); - TaskList.Add(Params.UniqueCode, "Sended"); + SendCall(Params); JObject Result = null; await Task.Run(() => { Result = FeedbackObject(Params.UniqueCode); }); return Result; } + private async Task SendCallArray(BaseAPI Params) + { + SendCall(Params); + + JArray Result = null; + await Task.Run(() => { Result = FeedbackArray(Params.UniqueCode); }); + return Result; + } + + private void SendCall(BaseAPI Params) + { + Logger.Debug($"API调用:\n请求的接口:{Params.Action}\n请求的唯一码:{Params.UniqueCode}\n请求的参数:\n{Params.Params}"); + WebSocket.Send(Params); + if (!TaskList.TryGetValue(Params.UniqueCode, out _)) + { + TaskList.Add(Params.UniqueCode, "Sended"); + } + } + private void SendCallVoid(BaseAPI Params) { WebSocket.Send(Params); @@ -834,7 +972,7 @@ private void SendCallVoid(BaseAPI Params) private static string FeedbackMessageID(string UniqueCode) { - JObject FBJson = GetFeedback(UniqueCode); + JToken FBJson = GetFeedback(UniqueCode); //判断返回 if (FBJson["status"].ToString() == "ok") @@ -846,7 +984,7 @@ private static string FeedbackMessageID(string UniqueCode) private static JObject FeedbackObject(string UniqueCode) { - JObject FBJson = GetFeedback(UniqueCode); + JToken FBJson = GetFeedback(UniqueCode); //判断返回 if (FBJson["status"].ToString() == "ok") @@ -856,21 +994,63 @@ private static JObject FeedbackObject(string UniqueCode) return null; } - private static JObject GetFeedback(string UniqueCode) { - JObject FBJson = new JObject(); + private static JArray FeedbackArray(string UniqueCode) + { + JToken FBJson = GetFeedback(UniqueCode); + + //判断返回 + if (FBJson["status"].ToString() == "ok") + { + return JArray.Parse(FBJson["data"].ToString()); + } + return null; + } + + private static JToken GetFeedback(string UniqueCode) + { + JToken FBJson = null; do { if (TaskList[UniqueCode].ToString() != "Sended") { - FBJson = JObject.Parse(TaskList[UniqueCode].ToString()); + FBJson = TaskList[UniqueCode]; TaskList.Remove(UniqueCode); break; } Thread.Sleep(10); - }while (FBJson["status"] == null); + } while (FBJson == null); return FBJson; } + + internal static Api Create(BaseWebSocket WebSocket) + { + try + { + Api api = new Api(WebSocket); + Cache.Set($"API{AppDomain.CurrentDomain.Id}", api); + Task.Run(() => + { + Thread.Sleep(5000); + if (!BaseWebSocket.IsCheckVersion) + { + Event.CheckVersion(); + } + }); + return api; + } + catch (WebSocketException e) + { + Logger.Warning("警告,传入的WebSocket有误。错误代码: " + e.ErrorCode); + } + return null; + } + + internal static void Destroy() + { + Cache.Remove($"API{AppDomain.CurrentDomain.Id}"); + } + #endregion } } diff --git a/AuroraNative/EventArgs/Basic/Device.cs b/AuroraNative/Abstract/Device.cs similarity index 97% rename from AuroraNative/EventArgs/Basic/Device.cs rename to AuroraNative/Abstract/Device.cs index 0f42780..ab91fae 100644 --- a/AuroraNative/EventArgs/Basic/Device.cs +++ b/AuroraNative/Abstract/Device.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace AuroraNative.EventArgs +namespace AuroraNative { /// /// 提供用于描述事件参数的基础类, 该类是抽象的 diff --git a/AuroraNative/Abstract/Essences.cs b/AuroraNative/Abstract/Essences.cs new file mode 100644 index 0000000..b2365ac --- /dev/null +++ b/AuroraNative/Abstract/Essences.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 精华消息 抽象类 + /// + public sealed class Essences + { + #region --属性-- + + /// + /// 发送者QQ 号 + /// + [JsonProperty(PropertyName = "sender_id")] + public long SenderID { get; private set; } + + /// + /// 发送者昵称 + /// + [JsonProperty(PropertyName = "sender_nick")] + public string SenderNickName { get; private set; } + + /// + /// 消息发送时间 + /// + [JsonProperty(PropertyName = "sender_time")] + public string SenderTime { get; private set; } + + /// + /// 操作者QQ 号 + /// + [JsonProperty(PropertyName = "operator_id")] + public string OperatorID { get; private set; } + + /// + /// 操作者昵称 + /// + [JsonProperty(PropertyName = "operator_nick")] + public string OperatorNickName { get; private set; } + + /// + /// 精华设置时间 + /// + [JsonProperty(PropertyName = "operator_time")] + public string OperatorTime { get; private set; } + + /// + /// 消息ID + /// + [JsonProperty(PropertyName = "message_id")] + public string MessageID { get; private set; } + + #endregion + } +} diff --git a/AuroraNative/Abstract/Groups/Files/File.cs b/AuroraNative/Abstract/Groups/Files/File.cs new file mode 100644 index 0000000..03ed694 --- /dev/null +++ b/AuroraNative/Abstract/Groups/Files/File.cs @@ -0,0 +1,74 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 群文件 抽象类 + /// + public sealed class File + { + #region --属性-- + + /// + /// 文件ID + /// + [JsonProperty(PropertyName = "file_id")] + public string FileID; + + /// + /// 文件名称 + /// + [JsonProperty(PropertyName = "file_name")] + public string FileName; + + /// + /// 文件类型 + /// + [JsonProperty(PropertyName = "busid")] + public long BusID; + + /// + /// 文件大小 + /// + [JsonProperty(PropertyName = "file_size")] + public long FileSize; + + /// + /// 上传时间 + /// + [JsonProperty(PropertyName = "upload_time")] + public string UploadTime; + + /// + /// 过期时间,永久为零 + /// + [JsonProperty(PropertyName = "dead_time")] + public int DeadTime; + + /// + /// 最后修改时间 + /// + [JsonProperty(PropertyName = "modify_time")] + public int ModifyTime; + + /// + /// 下载次数 + /// + [JsonProperty(PropertyName = "download_times")] + public int DownloadsCount; + + /// + /// 上传者ID + /// + [JsonProperty(PropertyName = "uploader")] + public int Uploader; + + /// + /// 上传者名字 + /// + [JsonProperty(PropertyName = "uploader_name")] + public int UploaderName; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Groups/Files/Folder.cs b/AuroraNative/Abstract/Groups/Files/Folder.cs new file mode 100644 index 0000000..4b17f83 --- /dev/null +++ b/AuroraNative/Abstract/Groups/Files/Folder.cs @@ -0,0 +1,50 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 群文件夹 抽象类 + /// + public sealed class Folder + { + #region --属性-- + + /// + /// 文件夹ID + /// + [JsonProperty(PropertyName = "folder_id")] + public string FolderID; + + /// + /// 文件夹名称 + /// + [JsonProperty(PropertyName = "folder_name")] + public string FolderName; + + /// + /// 创建时间 + /// + [JsonProperty(PropertyName = "create_time")] + public long CreateTime; + + /// + /// 创建者 + /// + [JsonProperty(PropertyName = "creator")] + public long Creator; + + /// + /// 创建者名称 + /// + [JsonProperty(PropertyName = "creator_name")] + public string CreatoName; + + /// + /// 子文件数量 + /// + [JsonProperty(PropertyName = "total_file_count")] + public int TotalFilesCount; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Groups/GroupMember.cs b/AuroraNative/Abstract/Groups/GroupMember.cs new file mode 100644 index 0000000..205add0 --- /dev/null +++ b/AuroraNative/Abstract/Groups/GroupMember.cs @@ -0,0 +1,104 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 群成员信息 抽象类 + /// + public sealed class GroupMember + { + #region --属性-- + + /// + /// 群号 + /// + [JsonProperty(PropertyName = "group_id", NullValueHandling = NullValueHandling.Include)] + public long GroupID; + + /// + /// QQ号 + /// + [JsonProperty(PropertyName = "user_id", NullValueHandling = NullValueHandling.Include)] + public long UserID; + + /// + /// 昵称 + /// + [JsonProperty(PropertyName = "nickname", NullValueHandling = NullValueHandling.Include)] + public string NickName; + + /// + /// 群名片 + /// + [JsonProperty(PropertyName = "card", NullValueHandling = NullValueHandling.Include)] + public string Card; + + /// + /// 现在人数 + /// + [JsonProperty(PropertyName = "sex", NullValueHandling = NullValueHandling.Include)] + public string Sex; + + /// + /// 最大人数 + /// + [JsonProperty(PropertyName = "age", NullValueHandling = NullValueHandling.Include)] + public int MaxMemberCount; + + /// + /// 地区 + /// + [JsonProperty(PropertyName = "area", NullValueHandling = NullValueHandling.Include)] + public string Area; + + /// + /// 加群时间戳 + /// + [JsonProperty(PropertyName = "join_time", NullValueHandling = NullValueHandling.Include)] + public int JoinTime; + + /// + /// 最后发言时间戳 + /// + [JsonProperty(PropertyName = "last_sent_time", NullValueHandling = NullValueHandling.Include)] + public int LastSentTime; + + /// + /// 成员等级 + /// + [JsonProperty(PropertyName = "level", NullValueHandling = NullValueHandling.Include)] + public int Level; + + /// + /// 角色 + /// + [JsonProperty(PropertyName = "role", NullValueHandling = NullValueHandling.Include)] + public int Role; + + /// + /// 是否不良记录成员 + /// + [JsonProperty(PropertyName = "unfriendly", NullValueHandling = NullValueHandling.Include)] + public bool UnFriendly; + + /// + /// 专属头衔 + /// + [JsonProperty(PropertyName = "title", NullValueHandling = NullValueHandling.Include)] + public string ExclusiveTitle; + + /// + /// 专属头衔过期时间戳 + /// + [JsonProperty(PropertyName = "title_expire_time", NullValueHandling = NullValueHandling.Include)] + public long ExclusiveTitleTime; + + /// + /// 是否允许修改群名片 + /// + [JsonProperty(PropertyName = "card_changeable", NullValueHandling = NullValueHandling.Include)] + public bool IsChangeCard; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Groups/Groups.cs b/AuroraNative/Abstract/Groups/Groups.cs new file mode 100644 index 0000000..ccb8dab --- /dev/null +++ b/AuroraNative/Abstract/Groups/Groups.cs @@ -0,0 +1,38 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 群组 抽象类 + /// + public sealed class Groups + { + #region --属性-- + + /// + /// 群号 + /// + [JsonProperty(PropertyName = "group_id")] + public long GroupID; + + /// + /// 群名称 + /// + [JsonProperty(PropertyName = "group_name")] + public string GroupName; + + /// + /// 现在人数 + /// + [JsonProperty(PropertyName = "member_count")] + public int MemberCount; + + /// + /// 最大人数 + /// + [JsonProperty(PropertyName = "max_member_count")] + public int MaxMemberCount; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Groups/HonorListInfo.cs b/AuroraNative/Abstract/Groups/HonorListInfo.cs new file mode 100644 index 0000000..e0747e9 --- /dev/null +++ b/AuroraNative/Abstract/Groups/HonorListInfo.cs @@ -0,0 +1,44 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 群荣誉详细信息 抽象类 + /// + public sealed class HonorListInfo + { + #region --属性-- + + /// + /// QQ号 + /// + [JsonProperty(PropertyName = "user_id")] + public long UserID; + + /// + /// 昵称 + /// + [JsonProperty(PropertyName = "nickname")] + public string NickName; + + /// + /// 头像URL + /// + [JsonProperty(PropertyName = "avatar")] + public string Avater; + + /// + /// 荣誉描述 + /// + [JsonProperty(PropertyName = "description", NullValueHandling = NullValueHandling.Ignore)] + public string Description; + + /// + /// 持续天数 + /// + [JsonProperty(PropertyName = "day_count", NullValueHandling = NullValueHandling.Ignore)] + public string DayCount; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Groups/SystemMessage/BaseRequest.cs b/AuroraNative/Abstract/Groups/SystemMessage/BaseRequest.cs new file mode 100644 index 0000000..7c36b7e --- /dev/null +++ b/AuroraNative/Abstract/Groups/SystemMessage/BaseRequest.cs @@ -0,0 +1,44 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 群系统消息 - 消息列表 基抽象类 + /// + public abstract class BaseRequest + { + #region --属性-- + + /// + /// 请求ID + /// + [JsonProperty(PropertyName = "request_id")] + public long RequestID; + + /// + /// 群号 + /// + [JsonProperty(PropertyName = "group_id")] + public long GroupID; + + /// + /// 群名称 + /// + [JsonProperty(PropertyName = "group_name")] + public string GroupName; + + /// + /// 是否已处理 + /// + [JsonProperty(PropertyName = "checked")] + public bool Checked; + + /// + /// 处理者,未处理是0 + /// + [JsonProperty(PropertyName = "actor")] + public long Actor; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Groups/SystemMessage/InvitedRequest.cs b/AuroraNative/Abstract/Groups/SystemMessage/InvitedRequest.cs new file mode 100644 index 0000000..df275cb --- /dev/null +++ b/AuroraNative/Abstract/Groups/SystemMessage/InvitedRequest.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 群系统消息 - 邀请消息列表 抽象类 + /// + public sealed class InvitedRequest : BaseRequest + { + #region --属性-- + + /// + /// 邀请者 + /// + [JsonProperty(PropertyName = "invitor_uin")] + public long InvitorUserID; + + /// + /// 邀请者昵称 + /// + [JsonProperty(PropertyName = "invitor_nick")] + public string InvitorNickName; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Groups/SystemMessage/JoinRequest.cs b/AuroraNative/Abstract/Groups/SystemMessage/JoinRequest.cs new file mode 100644 index 0000000..495ceeb --- /dev/null +++ b/AuroraNative/Abstract/Groups/SystemMessage/JoinRequest.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 群系统消息 - 进群消息列表 抽象类 + /// + public sealed class JoinRequest : BaseRequest + { + #region --属性-- + + /// + /// 请求者 + /// + [JsonProperty(PropertyName = "requester_uin")] + public long RequesterUserID; + + /// + /// 请求者昵称 + /// + [JsonProperty(PropertyName = "requester_nick")] + public string RequesterNickName; + + /// + /// 验证信息 + /// + [JsonProperty(PropertyName = "message")] + public long Message; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Messages.cs b/AuroraNative/Abstract/Messages.cs new file mode 100644 index 0000000..9b4f6ec --- /dev/null +++ b/AuroraNative/Abstract/Messages.cs @@ -0,0 +1,98 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 消息 抽象类 + /// + public sealed class Messages + { + #region --属性-- + + /// + /// 匿名信息 + /// + [JsonProperty(PropertyName = "anonymous")] + public Anonymous Anonymous; + + /// + /// 字体 + /// + [JsonProperty(PropertyName = "font")] + public int Font; + + /// + /// 群号 + /// + [JsonProperty(PropertyName = "group_id")] + public long GroupID; + + /// + /// 消息内容 + /// + [JsonProperty(PropertyName = "message")] + public string Message; + + /// + /// 原始消息内容 + /// + [JsonProperty(PropertyName = "raw_message")] + public string RawMessage; + + /// + /// 消息ID + /// + [JsonProperty(PropertyName = "message_id")] + public int MessageID; + + /// + /// 消息序号 + /// + [JsonProperty(PropertyName = "message_seq")] + public long MessageSeq; + + /// + /// 消息类型 + /// + [JsonProperty(PropertyName = "message_type")] + public string MessageType; + + /// + /// 消息事件主类型 + /// + [JsonProperty(PropertyName = "post_type")] + public string PostType; + + /// + /// 消息事件子类型 + /// + [JsonProperty(PropertyName = "sub_type")] + public string SubType; + + /// + /// 收到事件的机器人QQ号 + /// + [JsonProperty(PropertyName = "self_id")] + public int SelfID; + + /// + /// 发送者 + /// + [JsonProperty(PropertyName = "sender")] + public Sender Sender; + + /// + /// 消息时间戳 + /// + [JsonProperty(PropertyName = "time")] + public long TimeStamp; + + /// + /// 发送者QQ号 + /// + [JsonProperty(PropertyName = "user_id")] + public long UserID; + + #endregion + } +} diff --git a/AuroraNative/Abstract/OCRTextDetection.cs b/AuroraNative/Abstract/OCRTextDetection.cs new file mode 100644 index 0000000..94dd71a --- /dev/null +++ b/AuroraNative/Abstract/OCRTextDetection.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; +using System.Numerics; + +namespace AuroraNative +{ + /// + /// OCR结果信息 抽象类 + /// + public sealed class OCRTextDetection + { + #region --属性-- + + /// + /// 文本 + /// + [JsonProperty(PropertyName = "text")] + public string Text; + + /// + /// 置信度 + /// + [JsonProperty(PropertyName = "confidence")] + public int Confidence; + + /// + /// 坐标 + /// + [JsonProperty(PropertyName = "coordinates")] + public Vector2 Coordinates; + + #endregion + } +} diff --git a/AuroraNative/Abstract/Statistics.cs b/AuroraNative/Abstract/Statistics.cs new file mode 100644 index 0000000..481bc0c --- /dev/null +++ b/AuroraNative/Abstract/Statistics.cs @@ -0,0 +1,57 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 运行统计 抽象类 + /// + public sealed class Statistics + { + #region --属性-- + + /// + /// 收到的数据包总数 + /// + [JsonProperty(PropertyName = "packet_received")] + public ulong PacketReceived; + + /// + /// 发送的数据包总数 + /// + [JsonProperty(PropertyName = "packet_sent")] + public ulong PacketSent; + + /// + /// 数据包丢失总数 + /// + [JsonProperty(PropertyName = "packet_lost")] + public uint PacketLost; + + /// + /// 接受信息总数 + /// + [JsonProperty(PropertyName = "message_received")] + public ulong MessageReceived; + + /// + /// 发送信息总数 + /// + [JsonProperty(PropertyName = "message_sent")] + public ulong MessageSent; + + /// + /// TCP 链接断开次数 + /// + [JsonProperty(PropertyName = "disconnect_times")] + public uint DisconnectsCount; + + + /// + /// 账号掉线次数 + /// + [JsonProperty(PropertyName = "lost_times")] + public uint LostsCount; + + #endregion + } +} diff --git a/AuroraNative/EventArgs/Basic/Anonymous.cs b/AuroraNative/Abstract/Users/Anonymous.cs similarity index 97% rename from AuroraNative/EventArgs/Basic/Anonymous.cs rename to AuroraNative/Abstract/Users/Anonymous.cs index 4cb522d..895bc76 100644 --- a/AuroraNative/EventArgs/Basic/Anonymous.cs +++ b/AuroraNative/Abstract/Users/Anonymous.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace AuroraNative.EventArgs +namespace AuroraNative { /// /// 提供用于描述匿名信息的基础类, 该类是抽象的 diff --git a/AuroraNative/Abstract/Users/Friends.cs b/AuroraNative/Abstract/Users/Friends.cs new file mode 100644 index 0000000..c1dc2f3 --- /dev/null +++ b/AuroraNative/Abstract/Users/Friends.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; + +namespace AuroraNative +{ + /// + /// 好友 抽象类 + /// + public sealed class Friends + { + #region --属性-- + + /// + /// QQ号 + /// + [JsonProperty(PropertyName = "user_id")] + public long UserID; + + /// + /// 昵称 + /// + [JsonProperty(PropertyName = "nickname")] + public string NickName; + + /// + /// 备注 + /// + [JsonProperty(PropertyName = "remark")] + public string Remark; + + #endregion + } +} diff --git a/AuroraNative/EventArgs/Basic/Sender.cs b/AuroraNative/Abstract/Users/Sender.cs similarity index 98% rename from AuroraNative/EventArgs/Basic/Sender.cs rename to AuroraNative/Abstract/Users/Sender.cs index ef0404f..6bfb011 100644 --- a/AuroraNative/EventArgs/Basic/Sender.cs +++ b/AuroraNative/Abstract/Users/Sender.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace AuroraNative.EventArgs +namespace AuroraNative { /// /// 提供用于描述发送者信息的基础类, 该类是抽象的 diff --git a/AuroraNative/AuroraNative.csproj b/AuroraNative/AuroraNative.csproj index 20db5b0..e90a043 100644 --- a/AuroraNative/AuroraNative.csproj +++ b/AuroraNative/AuroraNative.csproj @@ -15,13 +15,13 @@ false false true - 0.1.0.0311 - 0.1.0.0311 + 1.0.0.0315 + 1.0.0.0315 Icon.png false AuroraNative AuroraNative - 0.1.0-alpha + 1.0.0-Beta true @@ -40,8 +40,14 @@ - + + + + + + + diff --git a/AuroraNative/AuroraNative.xml b/AuroraNative/AuroraNative.xml index 7163e89..79ebc0a 100644 --- a/AuroraNative/AuroraNative.xml +++ b/AuroraNative/AuroraNative.xml @@ -4,6 +4,611 @@ AuroraNative + + + 提供用于描述事件参数的基础类, 该类是抽象的 + + + + + 客户端ID + + + + + 设备名称 + + + + + 设备类型 + + + + + 初始化 类的新实例 + + 客户端ID + 设备名称 + 设备类型 + + + + 精华消息 抽象类 + + + + + 发送者QQ 号 + + + + + 发送者昵称 + + + + + 消息发送时间 + + + + + 操作者QQ 号 + + + + + 操作者昵称 + + + + + 精华设置时间 + + + + + 消息ID + + + + + 群文件 抽象类 + + + + + 文件ID + + + + + 文件名称 + + + + + 文件类型 + + + + + 文件大小 + + + + + 上传时间 + + + + + 过期时间,永久为零 + + + + + 最后修改时间 + + + + + 下载次数 + + + + + 上传者ID + + + + + 上传者名字 + + + + + 群文件夹 抽象类 + + + + + 文件夹ID + + + + + 文件夹名称 + + + + + 创建时间 + + + + + 创建者 + + + + + 创建者名称 + + + + + 子文件数量 + + + + + 群成员信息 抽象类 + + + + + 群号 + + + + + QQ号 + + + + + 昵称 + + + + + 群名片 + + + + + 现在人数 + + + + + 最大人数 + + + + + 地区 + + + + + 加群时间戳 + + + + + 最后发言时间戳 + + + + + 成员等级 + + + + + 角色 + + + + + 是否不良记录成员 + + + + + 专属头衔 + + + + + 专属头衔过期时间戳 + + + + + 是否允许修改群名片 + + + + + 群组 抽象类 + + + + + 群号 + + + + + 群名称 + + + + + 现在人数 + + + + + 最大人数 + + + + + 群荣誉详细信息 抽象类 + + + + + QQ号 + + + + + 昵称 + + + + + 头像URL + + + + + 荣誉描述 + + + + + 持续天数 + + + + + 群系统消息 - 消息列表 基抽象类 + + + + + 请求ID + + + + + 群号 + + + + + 群名称 + + + + + 是否已处理 + + + + + 处理者,未处理是0 + + + + + 群系统消息 - 邀请消息列表 抽象类 + + + + + 邀请者 + + + + + 邀请者昵称 + + + + + 群系统消息 - 进群消息列表 抽象类 + + + + + 请求者 + + + + + 请求者昵称 + + + + + 验证信息 + + + + + 消息 抽象类 + + + + + 匿名信息 + + + + + 字体 + + + + + 群号 + + + + + 消息内容 + + + + + 原始消息内容 + + + + + 消息ID + + + + + 消息序号 + + + + + 消息类型 + + + + + 消息事件主类型 + + + + + 消息事件子类型 + + + + + 收到事件的机器人QQ号 + + + + + 发送者 + + + + + 消息时间戳 + + + + + 发送者QQ号 + + + + + OCR结果信息 抽象类 + + + + + 文本 + + + + + 置信度 + + + + + 坐标 + + + + + 运行统计 抽象类 + + + + + 收到的数据包总数 + + + + + 发送的数据包总数 + + + + + 数据包丢失总数 + + + + + 接受信息总数 + + + + + 发送信息总数 + + + + + TCP 链接断开次数 + + + + + 账号掉线次数 + + + + + 提供用于描述匿名信息的基础类, 该类是抽象的 + + + + + 匿名用户 ID + + + + + 匿名用户名称 + + + + + 匿名用户 flag, 在调用禁言 API 时需要传入 + + + + + 初始化 类的新实例 + + 匿名用户 ID + 匿名用户名称 + 匿名用户 flag, 在调用禁言 API 时需要传入 + + + + 好友 抽象类 + + + + + QQ号 + + + + + 昵称 + + + + + 备注 + + + + + 提供用于描述发送者信息的基础类, 该类是抽象的 + + + + + 发送者 QQ 号 + + + + + 昵称 + + + + + 性别 + + + + + 年龄 + + + + + 群名片/备注 + + + + + 地区 + + + + + 成员等级 + + + + + 角色 + + + + + 专属头衔 + + + + + 初始化 类的新实例 + + 发送者 QQ 号 + 昵称 + 群名片/备注 + 性别 + 年龄 + 地区 + 成员等级 + 角色 + 专属头衔 + API 类 @@ -14,6 +619,11 @@ 任务队列 + + + 获取API实例 + + 构建函数 @@ -24,7 +634,7 @@ 发送私聊消息 - 接受者QQ号 + 接受者QQ号 信息内容 是否转义默认:false 返回消息ID,错误返回-1 @@ -52,7 +662,7 @@ 信息内容 信息类型私聊:private群聊:group - QQ号 + QQ号 群号 是否转义默认:false 错误返回-1,成功返回信息ID @@ -89,7 +699,7 @@ 群组踢人 群号 - QQ号 + QQ号 是否自动拒绝此人加群申请默认:false @@ -97,10 +707,10 @@ 群组单人禁言 群号 - QQ号 + QQ号 禁言时间,单位秒默认:30分钟(1800秒) - + 群组匿名用户禁言 @@ -121,7 +731,7 @@ 设置群管理员 群号 - QQ号 + QQ号 是否设置为管理员默认:true @@ -129,7 +739,7 @@ 设置群名片 群号 - QQ号 + QQ号 群名片内容默认:null(删除群名片) @@ -151,7 +761,7 @@ 设置群组专属头衔 群号 - QQ号 + QQ号 群名片内容默认:null(删除群名片) 专属头衔有效期, 单位秒, 不过此项似乎没有效果, 可能是只有某些特殊的时间长度有效, 有待测试默认:-1(永久) @@ -182,7 +792,7 @@ 获取陌生人信息 - QQ号 + QQ号 是否使用缓存,使用缓存响应快但是可能更新不及时默认:false 错误返回null,成功返回JObject @@ -211,7 +821,7 @@ 获取群成员信息 群号 - QQ号 + QQ号 是否使用缓存,使用缓存响应快但是可能更新不及时默认:false 错误返回null,成功返回JObject @@ -346,7 +956,7 @@ 获取VIP信息 - QQ号 + QQ号 错误返回null,成功返回JObject @@ -695,178 +1305,38 @@ - 请求事件 - - - - - 事件类 - - - - - 元事件 - 生命周期 - - 生命周期事件参数 - - - - 元事件 - 心跳 - - 心跳事件参数 - - - - 消息事件 - 私聊消息 - - 私聊消息参数 - - - - 消息事件 - 群消息 - - 群消息参数 - - - - 请求事件 - 好友请求 - - 好友请求参数 - - - - 请求事件 - 群请求 - - 群请求参数 - - - - 通知事件 - 群文件上传 - - 群文件上传参数 - - - - 通知事件 - 群管理员变动 - - 群管理员变动参数 - - - - 通知事件 - 群成员减少 - - 群成员减少参数 - - - - 通知事件 - 群成员增加 - - 群成员增加参数 - - - - 通知事件 - 群禁言 - - 群禁言参数 - - - - 通知事件 - 好友添加 - - 好友添加参数 - - - - 通知事件 - 群消息撤回 - - 群消息撤回参数 - - - - 通知事件 - 好友消息撤回 - - 好友消息撤回参数 - - - - 通知事件 - 群内戳一戳 - - 群内戳一戳参数 - - - - 通知事件 - 好友戳一戳 - - 群内戳一戳参数 - - - - 通知事件 - 群红包运气王提示 - - 群红包运气王提示参数 - - - - 通知事件 - 群成员荣誉变更提示 - - 群成员荣誉变更提示参数 - - - - 通知事件 - 群成员名片更新(核验) - - 群成员名片更新(核验)参数 - - - - 通知事件 - 接收到离线文件 - - 接收到离线文件参数 - - - - 通知事件 - 其他客户端在线状态变更 - - 其他客户端在线状态变更参数 - - - - 通知事件 - 精华消息变更 + 请求事件 - 精华消息变更参数 - + - 请勿使用,用于子事件分发 + 表示日志信息等级的枚举 - + - 提供用于描述匿名信息的基础类, 该类是抽象的 + 表示输出日志的等级是 "调试" 级别 - + - 匿名用户 ID + 表示输出日志的等级是 "信息" 级别 - + - 匿名用户名称 + 表示输出日志的等级是 "警告" 级别 - + - 匿名用户 flag, 在调用禁言 API 时需要传入 + 表示输出日志的等级是 "错误" 级别 - + - 初始化 类的新实例 + 表示不输出日志 - 匿名用户 ID - 匿名用户名称 - 匿名用户 flag, 在调用禁言 API 时需要传入 @@ -896,37 +1366,9 @@ 收到事件的机器人QQ号 上报类型 - - - 提供用于描述事件参数的基础类, 该类是抽象的 - - - - - 客户端ID - - - - - 设备名称 - - - - - 设备类型 - - - - - 初始化 类的新实例 - - 客户端ID - 设备名称 - 设备类型 - - 提供用于描述匿名信息的基础类, 该类是抽象的 + 提供用于描述文件数据的基础类, 该类是抽象的 @@ -964,70 +1406,6 @@ 下载链接 busid ( 目前不清楚有什么作用 ) - - - 提供用于描述发送者信息的基础类, 该类是抽象的 - - - - - 发送者 QQ 号 - - - - - 昵称 - - - - - 性别 - - - - - 年龄 - - - - - 群名片/备注 - - - - - 地区 - - - - - 成员等级 - - - - - 角色 - - - - - 专属头衔 - - - - - 初始化 类的新实例 - - 发送者 QQ 号 - 昵称 - 群名片/备注 - 性别 - 年龄 - 地区 - 成员等级 - 角色 - 专属头衔 - 提供用于描述消息事件中群聊消息事件参数的类 @@ -1043,7 +1421,7 @@ 匿名消息 - + 初始化 类的新实例 @@ -1106,7 +1484,7 @@ 发送者信息 - + 初始化 类的新实例 @@ -1127,7 +1505,7 @@ 提供用于描述消息事件中私聊消息事件参数的类 - + 初始化 类的新实例 @@ -1223,7 +1601,7 @@ 当前是否在线 - + 初始化 类的新实例 @@ -1784,6 +2162,186 @@ 异常 类 -- 关于WebSocket异常 + + + 事件类 + + + + + 元事件 - 生命周期 + + 生命周期事件参数 + + + + 元事件 - 心跳 + + 心跳事件参数 + + + + 消息事件 - 私聊消息 + + 私聊消息参数 + + + + 消息事件 - 群消息 + + 群消息参数 + + + + 请求事件 - 好友请求 + + 好友请求参数 + + + + 请求事件 - 群请求 + + 群请求参数 + + + + 通知事件 - 群文件上传 + + 群文件上传参数 + + + + 通知事件 - 群管理员变动 + + 群管理员变动参数 + + + + 通知事件 - 群成员减少 + + 群成员减少参数 + + + + 通知事件 - 群成员增加 + + 群成员增加参数 + + + + 通知事件 - 群禁言 + + 群禁言参数 + + + + 通知事件 - 好友添加 + + 好友添加参数 + + + + 通知事件 - 群消息撤回 + + 群消息撤回参数 + + + + 通知事件 - 好友消息撤回 + + 好友消息撤回参数 + + + + 通知事件 - 群内戳一戳 + + 群内戳一戳参数 + + + + 通知事件 - 好友戳一戳 + + 群内戳一戳参数 + + + + 通知事件 - 群红包运气王提示 + + 群红包运气王提示参数 + + + + 通知事件 - 群成员荣誉变更提示 + + 群成员荣誉变更提示参数 + + + + 通知事件 - 群成员名片更新(核验) + + 群成员名片更新(核验)参数 + + + + 通知事件 - 接收到离线文件 + + 接收到离线文件参数 + + + + 通知事件 - 其他客户端在线状态变更 + + 其他客户端在线状态变更参数 + + + + 通知事件 - 精华消息变更 + + 精华消息变更参数 + + + + 请勿使用,用于子事件分发 + + + + + 彩色日志输出类 + + + + + 日志级别设定默认 Info + + + + + 输出一个等级为 调试 的信息 + + 要输出的信息 + 输出的方法名,可选传入 + + + + 输出一个等级为 信息 的信息 + + 要输出的信息 + 输出的方法名,可选传入 + + + + 输出一个等级为 警告 的信息 + + 要输出的信息 + 输出的方法名,可选传入 + + + + 输出一个等级为 错误 的信息 + + 要输出的信息 + 输出的方法名,可选传入 + 通用方法 类 @@ -1794,7 +2352,7 @@ 通过 枚举Description 转为枚举 枚举 - 需要转换的Description + 需要转换的Description 返回该枚举 @@ -1815,14 +2373,14 @@ WebSocket 基础类 - + - Websocket句柄 + 客户端创建 抽象方法 - + - 事件钩子 + 客户端销毁 抽象方法 @@ -1839,8 +2397,19 @@ - WebSocket服务端地址请记得带端口号 + WebSocket服务端地址 + + + + + WebSocket服务端端口号 + + + + + 创建一个 实例 + 重写后的事件类实例 @@ -1863,6 +2432,12 @@ WebSocket监听端口 + + + 创建一个 实例 + + 重写后的事件类实例 + 创建WebSocket服务器并监听端口 diff --git a/AuroraNative/Enum/LogLevel.cs b/AuroraNative/Enum/LogLevel.cs new file mode 100644 index 0000000..ba0c67b --- /dev/null +++ b/AuroraNative/Enum/LogLevel.cs @@ -0,0 +1,29 @@ +namespace AuroraNative +{ + /// + /// 表示日志信息等级的枚举 + /// + public enum LogLevel + { + /// + /// 表示输出日志的等级是 "调试" 级别 + /// + Debug = 0, + /// + /// 表示输出日志的等级是 "信息" 级别 + /// + Info = 1, + /// + /// 表示输出日志的等级是 "警告" 级别 + /// + Warning = 2, + /// + /// 表示输出日志的等级是 "错误" 级别 + /// + Error = 3, + /// + /// 表示不输出日志 + /// + Off = 4 + } +} diff --git a/AuroraNative/EventArgs/Basic/File.cs b/AuroraNative/EventArgs/Basic/File.cs index d0eb1d2..db42ca3 100644 --- a/AuroraNative/EventArgs/Basic/File.cs +++ b/AuroraNative/EventArgs/Basic/File.cs @@ -3,7 +3,7 @@ namespace AuroraNative.EventArgs { /// - /// 提供用于描述匿名信息的基础类, 该类是抽象的 + /// 提供用于描述文件数据的基础类, 该类是抽象的 /// public sealed class File { diff --git a/AuroraNative/README.md b/AuroraNative/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/AuroraNative/Event.cs b/AuroraNative/Utils/Event.cs similarity index 89% rename from AuroraNative/Event.cs rename to AuroraNative/Utils/Event.cs index 186fe40..57ececb 100644 --- a/AuroraNative/Event.cs +++ b/AuroraNative/Utils/Event.cs @@ -1,12 +1,14 @@ using AuroraNative.EventArgs; +using AuroraNative.WebSockets; using Newtonsoft.Json.Linq; +using System; namespace AuroraNative { /// /// 事件类 /// - public class Event + public abstract class Event { #region --公开函数-- @@ -230,5 +232,23 @@ public void RouterNotify(JObject Json) #endregion #endregion + + #region --私有函数-- + + internal static async void CheckVersion() + { + Logger.Debug("开始检查 go-cqhttp 版本是否符合最低版本..."); + if ((await Api.CurrentApi.GetVersionInfo()).TryGetValue("AppVersion", out object Version) && new Version(Version.ToString().Substring(1, Version.ToString().IndexOf('-') - 1)) < BaseWebSocket.DependencyVersion) + { + Logger.Warning($"框架最低依赖版本与 go-cqhttp 不符!请检查是否为最新的框架或符合的 go-cqhttp\ngo-cqhttp版本:{Version}\n框架最低依赖版本:v{BaseWebSocket.DependencyVersion}"); + } + else + { + Logger.Debug("go-cqhttp 版本符合最低版本!"); + } + BaseWebSocket.IsCheckVersion = true; + } + + #endregion } } diff --git a/AuroraNative/Utils/Logger.cs b/AuroraNative/Utils/Logger.cs new file mode 100644 index 0000000..20a93cb --- /dev/null +++ b/AuroraNative/Utils/Logger.cs @@ -0,0 +1,104 @@ +using System; + +namespace AuroraNative +{ + /// + /// 彩色日志输出类 + /// + public static class Logger + { + #region --属性-- + + /// + /// 日志级别设定默认 Info + /// + public static LogLevel LogLevel = LogLevel.Info; + + #endregion + + #region --公开函数-- + + /// + /// 输出一个等级为 调试 的信息 + /// + /// 要输出的信息 + /// 输出的方法名,可选传入 + public static void Debug(string Message, string MethodName = null) + { + if (LogLevel <= LogLevel.Debug) + { + Output(Message, ConsoleColor.Gray, LogLevel.Debug, MethodName, true); + } + } + + /// + /// 输出一个等级为 信息 的信息 + /// + /// 要输出的信息 + /// 输出的方法名,可选传入 + public static void Info(string Message, string MethodName = null) + { + if (LogLevel <= LogLevel.Info) + { + Output(Message, ConsoleColor.White, LogLevel.Info, MethodName); + } + } + + /// + /// 输出一个等级为 警告 的信息 + /// + /// 要输出的信息 + /// 输出的方法名,可选传入 + public static void Warning(string Message, string MethodName = null) + { + if (LogLevel <= LogLevel.Warning) + { + Output(Message, ConsoleColor.Yellow, LogLevel.Warning, MethodName); + } + } + + /// + /// 输出一个等级为 错误 的信息 + /// + /// 要输出的信息 + /// 输出的方法名,可选传入 + public static void Error(string Message, string MethodName = null) + { + if (LogLevel <= LogLevel.Error) + { + Output(Message, ConsoleColor.Red, LogLevel.Error, MethodName); + } + } + + #endregion + + #region --私有函数-- + + internal static void Output(string Message, ConsoleColor Color, LogLevel Level, string MethodName, bool IsFine = false) + { + Console.ForegroundColor = Color; + string NowTime; + + if (!IsFine) + { + NowTime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"); + } + else + { + NowTime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff"); + } + + if (MethodName != null) + { + Console.WriteLine($"[{NowTime}]" + $" [{Level}]" + $" [{MethodName}]: " + Message); + } + else + { + Console.WriteLine($"[{NowTime}]" + $" [{Level}]: " + Message); + } + Console.ForegroundColor = ConsoleColor.White; + } + + #endregion + } +} diff --git a/AuroraNative/Utils.cs b/AuroraNative/Utils/Utils.cs similarity index 90% rename from AuroraNative/Utils.cs rename to AuroraNative/Utils/Utils.cs index 3bbf6d0..b16bef7 100644 --- a/AuroraNative/Utils.cs +++ b/AuroraNative/Utils/Utils.cs @@ -13,21 +13,21 @@ public class Utils /// 通过 枚举Description 转为枚举 /// /// 枚举 - /// 需要转换的Description + /// 需要转换的Description /// 返回该枚举 - public static T GetEnumByDescription(string description) where T : Enum + public static T GetEnumByDescription(string Description) where T : Enum { System.Reflection.FieldInfo[] fields = typeof(T).GetFields(); foreach (System.Reflection.FieldInfo field in fields) { object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false); - if (objs.Length > 0 && (objs[0] as DescriptionAttribute).Description == description) + if (objs.Length > 0 && (objs[0] as DescriptionAttribute).Description == Description) { return (T)field.GetValue(null); } } - throw new ArgumentException(string.Format("{0} 未能找到对应的枚举.", description), "Description"); + throw new ArgumentException(string.Format("{0} 未能找到对应的枚举.", Description), nameof(Description)); } /// diff --git a/AuroraNative/WebSockets/BaseWebSocket.cs b/AuroraNative/WebSockets/BaseWebSocket.cs index 4c14c56..0bac87f 100644 --- a/AuroraNative/WebSockets/BaseWebSocket.cs +++ b/AuroraNative/WebSockets/BaseWebSocket.cs @@ -17,40 +17,59 @@ public abstract class BaseWebSocket { #region --变量-- - /// - /// Websocket句柄 - /// + internal int Port = 6700; internal WebSocket WebSocket; - /// - /// 事件钩子 - /// - public Event EventHook; - + internal Event EventHook; internal JObject Json; - internal static Type[] AttributeTypes; + internal static readonly Type[] AttributeTypes = Assembly.GetExecutingAssembly().GetTypes().Where(p => p.IsAbstract == false && p.IsInterface == false && typeof(Attribute).IsAssignableFrom(p)).ToArray(); + internal static readonly Version DependencyVersion = new Version("0.9.40"); + internal static bool IsCheckVersion = false; #endregion #region --公开函数-- + /// + /// 客户端创建 抽象方法 + /// + public abstract void Create(); + /// + /// 客户端销毁 抽象方法 + /// + public abstract void Dispose(); + + internal abstract void Feedback(); + /// /// 发送数据到服务端/客户端 /// /// 传输Json格式的文本 - public void Send(BaseAPI Json) + internal void Send(BaseAPI Json) { - WebSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Json, Formatting.None))), WebSocketMessageType.Text, true, CancellationToken.None); + try + { + WebSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Json, Formatting.None))), WebSocketMessageType.Text, true, CancellationToken.None); + } + catch (Exception e) + { + Logger.Error("调用API出现未知错误!\n" + e.Message, $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + } } internal async Task GetEventAsync() { - ArraySegment BytesReceived = new ArraySegment(new byte[5120]); + ArraySegment BytesReceived = new ArraySegment(new byte[10240]); WebSocketReceiveResult Result = await WebSocket.ReceiveAsync(BytesReceived, CancellationToken.None); - Json = JObject.Parse(Encoding.UTF8.GetString(BytesReceived.Array, 0, Result.Count)); + if (Result.Count == 0) {return;} + Json = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(BytesReceived.Array, 0, Result.Count)); if (Json.TryGetValue("echo", out JToken Token)) { - Api.TaskList[Json["echo"].ToString()] = Json; + if (Json.TryGetValue("status", out JToken Cache) && Cache.ToString() != "ok") { + Logger.Warning(Json.ToString(), $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + } + + Api.TaskList[Token.ToString()] = Json; } else { @@ -64,7 +83,7 @@ internal async Task GetEventAsync() { foreach (MethodInfo Method in EventHook.GetType().GetMethods().Where(p => p.GetCustomAttribute() != null)) { - if (Method.GetCustomAttribute(Type) is BaseAttribute attribute && attribute.Type == (string)Json.GetValue(Utils.GetChildTypeByPostType(Json))) + if (Method.GetCustomAttribute(Type) is BaseAttribute Attribute && Attribute.Type == (string)Json.GetValue(Utils.GetChildTypeByPostType(Json))) { ParameterInfo Parameter = Method.GetParameters().SingleOrDefault(); diff --git a/AuroraNative/WebSockets/Client.cs b/AuroraNative/WebSockets/Client.cs index 812510f..d2157a1 100644 --- a/AuroraNative/WebSockets/Client.cs +++ b/AuroraNative/WebSockets/Client.cs @@ -1,7 +1,7 @@ using System; -using System.Linq; using System.Net.WebSockets; using System.Reflection; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -15,24 +15,46 @@ public class Client : BaseWebSocket { #region --变量-- - private string Host = "127.0.0.1:6700"; + private string Host = "127.0.0.1"; + /// - /// WebSocket服务端地址请记得带端口号 + /// WebSocket服务端地址 /// public string host { private get { return Host; } - set { Host = value; } + set + { + if (value.Contains(":")) + { + string[] Cache = value.Split(':'); + Host = Cache[0]; + Port = int.Parse(Cache[1]); + } + else + { + Host = value; + } + } + } + /// + /// WebSocket服务端端口号 + /// + public int port + { + private get { return Port; } + set { Port = value; } } #endregion #region --构造函数-- - static Client() - { - AttributeTypes = Assembly.GetExecutingAssembly().GetTypes().Where(p => p.IsAbstract == false && p.IsInterface == false && typeof(Attribute).IsAssignableFrom(p)).ToArray(); - } + /// + /// 创建一个 实例 + /// + /// 重写后的事件类实例 + public Client(Event Event) => EventHook = Event; #endregion @@ -41,31 +63,69 @@ static Client() /// /// 创建并连接到WebSocket服务器 /// - public void Create() + public override void Create() { - WebSocket = new ClientWebSocket(); - Task Connect = ((ClientWebSocket)WebSocket).ConnectAsync(new Uri("ws://" + Host + "/"), CancellationToken.None); - Connect.Wait(); - if (WebSocket.State == WebSocketState.Open) + StringBuilder Cache = new StringBuilder(); + Cache.Append(Host); + Cache.Append(':'); + Cache.Append(Port); + + Logger.Debug("正向WebSocket已创建,准备连接...", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + for (int i = 1; i < 4; i++) { - Task.Run(Feedback); + try + { + WebSocket = new ClientWebSocket(); + if (WebSocket is ClientWebSocket socket) + { + Logger.Debug($"准备连接至IP:{Cache}", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + Task Connect = socket.ConnectAsync(new Uri("ws://" + Cache.ToString() + "/"), CancellationToken.None); + Connect.Wait(); + if (WebSocket.State == WebSocketState.Open) + { + Logger.Info("已连接至 go-cqhttp 服务器!"); + Logger.Debug("防止由于go-cqhttp未初始化异常,连接后需等待2秒..."); + Thread.Sleep(2000); + Logger.Debug("go-cqhttp 初始化完毕!"); + Task.Run(Feedback); + Api.Create(this); + return; + } + } + } + catch (AggregateException) + { + Logger.Warning($"连接到 go-cqhttp 服务器失败!五秒后重试(重试次数:{i})...", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + Thread.Sleep(5000); + } } + Logger.Error("连接到 go-cqhttp 服务器失败!请检查IP是否正确(需要携带端口号)或确认服务器是否启动和初始化完毕!", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); } /// /// 立刻中断并释放连接注意!断开后需要重新Create /// - public void Dispose() + public override void Dispose() { - WebSocket.Dispose(); - WebSocket.Abort(); + Logger.Debug($"准备销毁正向WebSocket...", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + try + { + WebSocket.Dispose(); + WebSocket.Abort(); + Api.Destroy(); + Logger.Info("已销毁正向WebSocket"); + } + catch (Exception e) + { + Logger.Error("销毁正向WebSocket失败!\n" + e.Message, $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + } } #endregion #region --私有函数-- - private async void Feedback() + internal override async void Feedback() { while (true) { diff --git a/AuroraNative/WebSockets/Server.cs b/AuroraNative/WebSockets/Server.cs index 87f1f77..ef5a104 100644 --- a/AuroraNative/WebSockets/Server.cs +++ b/AuroraNative/WebSockets/Server.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Net; using System.Net.WebSockets; using System.Reflection; @@ -16,11 +15,10 @@ public class Server : BaseWebSocket { #region --变量-- - private string Port = "6700"; /// /// WebSocket监听端口 /// - public string port + public int port { private get { return Port; } set { Port = value; } @@ -33,10 +31,11 @@ public string port #region --构造函数-- - static Server() - { - AttributeTypes = Assembly.GetExecutingAssembly().GetTypes().Where(p => p.IsAbstract == false && p.IsInterface == false && typeof(Attribute).IsAssignableFrom(p)).ToArray(); - } + /// + /// 创建一个 实例 + /// + /// 重写后的事件类实例 + public Server(Event Event) => EventHook = Event; #endregion @@ -45,47 +44,80 @@ static Server() /// /// 创建WebSocket服务器并监听端口 /// - public void Create() + public override void Create() { - Listener = new HttpListener(); - Listener.Prefixes.Add("http://*:" + Port + "/"); - Listener.Start(); - Task.Run(Feedback); - while (!IsConnect) + try + { + Logger.Debug("反向WebSocket已创建,准备监听...", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + Listener = new HttpListener(); + Listener.Prefixes.Add("http://*:" + Port.ToString() + "/"); + Listener.Start(); + Logger.Info("开始监听来自 go-cqhttp 客户端的连接..."); + Task.Run(Feedback); + while (!IsConnect) + { + Thread.Sleep(100); + } + } + catch (HttpListenerException) { - Thread.Sleep(100); + Logger.Error("无法启动监听服务器,请确保使用管理员权限运行。否则无法监听!", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + Console.ReadKey(); + Environment.Exit(0); } } /// /// 立刻中断并释放连接注意!断开后需要重新Create /// - public void Dispose() + public override void Dispose() { - Listener.Stop(); - WebSocket.Dispose(); - WebSocket.Abort(); + Logger.Debug($"准备销毁反向WebSocket...", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + try + { + Listener.Stop(); + WebSocket.Dispose(); + WebSocket.Abort(); + Api.Destroy(); + Logger.Info("已销毁反向WebSocket"); + } + catch (Exception e) + { + Logger.Error("销毁反向WebSocket失败!\n" + e.Message, $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + } } #endregion #region --私有函数-- - private async void Feedback() + internal override async void Feedback() { while (true) { - HttpListenerContext Context = await Listener.GetContextAsync(); - if (Context.Request.IsWebSocketRequest) + try { - HttpListenerWebSocketContext SocketContext = await Context.AcceptWebSocketAsync(null); - WebSocket = SocketContext.WebSocket; - IsConnect = true; - while (WebSocket.State == WebSocketState.Open) + HttpListenerContext Context = await Listener.GetContextAsync(); + if (Context.Request.IsWebSocketRequest) { - await GetEventAsync(); + Logger.Info("收到来自 go-cqhttp 客户端的连接!连接已建立!"); + HttpListenerWebSocketContext SocketContext = await Context.AcceptWebSocketAsync(null); + WebSocket = SocketContext.WebSocket; + Logger.Debug("防止由于go-cqhttp未初始化异常,连接后需等待5秒..."); + Thread.Sleep(5000); + Logger.Debug("go-cqhttp 初始化完毕!"); + IsConnect = true; + Api.Create(this); + while (WebSocket.State == WebSocketState.Open) + { + await GetEventAsync(); + } } } + catch (Exception e) + { + Logger.Error("反向WebSocket出现未知错误!\n" + e.Message, $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + } } } diff --git a/README.md b/README.md index cc619c7..8fb50fd 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,15 @@ - 优化内部算法或修改类型(如将返回的JObject类型抽象为新自定义类型) - vX.X.X+1 - 重命名/删除/新增 文件/命名空间/API - vX.X+1.X +## 文档 + +开发文档:[点我查看](https://auroranative.mikuy.cn) + +> 开发文档是与框架一起更新的,因此文档也处于快速迭代状态。 + ## 兼容性 -### 接口 +### 通讯方式 - [ ] HTTP API - [ ] 反向 HTTP POST @@ -50,7 +56,7 @@ ## 关于 ISSUE -如果没有大问题请到 Discussions 处提问 +如果没有大问题请到 [Discussions](https://github.com/timi137137/AuroraNative/discussions) 处提问 以下 ISSUE 会被直接关闭 @@ -69,4 +75,4 @@ ### 使用到的开源库 -[Newtonsoft.Json](https://www.newtonsoft.com/json) +[Newtonsoft.Json](https://www.newtonsoft.com/json) | [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/5.0.0)