diff --git a/AuroraNative/API/Api.cs b/AuroraNative/API/Api.cs index 6f57e84..db79fd6 100644 --- a/AuroraNative/API/Api.cs +++ b/AuroraNative/API/Api.cs @@ -1,7 +1,9 @@ using AuroraNative.EventArgs; using AuroraNative.WebSockets; +using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System; using System.Threading; using System.Threading.Tasks; @@ -10,7 +12,7 @@ namespace AuroraNative /// /// API 类 /// - public class Api + public sealed class Api { #region --变量-- @@ -18,18 +20,28 @@ namespace AuroraNative /// 任务队列 /// 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; } @@ -856,7 +868,8 @@ namespace AuroraNative return null; } - private static JObject GetFeedback(string UniqueCode) { + private static JObject GetFeedback(string UniqueCode) + { JObject FBJson = new JObject(); do @@ -868,9 +881,22 @@ namespace AuroraNative break; } Thread.Sleep(10); - }while (FBJson["status"] == null); + } while (FBJson["status"] == null); return FBJson; } + + internal static Api Create(BaseWebSocket WebSocket) + { + Api api = new Api(WebSocket); + Cache.Set($"API{AppDomain.CurrentDomain.Id}", api); + return api; + } + + internal static void Destroy() + { + Cache.Remove($"API{AppDomain.CurrentDomain.Id}"); + } + #endregion } } diff --git a/AuroraNative/AuroraNative.csproj b/AuroraNative/AuroraNative.csproj index 20db5b0..e84de38 100644 --- a/AuroraNative/AuroraNative.csproj +++ b/AuroraNative/AuroraNative.csproj @@ -15,13 +15,13 @@ false false true - 0.1.0.0311 - 0.1.0.0311 + 0.2.0.0312 + 0.2.0.0312 Icon.png false AuroraNative AuroraNative - 0.1.0-alpha + 0.2.0-alpha true @@ -41,6 +41,7 @@ + diff --git a/AuroraNative/AuroraNative.xml b/AuroraNative/AuroraNative.xml index 7163e89..5f3e9ad 100644 --- a/AuroraNative/AuroraNative.xml +++ b/AuroraNative/AuroraNative.xml @@ -14,6 +14,11 @@ 任务队列 + + + 获取API实例 + + 构建函数 @@ -1784,6 +1789,69 @@ 异常 类 -- 关于WebSocket异常 + + + 彩色日志输出类 + + + + + 日志级别设定默认 Info + + + + + 输出一个等级为 调试 的信息 + + 要输出的信息 + 输出的方法名,可选传入 + + + + 输出一个等级为 信息 的信息 + + 要输出的信息 + 输出的方法名,可选传入 + + + + 输出一个等级为 警告 的信息 + + 要输出的信息 + 输出的方法名,可选传入 + + + + 输出一个等级为 错误 的信息 + + 要输出的信息 + 输出的方法名,可选传入 + + + + 表示日志信息等级的枚举 + + + + + 表示输出日志的等级是 "调试" 级别 + + + + + 表示输出日志的等级是 "信息" 级别 + + + + + 表示输出日志的等级是 "警告" 级别 + + + + + 表示输出日志的等级是 "错误" 级别 + + 通用方法 类 @@ -1815,16 +1883,6 @@ WebSocket 基础类 - - - Websocket句柄 - - - - - 事件钩子 - - 发送数据到服务端/客户端 @@ -1842,6 +1900,12 @@ WebSocket服务端地址请记得带端口号 + + + 创建一个 实例 + + 重写后的事件类实例 + 创建并连接到WebSocket服务器 @@ -1863,6 +1927,12 @@ WebSocket监听端口 + + + 创建一个 实例 + + 重写后的事件类实例 + 创建WebSocket服务器并监听端口 diff --git a/AuroraNative/Event.cs b/AuroraNative/Event.cs index 186fe40..f016728 100644 --- a/AuroraNative/Event.cs +++ b/AuroraNative/Event.cs @@ -1,4 +1,5 @@ using AuroraNative.EventArgs; +using AuroraNative.WebSockets; using Newtonsoft.Json.Linq; namespace AuroraNative diff --git a/AuroraNative/Logger.cs b/AuroraNative/Logger.cs new file mode 100644 index 0000000..04f7902 --- /dev/null +++ b/AuroraNative/Logger.cs @@ -0,0 +1,110 @@ +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); + } + } + + /// + /// 输出一个等级为 信息 的信息 + /// + /// 要输出的信息 + /// 输出的方法名,可选传入 + 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) { + Console.ForegroundColor = Color; + if (MethodName != null) { + Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + $" [{Level}]" + $" [{MethodName}] " + Message); + } + else { + Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + $" [{Level}] " + Message); + } + Console.ForegroundColor = ConsoleColor.White; + } + + #endregion + } + + /// + /// 表示日志信息等级的枚举 + /// + public enum LogLevel { + /// + /// 表示输出日志的等级是 "调试" 级别 + /// + Debug = 0, + /// + /// 表示输出日志的等级是 "信息" 级别 + /// + Info = 1, + /// + /// 表示输出日志的等级是 "警告" 级别 + /// + Warning = 2, + /// + /// 表示输出日志的等级是 "错误" 级别 + /// + Error = 3 + } +} diff --git a/AuroraNative/WebSockets/BaseWebSocket.cs b/AuroraNative/WebSockets/BaseWebSocket.cs index 4c14c56..9fa23c7 100644 --- a/AuroraNative/WebSockets/BaseWebSocket.cs +++ b/AuroraNative/WebSockets/BaseWebSocket.cs @@ -17,15 +17,8 @@ namespace AuroraNative.WebSockets { #region --变量-- - /// - /// Websocket句柄 - /// internal WebSocket WebSocket; - /// - /// 事件钩子 - /// - public Event EventHook; - + internal Event EventHook; internal JObject Json; internal static Type[] AttributeTypes; diff --git a/AuroraNative/WebSockets/Client.cs b/AuroraNative/WebSockets/Client.cs index e7f1250..6517a21 100644 --- a/AuroraNative/WebSockets/Client.cs +++ b/AuroraNative/WebSockets/Client.cs @@ -34,6 +34,12 @@ namespace AuroraNative.WebSockets AttributeTypes = Assembly.GetExecutingAssembly().GetTypes().Where(p => p.IsAbstract == false && p.IsInterface == false && typeof(Attribute).IsAssignableFrom(p)).ToArray(); } + /// + /// 创建一个 实例 + /// + /// 重写后的事件类实例 + public Client(Event Event) => EventHook = Event; + #endregion #region --公开函数-- @@ -43,16 +49,32 @@ namespace AuroraNative.WebSockets /// public bool Create() { - WebSocket = new ClientWebSocket(); - if (WebSocket is ClientWebSocket socket) { - Task Connect = socket.ConnectAsync(new Uri("ws://" + Host + "/"), CancellationToken.None); - Connect.Wait(); - if (WebSocket.State == WebSocketState.Open) + Logger.Debug("正向WebSocket已创建,准备连接...", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + for (int i = 1;i < 4;i++) { + try { - Task.Run(Feedback); - return true; + WebSocket = new ClientWebSocket(); + if (WebSocket is ClientWebSocket socket) + { + Logger.Debug($"准备连接至IP:{Host}", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + Task Connect = socket.ConnectAsync(new Uri("ws://" + Host + "/"), CancellationToken.None); + Connect.Wait(); + if (WebSocket.State == WebSocketState.Open) + { + Logger.Info("已连接至 go-cqhttp 服务器!"); + Task.Run(Feedback); + Api.Create(this); + return true; + } + } + } + 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}"); return false; } @@ -61,8 +83,17 @@ namespace AuroraNative.WebSockets /// public 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 diff --git a/AuroraNative/WebSockets/Server.cs b/AuroraNative/WebSockets/Server.cs index 87f1f77..3fbb4f2 100644 --- a/AuroraNative/WebSockets/Server.cs +++ b/AuroraNative/WebSockets/Server.cs @@ -38,6 +38,12 @@ namespace AuroraNative.WebSockets AttributeTypes = Assembly.GetExecutingAssembly().GetTypes().Where(p => p.IsAbstract == false && p.IsInterface == false && typeof(Attribute).IsAssignableFrom(p)).ToArray(); } + /// + /// 创建一个 实例 + /// + /// 重写后的事件类实例 + public Server(Event Event) => EventHook = Event; + #endregion #region --公开函数-- @@ -47,13 +53,22 @@ namespace AuroraNative.WebSockets /// public void Create() { - Listener = new HttpListener(); - Listener.Prefixes.Add("http://*:" + Port + "/"); - Listener.Start(); - Task.Run(Feedback); - while (!IsConnect) + try { - Thread.Sleep(100); + Logger.Debug("反向WebSocket已创建,准备监听...", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + Listener = new HttpListener(); + Listener.Prefixes.Add("http://*:" + Port + "/"); + Listener.Start(); + Logger.Info("开始监听来自 go-cqhttp 客户端的连接..."); + Task.Run(Feedback); + while (!IsConnect) { + Thread.Sleep(100); + } + } + catch(HttpListenerException) { + Logger.Error("无法启动监听服务器,请确保使用管理员权限运行。否则无法监听!", $"{MethodBase.GetCurrentMethod().DeclaringType.Name}.{MethodBase.GetCurrentMethod().Name}"); + Console.ReadKey(); + Environment.Exit(0); } } @@ -62,9 +77,16 @@ namespace AuroraNative.WebSockets /// public 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 @@ -78,9 +100,11 @@ namespace AuroraNative.WebSockets HttpListenerContext Context = await Listener.GetContextAsync(); if (Context.Request.IsWebSocketRequest) { + Logger.Info("收到来自 go-cqhttp 客户端的连接!连接已建立!"); HttpListenerWebSocketContext SocketContext = await Context.AcceptWebSocketAsync(null); WebSocket = SocketContext.WebSocket; IsConnect = true; + Api.Create(this); while (WebSocket.State == WebSocketState.Open) { await GetEventAsync(); diff --git a/README.md b/README.md index e148241..35678b2 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 会被直接关闭