From ea4937676d8f9a8b784d5203f8c31e0c30b62bce Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Wed, 8 Nov 2023 02:31:36 +0800 Subject: [PATCH 01/22] =?UTF-8?q?=E5=87=86=E5=A4=87=E4=BD=BF=E7=94=A8XFEMe?= =?UTF-8?q?ssage.xfe=E7=BB=9F=E4=B8=80=E8=AF=BB=E5=8F=96=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CyberComm.cs" | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" index 9bbb56e..5a262f3 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" @@ -1559,7 +1559,7 @@ private void LoadFile(string groupId, string filePath) switch (Path.GetExtension(filePath)) { case ".png": - xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Image, fileBuffer)); + xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Image,, fileBuffer)); break; case ".mp4": xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Video, fileBuffer)); @@ -1694,6 +1694,14 @@ public class XCCFile /// public string MessageId { get; } /// + /// 发送者 + /// + public string Sender { get; } + /// + /// 发送时间 + /// + public DateTime SendTime { get; } + /// /// XCC文件类型 /// public XCCFileType FileType { get; } @@ -1721,27 +1729,18 @@ public void LoadFile(byte[] fileBuffer) /// 群组ID /// 文件消息ID /// 文件类型 + /// 发送者 + /// 发送时间 /// 文件的Buffer - public XCCFile(string groupId, string messageId, XCCFileType fileType, byte[] fileBuffer) + public XCCFile(string groupId, string messageId, XCCFileType fileType, string sender, DateTime sendTime, byte[] fileBuffer = null) { GroupId = groupId; - FileType = fileType; MessageId = messageId; - FileBuffer = fileBuffer; - Loaded = true; - } - /// - /// XCC文件 - /// - /// 群组ID - /// 文件ID - /// 文件类型 - public XCCFile(string groupId, string messageId, XCCFileType fileType) - { - GroupId = groupId; FileType = fileType; - MessageId = messageId; - Loaded = false; + Sender = sender; + SendTime = sendTime; + FileBuffer = fileBuffer; + Loaded = fileBuffer != null; } } /// From 09682d6fecd9f7fbbcf9ce251c781f778fc1f88e Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Wed, 8 Nov 2023 23:11:37 +0800 Subject: [PATCH 02/22] =?UTF-8?q?=E6=8C=81=E7=BB=AD=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CyberComm.cs" | 71 +++++++++++++++++-- .../FormatExtension.cs" | 11 +++ 2 files changed, 76 insertions(+), 6 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" index 5a262f3..0a3356e 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" @@ -1487,7 +1487,7 @@ public enum XCCFileType public class XCCMessageReceiveHelper { private readonly Dictionary xCCFileDictionary = new Dictionary(); - private readonly Dictionary xCCMessageDictionary = new Dictionary(); + private readonly Dictionary> xCCMessageDictionary = new Dictionary>(); /// /// 自动保存到本地 /// @@ -1514,12 +1514,16 @@ await Task.Run(() => { foreach (var groupId in Directory.EnumerateDirectories(SavePathRoot)) { + if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) + { + xCCMessageDictionary.Add(, new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage.xfe"))); + } foreach (var file in Directory.EnumerateFiles($"{SavePathRoot}/{groupId}")) { var filePath = $"{SavePathRoot}/{groupId}/{file}"; if (file == "XFEMessage.xfe") { - xCCMessageDictionary.Add(groupId, new XFEMultiDictionary(File.ReadAllText(filePath))); + } else { @@ -1746,14 +1750,69 @@ public XCCFile(string groupId, string messageId, XCCFileType fileType, string se /// /// XCC消息 /// - public class XCCMessage : XFEEntry + public class XCCMessage { + /// + /// 消息ID + /// + public string MessageId { get; } + /// + /// 消息类型 + /// + public XCCTextMessageType MessageType { get; } + /// + /// 消息内容 + /// + public string Message { get; } + /// + /// 发送者 + /// + public string Sender { get; } + /// + /// 发送时间 + /// + public DateTime SendTime { get; } + /// + /// 群组ID + /// + public string GroupId { get; } + /// + /// 封装为字符串 + /// + /// + public override string ToString() + { + return new string[] { MessageId, MessageType.ToString(), Message, Sender, SendTime.ToString() }.ToXFEString(); + } + /// + /// 将封装后的XCC消息字符串转换为XCC消息对象 + /// + /// + /// + /// + public static XCCMessage ConvertToXCCMessage(string xCCMessageStringFormat, string groupId) + { + var unPackedMessage = xCCMessageStringFormat.ToXFEArray(); + return new XCCMessage(unPackedMessage[0], (XCCTextMessageType)Enum.Parse(typeof(XCCTextMessageType), unPackedMessage[1]), unPackedMessage[2], unPackedMessage[3], DateTime.Parse(unPackedMessage[4]), groupId); + } /// /// XCC消息 /// - /// XCC头 - /// 内容 - public XCCMessage(string Header, string Content) : base(Header, Content) { } + /// 消息ID + /// 消息类型 + /// 消息内容 + /// 发送者 + /// 发送时间 + /// 群组ID + public XCCMessage(string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, string groupId) + { + MessageId = messageId; + MessageType = messageType; + Message = message; + Sender = sender; + SendTime = sendTime; + GroupId = groupId; + } } /// /// XCC网络通讯事件 diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/FormatExtension.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/FormatExtension.cs" index 2558256..6bf856f 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/FormatExtension.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/FormatExtension.cs" @@ -487,6 +487,17 @@ public void CopyTo(XFEEntry[] array, int arrayIndex) xFEMultiDictionaryList.CopyTo(array, arrayIndex); } /// + /// 获取内容 + /// + /// 头 + /// + public List GetContents(string header) + { + var list = new List(); + xFEMultiDictionaryList.FindAll(x => x.Header == header)?.ForEach(y => list.Add(y.Content)); + return list; + } + /// /// 获取索引器 /// /// From 9ca3ad7a488d1f78e764735699692c7448494ca0 Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Thu, 9 Nov 2023 00:15:28 +0800 Subject: [PATCH 03/22] =?UTF-8?q?=E5=B0=86XCC=E7=BD=91=E7=BB=9C=E9=80=9A?= =?UTF-8?q?=E8=AE=AF=E4=BB=8ECyberComm=E6=96=87=E4=BB=B6=E4=B8=AD=E7=8B=AC?= =?UTF-8?q?=E7=AB=8B=E5=87=BA=E6=9D=A5=20XCC=E6=B6=88=E6=81=AF=E6=8E=A5?= =?UTF-8?q?=E6=94=B6=E5=8A=A9=E6=89=8B=E8=BF=9B=E4=B8=80=E6=AD=A5=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CyberComm.cs" | 1188 ---------------- .../XCCNetWork.cs" | 1249 +++++++++++++++++ ...47\261\273\346\213\223\345\261\225.csproj" | 1 + 3 files changed, 1250 insertions(+), 1188 deletions(-) create mode 100644 "XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" index 0a3356e..d563d62 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" @@ -6,7 +6,6 @@ using System.Net; using System.Net.WebSockets; using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using XFE各类拓展.ArrayExtension; @@ -850,1191 +849,4 @@ public CyberCommGroupController() commGroups = new List(); } } - namespace XCCNetWork - { - /// - /// XFE网络通信二进制返回消息类型 - /// - public enum XCCBinaryMessageType - { - /// - /// 文本消息 - /// - Text, - /// - /// 二进制消息 - /// - Binary, - /// - /// 图片消息 - /// - Image, - /// - /// 音频消息 - /// - Audio, - /// - /// 实时音频 - /// - AudioBuffer, - /// - /// 视频消息 - /// - Video - } - /// - /// XFE网络通信明文返回消息类型 - /// - public enum XCCTextMessageType - { - /// - /// 文本消息 - /// - Text, - /// - /// 图片消息 - /// - Image, - /// - /// 音频消息 - /// - Audio, - /// - /// 视频消息 - /// - Video - } - class XCCNetWorkBase - { - /// - /// 明文消息接收时触发 - /// - public EventHandler textMessageReceived; - /// - /// 二进制消息接收时触发 - /// - public EventHandler binaryMessageReceived; - /// - /// 异常消息接收时触发 - /// - public EventHandler exceptionMessageReceived; - /// - /// 连接关闭时触发 - /// - public EventHandler connectionClosed; - /// - /// 连接成功时触发 - /// - public EventHandler connected; - } - /// - /// XCC网络通讯 - /// - public class XCCNetWork - { - private readonly XCCNetWorkBase xCCNetWorkBase; - /// - /// XCC当前群组 - /// - public List Groups { get; set; } - /// - /// 明文消息接收时触发 - /// - public event EventHandler TextMessageReceived - { - add - { - xCCNetWorkBase.textMessageReceived += value; - } - remove - { - xCCNetWorkBase.textMessageReceived -= value; - } - } - /// - /// 二进制消息接收时触发 - /// - public event EventHandler BinaryMessageReceived - { - add - { - xCCNetWorkBase.binaryMessageReceived += value; - } - remove - { - xCCNetWorkBase.binaryMessageReceived -= value; - } - } - /// - /// 异常消息接收时触发 - /// - public event EventHandler ExceptionMessageReceived - { - add - { - xCCNetWorkBase.exceptionMessageReceived += value; - } - remove - { - xCCNetWorkBase.exceptionMessageReceived -= value; - } - } - /// - /// 连接关闭时触发 - /// - public event EventHandler ConnectionClosed - { - add - { - xCCNetWorkBase.connectionClosed += value; - } - remove - { - xCCNetWorkBase.connectionClosed -= value; - } - } - /// - /// 连接成功时触发 - /// - public event EventHandler Connected - { - add - { - xCCNetWorkBase.connected += value; - } - remove - { - xCCNetWorkBase.connected -= value; - } - } - /// - /// 创建XCC群组会话 - /// - /// 群组名称 - /// 发送者 - /// - public XCCGroup CreateGroup(string groupId, string sender) - { - var group = new XCCGroupImpl(groupId, sender, xCCNetWorkBase); - Groups.Add(group); - return group; - } - /// - /// XCC网络通信会话 - /// - public XCCNetWork() - { - xCCNetWorkBase = new XCCNetWorkBase(); - Groups = new List(); - } - } - /// - /// XCC群组 - /// - public abstract class XCCGroup - { - private event EndTaskTrigger UpdateTaskTrigger; - private readonly XCCNetWorkBase workBase; - private int reconnectTimes = -1; - #region 公有属性 - /// - /// 群组ID - /// - public string GroupId { get; } - /// - /// 发送者 - /// - public string Sender { get; } - /// - /// WebSocket客户端 - /// - public ClientWebSocket ClientWebSocket { get; private set; } - /// - /// 是否已连接 - /// - public bool IsConnected { get; private set; } = false; - #endregion - #region 公有方法 - /// - /// 启动XCC会话 - /// - /// 是否自动重连 - /// 最大重连次数,-1则为无限次 - /// 重连尝试延迟 - /// - public async Task StartXCC(bool autoReconnect = true, int reconnectMaxTimes = -1, int reconnectTryDelay = 100) - { - XCCReconnect: - ClientWebSocket = new ClientWebSocket(); - Uri serverUri = new Uri("ws://xcc.api.xfegzs.com"); - var base64GroupId = Convert.ToBase64String(Encoding.UTF8.GetBytes(GroupId)); - var base64SenderId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Sender)); - ClientWebSocket.Options.SetRequestHeader("Group", base64GroupId); - ClientWebSocket.Options.SetRequestHeader("Sender", base64SenderId); - reconnectTimes++; - try - { - await ClientWebSocket.ConnectAsync(serverUri, CancellationToken.None); - } - catch (Exception ex) - { - if (IsConnected == true) - { - workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, false)); - } - IsConnected = false; - if (autoReconnect) - { - if (reconnectTimes <= reconnectMaxTimes || reconnectMaxTimes == -1) - { - Thread.Sleep(reconnectTryDelay); - goto XCCReconnect; - } - } - else - { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("与XCC网络通讯服务器建立连接时发生异常", ex))); - return; - } - } - reconnectTimes = 0; - workBase.connected?.Invoke(this, new XCCConnectedEventArgsImpl(this, ClientWebSocket)); - IsConnected = true; - while (ClientWebSocket.State == WebSocketState.Open) - { - try - { - byte[] receiveBuffer = new byte[1024]; - WebSocketReceiveResult receiveResult = await ClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); - var bufferList = new List(); - bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); - //ReceiveCompletedMessageByUsingWhile - while (!receiveResult.EndOfMessage) - { - receiveResult = await ClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); - bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); - } - var receivedBinaryBuffer = bufferList.ToArray(); - if (receiveResult.MessageType == WebSocketMessageType.Text) - { - try - { - var receivedMessage = Encoding.UTF8.GetString(receivedBinaryBuffer); - var isHistory = receivedMessage.IndexOf("[XCCGetHistory]") == 0; - if (isHistory) - { - receivedMessage = receivedMessage.Substring(15); - } - var unPackedMessage = receivedMessage.ToXFEArray(); - var messageId = unPackedMessage[0]; - var signature = unPackedMessage[1]; - var message = unPackedMessage[2]; - var senderName = unPackedMessage[3]; - var sendTime = DateTime.Parse(unPackedMessage[4]); - var messageType = XCCTextMessageType.Text; - switch (signature) - { - case "[XCCTextMessage]": - messageType = XCCTextMessageType.Text; - break; - case "[XCCImage]": - messageType = XCCTextMessageType.Image; - break; - case "[XCCAudio]": - messageType = XCCTextMessageType.Audio; - break; - case "[XCCVideo]": - messageType = XCCTextMessageType.Video; - break; - default: - break; - } - workBase.textMessageReceived?.Invoke(this, new XCCTextMessageReceivedEventArgsImpl(this, ClientWebSocket, messageId, messageType, message, senderName, sendTime, isHistory)); - } - catch (Exception ex) - { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); - } - } - if (receiveResult.MessageType == WebSocketMessageType.Binary) - { - try - { - var messageType = XCCBinaryMessageType.Binary; - var xFEBuffer = XFEBuffer.ToXFEBuffer(receivedBinaryBuffer); - var sender = Encoding.UTF8.GetString(xFEBuffer["Sender"]); - var signature = Encoding.UTF8.GetString(xFEBuffer["Type"]); - var messageId = Encoding.UTF8.GetString(xFEBuffer["ID"]); - byte[] unPackedBuffer = signature == "callback" ? null : xFEBuffer[sender]; - switch (signature) - { - case "text": - messageType = XCCBinaryMessageType.Text; - break; - case "image": - messageType = XCCBinaryMessageType.Image; - break; - case "audio": - messageType = XCCBinaryMessageType.Audio; - break; - case "audio-buffer": - messageType = XCCBinaryMessageType.AudioBuffer; - break; - case "video": - messageType = XCCBinaryMessageType.Video; - break; - case "callback": - UpdateTaskTrigger?.Invoke(true, messageId); - continue; - default: - messageType = XCCBinaryMessageType.Binary; - break; - } - workBase.binaryMessageReceived?.Invoke(this, new XCCBinaryMessageReceivedEventArgsImpl(this, ClientWebSocket, sender, messageId, unPackedBuffer, messageType, signature)); - } - catch (Exception ex) - { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); - } - } - } - catch (Exception ex) - { - try { await ClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } catch { } - if (IsConnected == true) - { - workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, false)); - } - IsConnected = false; - if (autoReconnect) - { - if (autoReconnect) - { - Thread.Sleep(reconnectTryDelay); - if (reconnectTimes <= reconnectMaxTimes || reconnectMaxTimes == -1) - goto XCCReconnect; - } - } - else - { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("与XCC网络通讯服务器建立连接时发生异常", ex))); - return; - } - } - } - workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, true)); - } - /// - /// 发送文本消息,返回消息ID - /// - /// 待发送的文本 - /// 最长超时时长 - /// 服务器接收校验是否成功 - public async Task SendTextMessage(string message, int timeout = 30000) - { - var messageId = Guid.NewGuid().ToString(); - return await SendTextMessage(message, messageId, timeout); - } - /// - /// 发送文本消息 - /// - /// 待发送的文本 - /// 消息ID - /// 最长超时时长 - /// - /// 服务器接收校验是否成功 - public async Task SendTextMessage(string message, string messageId, int timeout) - { - try - { - byte[] sendBuffer = Encoding.UTF8.GetBytes(new string[] { messageId, "[XCCTextMessage]", message }.ToXFEString()); - await ClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); - var endTask = Task.Run(async () => - { - await Task.Delay(timeout); - UpdateTaskTrigger?.Invoke(false, messageId); - }); - return await new XFEWaitTask(ref UpdateTaskTrigger, messageId); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端发送文本到服务器时出现异常", ex); - } - } - /// - /// 发送标准的文本消息 - /// - /// 发送者角色 - /// 待发送的文本 - /// - /// 服务器接收校验是否成功 - [Obsolete("发送者已统一,请使用SendTextMessage或SendBinaryTextMessage")] - public async Task SendStandardTextMessage(string role, string message) - { - try - { - return await SendTextMessage(message); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端发送文本到服务器时出现异常", ex); - } - } - /// - /// 发送签名二进制消息,返回消息ID - /// - /// 二进制消息 - /// 签名标识 - /// 最长超时时长 - /// 服务器接收校验是否成功 - public async Task SendSignedBinaryMessage(byte[] message, string signature, int timeout = 10000) - { - var messageId = Guid.NewGuid().ToString(); - return await SendSignedBinaryMessage(message, messageId, signature, timeout); - } - /// - /// 发送签名二进制消息 - /// - /// 二进制消息 - /// 消息ID - /// 签名标识 - /// 最长超时时长 - /// 服务器接收校验是否成功 - /// - public async Task SendSignedBinaryMessage(byte[] message, string messageId, string signature, int timeout) - { - try - { - var xFEBuffer = new XFEBuffer(Sender, message, "Type", Encoding.UTF8.GetBytes(signature), "ID", Encoding.UTF8.GetBytes(messageId)); - await ClientWebSocket.SendAsync(new ArraySegment(xFEBuffer.ToBuffer()), WebSocketMessageType.Binary, true, CancellationToken.None); - var endTask = Task.Run(async () => - { - await Task.Delay(timeout); - UpdateTaskTrigger?.Invoke(false, messageId); - }); - return await new XFEWaitTask(ref UpdateTaskTrigger, messageId); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端发送二进制数据到服务器时出现异常", ex); - } - } - /// - /// 发送二进制文本消息 - /// - /// 消息 - /// 服务器接收校验是否成功 - /// - public async Task SendBinaryTextMessage(string message) - { - try - { - return await SendSignedBinaryMessage(Encoding.UTF8.GetBytes(message), "text"); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端发送文本到服务器时出现异常", ex); - } - } - /// - /// 发送默认标准的二进制消息 - /// - /// 待发送的二进制数据 - /// 最长超时时长 - /// - /// 服务器接收校验是否成功 - public async Task SendBinaryMessage(byte[] message, int timeout = 1000) - { - try - { - return await SendSignedBinaryMessage(message, "binary", timeout); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端发送二进制数据到服务器时出现异常", ex); - } - } - /// - /// 发送图片 - /// - /// 图片路径 - /// 服务器接收校验是否成功 - /// - public async Task SendImage(string filePath) - { - try - { - return await SendSignedBinaryMessage(File.ReadAllBytes(filePath), "image", 60000); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端发送图片到服务器时出现异常", ex); - } - } - /// - /// 发送视频 - /// - /// 视频路径 - /// 服务器接收校验是否成功 - /// - public async Task SendVideo(string filePath) - { - try - { - return await SendSignedBinaryMessage(File.ReadAllBytes(filePath), "video", 300000); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端发送视频到服务器时出现异常", ex); - } - } - /// - /// 发送音频 - /// - /// 音频路径 - /// 服务器接收校验是否成功 - /// - public async Task SendAudio(string filePath) - { - try - { - return await SendSignedBinaryMessage(File.ReadAllBytes(filePath), "audio"); - } - catch (Exception ex) { throw new XFECyberCommException("客户端发送音频到服务器时出现异常", ex); } - } - /// - /// 发送音频字节流(服务器不会缓存) - /// - /// 二进制音频流 - /// 服务器接收校验是否成功 - /// - public async Task SendAudioBuffer(byte[] buffer) - { - try - { - return await SendSignedBinaryMessage(buffer, "audio-buffer"); - } - catch (Exception ex) { throw new XFECyberCommException("客户端发送音频到服务器时出现异常", ex); } - } - /// - /// 获取历史记录 - /// - /// - public async Task GetHistory() - { - try - { - var messageId = Guid.NewGuid().ToString(); - byte[] sendBuffer = Encoding.UTF8.GetBytes(new string[] { messageId, "[XCCGetHistory]", "[XCCGetHistory]" }.ToXFEString()); - await ClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); - var endTask = Task.Run(async () => - { - await Task.Delay(5000); - UpdateTaskTrigger?.Invoke(false, messageId); - }); - return await new XFEWaitTask(ref UpdateTaskTrigger, messageId); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端获取历史记录时出现异常", ex); - } - } - /// - /// 关闭XCC会话 - /// - /// - /// - public async Task CloseXCC() - { - try - { - await ClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端关闭连接时出现异常", ex); - } - } - #endregion - internal XCCGroup(string groupId, string sender, XCCNetWorkBase xCCNetWorkBase) - { - GroupId = groupId; - Sender = sender; - workBase = xCCNetWorkBase; - } - } - /// - /// XCC文件类型 - /// - public enum XCCFileType - { - /// - /// 图片 - /// - Image, - /// - /// 视频 - /// - Video, - /// - /// 音频 - /// - Audio - } - /// - /// XCC消息接收器 - /// - public class XCCMessageReceiveHelper - { - private readonly Dictionary xCCFileDictionary = new Dictionary(); - private readonly Dictionary> xCCMessageDictionary = new Dictionary>(); - /// - /// 自动保存到本地 - /// - public bool AutoSaveInLocal { get; set; } - /// - /// 保存的根目录 - /// - public string SavePathRoot { get; set; } - /// - /// 接收到文件事件 - /// - public event EventHandler FileReceived; - /// - /// 接收到文本事件 - /// - public event EventHandler TextReceived; - /// - /// 从设置的根目录加载 - /// - /// - public async Task Load() - { - await Task.Run(() => - { - foreach (var groupId in Directory.EnumerateDirectories(SavePathRoot)) - { - if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) - { - xCCMessageDictionary.Add(, new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage.xfe"))); - } - foreach (var file in Directory.EnumerateFiles($"{SavePathRoot}/{groupId}")) - { - var filePath = $"{SavePathRoot}/{groupId}/{file}"; - if (file == "XFEMessage.xfe") - { - - } - else - { - LoadFile(groupId, filePath); - } - } - } - }); - } - /// - /// 从设置的根目录的指定群组加载 - /// - /// 群组ID - /// - public async Task LoadGroup(string groupId) - { - await Task.Run(() => - { - foreach (var file in Directory.EnumerateFiles($"{SavePathRoot}/{groupId}")) - { - var filePath = $"{SavePathRoot}/{groupId}/{file}"; - if (file == "XFEMessage.xfe") - { - xCCMessageDictionary.Add(groupId, new XFEMultiDictionary(File.ReadAllText(filePath))); - } - else - { - LoadFile(groupId, filePath); - } - } - }); - } - private void LoadFile(string groupId, string filePath) - { - var messageId = Path.GetFileNameWithoutExtension(filePath); - var fileBuffer = File.ReadAllBytes(filePath); - switch (Path.GetExtension(filePath)) - { - case ".png": - xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Image,, fileBuffer)); - break; - case ".mp4": - xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Video, fileBuffer)); - break; - case ".mp3": - xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Audio, fileBuffer)); - break; - default: - break; - } - } - /// - /// 获取文件 - /// - /// 消息ID - /// - public XCCFile GetFile(string messageId) - { - return xCCFileDictionary.ContainsKey(messageId) ? xCCFileDictionary[messageId] : null; - } - /// - /// 添加文件 - /// - /// XCC文件实例 - public void AddFile(XCCFile xCCFile) - { - xCCFileDictionary.Add(xCCFile.MessageId, xCCFile); - if (AutoSaveInLocal && xCCFile.FileBuffer != null) - Save(xCCFile); - } - /// - /// 保存图片 - /// - /// XCC图片实例 - public void Save(XCCFile xCCFile) - { - if (!Directory.Exists($"{SavePathRoot}/{xCCFile.GroupId}")) - { - Directory.CreateDirectory($"{SavePathRoot}/{xCCFile.GroupId}"); - } - switch (xCCFile.FileType) - { - case XCCFileType.Image: - File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.png", xCCFile.FileBuffer); - break; - case XCCFileType.Video: - File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.mp4", xCCFile.FileBuffer); - break; - case XCCFileType.Audio: - File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.mp3", xCCFile.FileBuffer); - break; - default: - break; - } - } - private void ReceiveFilePlaceHolder(XCCTextMessageReceivedEventArgs e, XCCFileType fileType) - { - if (!xCCFileDictionary.ContainsKey(e.MessageId)) - { - xCCFileDictionary.Add(e.MessageId, new XCCFile(e.GroupId, e.MessageId, fileType)); - } - } - /// - /// 接收文本消息 - /// - /// 发送者 - /// 事件参数 - public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) - { - switch (e.MessageType) - { - case XCCTextMessageType.Text: - //xCCMessageDictionary.Add(e.GroupId, new XFEMultiDictionary(e.)); - break; - case XCCTextMessageType.Image: - ReceiveFilePlaceHolder(e, XCCFileType.Image); - break; - case XCCTextMessageType.Audio: - ReceiveFilePlaceHolder(e, XCCFileType.Audio); - break; - case XCCTextMessageType.Video: - ReceiveFilePlaceHolder(e, XCCFileType.Video); - break; - default: - break; - } - } - /// - /// 接收二进制消息 - /// - /// 发送者 - /// 事件参数 - public void ReceiveBinaryMessage(object sender, XCCBinaryMessageReceivedEventArgs e) - { - if (xCCFileDictionary.ContainsKey(e.MessageId)) - { - var xCCFile = xCCFileDictionary[e.MessageId]; - if (!xCCFile.Loaded) - { - xCCFileDictionary[e.MessageId].LoadFile(e.BinaryMessage); - if (AutoSaveInLocal) - Save(xCCFile); - } - } - } - /// - /// XCC消息接收器 - /// - /// 保存根目录 - /// 自动保存 - public XCCMessageReceiveHelper(string savePathRoot, bool autoSaveInLocal = true) - { - AutoSaveInLocal = autoSaveInLocal; - SavePathRoot = savePathRoot; - } - } - /// - /// XCC文件 - /// - public class XCCFile - { - /// - /// 文件加载完成时触发 - /// - public event EventHandler FileLoaded; - /// - /// 群组ID - /// - public string GroupId { get; } - /// - /// 消息ID - /// - public string MessageId { get; } - /// - /// 发送者 - /// - public string Sender { get; } - /// - /// 发送时间 - /// - public DateTime SendTime { get; } - /// - /// XCC文件类型 - /// - public XCCFileType FileType { get; } - /// - /// 是否已加载 - /// - public bool Loaded { get; private set; } - /// - /// 文件流 - /// - public byte[] FileBuffer { get; set; } - /// - /// 加载文件 - /// - /// 文件流 - public void LoadFile(byte[] fileBuffer) - { - FileBuffer = fileBuffer; - Loaded = true; - FileLoaded?.Invoke(this, fileBuffer); - } - /// - /// XCC文件 - /// - /// 群组ID - /// 文件消息ID - /// 文件类型 - /// 发送者 - /// 发送时间 - /// 文件的Buffer - public XCCFile(string groupId, string messageId, XCCFileType fileType, string sender, DateTime sendTime, byte[] fileBuffer = null) - { - GroupId = groupId; - MessageId = messageId; - FileType = fileType; - Sender = sender; - SendTime = sendTime; - FileBuffer = fileBuffer; - Loaded = fileBuffer != null; - } - } - /// - /// XCC消息 - /// - public class XCCMessage - { - /// - /// 消息ID - /// - public string MessageId { get; } - /// - /// 消息类型 - /// - public XCCTextMessageType MessageType { get; } - /// - /// 消息内容 - /// - public string Message { get; } - /// - /// 发送者 - /// - public string Sender { get; } - /// - /// 发送时间 - /// - public DateTime SendTime { get; } - /// - /// 群组ID - /// - public string GroupId { get; } - /// - /// 封装为字符串 - /// - /// - public override string ToString() - { - return new string[] { MessageId, MessageType.ToString(), Message, Sender, SendTime.ToString() }.ToXFEString(); - } - /// - /// 将封装后的XCC消息字符串转换为XCC消息对象 - /// - /// - /// - /// - public static XCCMessage ConvertToXCCMessage(string xCCMessageStringFormat, string groupId) - { - var unPackedMessage = xCCMessageStringFormat.ToXFEArray(); - return new XCCMessage(unPackedMessage[0], (XCCTextMessageType)Enum.Parse(typeof(XCCTextMessageType), unPackedMessage[1]), unPackedMessage[2], unPackedMessage[3], DateTime.Parse(unPackedMessage[4]), groupId); - } - /// - /// XCC消息 - /// - /// 消息ID - /// 消息类型 - /// 消息内容 - /// 发送者 - /// 发送时间 - /// 群组ID - public XCCMessage(string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, string groupId) - { - MessageId = messageId; - MessageType = messageType; - Message = message; - Sender = sender; - SendTime = sendTime; - GroupId = groupId; - } - } - /// - /// XCC网络通讯事件 - /// - public abstract class XCCMessageReceivedEventArgs : EventArgs - { - /// - /// 当前WebSocket - /// - public ClientWebSocket CurrentWebSocket { get; } - /// - /// 触发事件的群组 - /// - public XCCGroup Group { get; } - /// - /// 消息ID - /// - public string MessageId { get; } - /// - /// 群组ID - /// - public string GroupId - { - get - { - return Group.GroupId; - } - } - /// - /// 发送者 - /// - public string Sender { get; } - /// - /// 回复文本消息 - /// - /// 待发送的文本 - /// 发送进程 - public async Task ReplyTextMessage(string message) - { - try - { - byte[] sendBuffer = Encoding.UTF8.GetBytes(message); - await CurrentWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); - } - catch (Exception ex) - { - throw new XFECyberCommException("收到服务器端数据后客户端回复文本数据时出现异常", ex); - } - } - /// - /// 回复二进制消息 - /// - /// 二进制消息 - /// - public async Task ReplyBinaryMessage(byte[] message) - { - try - { - await CurrentWebSocket.SendAsync(new ArraySegment(message), WebSocketMessageType.Binary, true, CancellationToken.None); - } - catch (Exception ex) - { - throw new XFECyberCommException("收到服务器端数据后客户端回复文本数据时出现异常", ex); - } - } - /// - /// 关闭连接 - /// - /// - public async Task Close() - { - try - { - await CurrentWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); - } - catch (Exception ex) - { - throw new XFECyberCommException("客户端关闭连接时出现异常", ex); - } - } - internal XCCMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId) - { - Group = group; - CurrentWebSocket = clientWebSocket; - Sender = sender; - MessageId = messageId; - } - } - /// - /// XCC网络通讯接收到明文消息事件 - /// - public abstract class XCCTextMessageReceivedEventArgs : XCCMessageReceivedEventArgs - { - /// - /// 返回文本消息类型 - /// - public XCCTextMessageType MessageType { get; } - /// - /// 文本消息 - /// - public string TextMessage { get; } - /// - /// 发送时间 - /// - public DateTime SendTime { get; } - /// - /// 是否为历史消息 - /// - public bool IsHistory { get; } - internal XCCTextMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, bool isHistory) : base(group, clientWebSocket, sender, messageId) - { - MessageType = messageType; - TextMessage = message; - SendTime = sendTime; - IsHistory = isHistory; - } - - } - /// - /// XCC网络通讯接收到二进制消息事件 - /// - public abstract class XCCBinaryMessageReceivedEventArgs : XCCMessageReceivedEventArgs - { - /// - /// 返回二进制消息类型 - /// - public XCCBinaryMessageType MessageType { get; } - /// - /// 消息签名 - /// - public string Signature { get; } - /// - /// 二进制消息 - /// - public byte[] BinaryMessage { get; } - internal XCCBinaryMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, clientWebSocket, sender, messageId) - { - BinaryMessage = buffer; - MessageType = messageType; - Signature = signature; - } - } - /// - /// XCC网络通讯期间异常事件 - /// - public abstract class XCCExceptionMessageReceivedEventArgs : XCCMessageReceivedEventArgs - { - /// - /// 异常信息 - /// - public XFECyberCommException Exception { get; } - internal XCCExceptionMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, XFECyberCommException exception) : base(group, clientWebSocket, sender, messageId) - { - Exception = exception; - } - } - /// - /// XCC会话关闭事件 - /// - public abstract class XCCConnectionClosedEventArgs : EventArgs - { - /// - /// 当前WebSocket - /// - public ClientWebSocket CurrentWebSocket { get; } - /// - /// 是否正常关闭 - /// - public bool ClosedNormally { get; } - /// - /// 触发事件的群组 - /// - public XCCGroup Group { get; } - internal XCCConnectionClosedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, bool closeNormally) - { - CurrentWebSocket = clientWebSocket; - Group = group; - ClosedNormally = closeNormally; - } - } - /// - /// XCC连接事件 - /// - public abstract class XCCConnectedEventArgs : EventArgs - { - /// - /// 当前WebSocket - /// - public ClientWebSocket CurrentWebSocket { get; } - /// - /// 触发事件的群组 - /// - public XCCGroup Group { get; } - internal XCCConnectedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket) - { - CurrentWebSocket = clientWebSocket; - Group = group; - } - } - class XCCGroupImpl : XCCGroup - { - internal XCCGroupImpl(string groupId, string sender, XCCNetWorkBase xCCNetWorkBase) : base(groupId, sender, xCCNetWorkBase) { } - } - class XCCConnectionClosedEventArgsImpl : XCCConnectionClosedEventArgs - { - internal XCCConnectionClosedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, bool closeNormally) : base(group, clientWebSocket, closeNormally) { } - } - class XCCConnectedEventArgsImpl : XCCConnectedEventArgs - { - internal XCCConnectedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket) : base(group, clientWebSocket) { } - } - class XCCTextMessageReceivedEventArgsImpl : XCCTextMessageReceivedEventArgs - { - internal XCCTextMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, bool isHistory) : base(group, clientWebSocket, messageId, messageType, message, sender, sendTime, isHistory) { } - } - class XCCBinaryMessageReceivedEventArgsImpl : XCCBinaryMessageReceivedEventArgs - { - internal XCCBinaryMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, clientWebSocket, sender, messageId, buffer, messageType, signature) { } - } - class XCCExceptionMessageReceivedEventArgsImpl : XCCExceptionMessageReceivedEventArgs - { - internal XCCExceptionMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, XFECyberCommException exception) : base(group, clientWebSocket, sender, messageId, exception) { } - } - } } \ No newline at end of file diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" new file mode 100644 index 0000000..d8ffa32 --- /dev/null +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -0,0 +1,1249 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.WebSockets; +using System.Text; +using System.Threading.Tasks; +using System.Threading; +using System; +using XFE各类拓展.ArrayExtension; +using XFE各类拓展.BufferExtension; +using XFE各类拓展.TaskExtension; +using XFE各类拓展; +using XFE各类拓展.FormatExtension; + +namespace XFE各类拓展.CyberComm.XCCNetWork +{ + class XCCNetWorkBase + { + /// + /// 明文消息接收时触发 + /// + public EventHandler textMessageReceived; + /// + /// 二进制消息接收时触发 + /// + public EventHandler binaryMessageReceived; + /// + /// 异常消息接收时触发 + /// + public EventHandler exceptionMessageReceived; + /// + /// 连接关闭时触发 + /// + public EventHandler connectionClosed; + /// + /// 连接成功时触发 + /// + public EventHandler connected; + } + /// + /// XCC网络通讯 + /// + public class XCCNetWork + { + private readonly XCCNetWorkBase xCCNetWorkBase; + /// + /// XCC当前群组 + /// + public List Groups { get; set; } + /// + /// 明文消息接收时触发 + /// + public event EventHandler TextMessageReceived + { + add + { + xCCNetWorkBase.textMessageReceived += value; + } + remove + { + xCCNetWorkBase.textMessageReceived -= value; + } + } + /// + /// 二进制消息接收时触发 + /// + public event EventHandler BinaryMessageReceived + { + add + { + xCCNetWorkBase.binaryMessageReceived += value; + } + remove + { + xCCNetWorkBase.binaryMessageReceived -= value; + } + } + /// + /// 异常消息接收时触发 + /// + public event EventHandler ExceptionMessageReceived + { + add + { + xCCNetWorkBase.exceptionMessageReceived += value; + } + remove + { + xCCNetWorkBase.exceptionMessageReceived -= value; + } + } + /// + /// 连接关闭时触发 + /// + public event EventHandler ConnectionClosed + { + add + { + xCCNetWorkBase.connectionClosed += value; + } + remove + { + xCCNetWorkBase.connectionClosed -= value; + } + } + /// + /// 连接成功时触发 + /// + public event EventHandler Connected + { + add + { + xCCNetWorkBase.connected += value; + } + remove + { + xCCNetWorkBase.connected -= value; + } + } + /// + /// 创建XCC群组会话 + /// + /// 群组名称 + /// 发送者 + /// + public XCCGroup CreateGroup(string groupId, string sender) + { + var group = new XCCGroupImpl(groupId, sender, xCCNetWorkBase); + Groups.Add(group); + return group; + } + /// + /// XCC网络通信会话 + /// + public XCCNetWork() + { + xCCNetWorkBase = new XCCNetWorkBase(); + Groups = new List(); + } + } + /// + /// XCC群组 + /// + public abstract class XCCGroup + { + private event EndTaskTrigger UpdateTaskTrigger; + private readonly XCCNetWorkBase workBase; + private int reconnectTimes = -1; + #region 公有属性 + /// + /// 群组ID + /// + public string GroupId { get; } + /// + /// 发送者 + /// + public string Sender { get; } + /// + /// WebSocket客户端 + /// + public ClientWebSocket ClientWebSocket { get; private set; } + /// + /// 是否已连接 + /// + public bool IsConnected { get; private set; } = false; + #endregion + #region 公有方法 + /// + /// 启动XCC会话 + /// + /// 是否自动重连 + /// 最大重连次数,-1则为无限次 + /// 重连尝试延迟 + /// + public async Task StartXCC(bool autoReconnect = true, int reconnectMaxTimes = -1, int reconnectTryDelay = 100) + { + XCCReconnect: + ClientWebSocket = new ClientWebSocket(); + Uri serverUri = new Uri("ws://xcc.api.xfegzs.com"); + var base64GroupId = Convert.ToBase64String(Encoding.UTF8.GetBytes(GroupId)); + var base64SenderId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Sender)); + ClientWebSocket.Options.SetRequestHeader("Group", base64GroupId); + ClientWebSocket.Options.SetRequestHeader("Sender", base64SenderId); + reconnectTimes++; + try + { + await ClientWebSocket.ConnectAsync(serverUri, CancellationToken.None); + } + catch (Exception ex) + { + if (IsConnected == true) + { + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, false)); + } + IsConnected = false; + if (autoReconnect) + { + if (reconnectTimes <= reconnectMaxTimes || reconnectMaxTimes == -1) + { + Thread.Sleep(reconnectTryDelay); + goto XCCReconnect; + } + } + else + { + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("与XCC网络通讯服务器建立连接时发生异常", ex))); + return; + } + } + reconnectTimes = 0; + workBase.connected?.Invoke(this, new XCCConnectedEventArgsImpl(this, ClientWebSocket)); + IsConnected = true; + while (ClientWebSocket.State == WebSocketState.Open) + { + try + { + byte[] receiveBuffer = new byte[1024]; + WebSocketReceiveResult receiveResult = await ClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); + var bufferList = new List(); + bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); + //ReceiveCompletedMessageByUsingWhile + while (!receiveResult.EndOfMessage) + { + receiveResult = await ClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); + bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); + } + var receivedBinaryBuffer = bufferList.ToArray(); + if (receiveResult.MessageType == WebSocketMessageType.Text) + { + try + { + var receivedMessage = Encoding.UTF8.GetString(receivedBinaryBuffer); + var isHistory = receivedMessage.IndexOf("[XCCGetHistory]") == 0; + if (isHistory) + { + receivedMessage = receivedMessage.Substring(15); + } + var unPackedMessage = receivedMessage.ToXFEArray(); + var messageId = unPackedMessage[0]; + var signature = unPackedMessage[1]; + var message = unPackedMessage[2]; + var senderName = unPackedMessage[3]; + var sendTime = DateTime.Parse(unPackedMessage[4]); + var messageType = XCCTextMessageType.Text; + switch (signature) + { + case "[XCCTextMessage]": + messageType = XCCTextMessageType.Text; + break; + case "[XCCImage]": + messageType = XCCTextMessageType.Image; + break; + case "[XCCAudio]": + messageType = XCCTextMessageType.Audio; + break; + case "[XCCVideo]": + messageType = XCCTextMessageType.Video; + break; + default: + break; + } + workBase.textMessageReceived?.Invoke(this, new XCCTextMessageReceivedEventArgsImpl(this, ClientWebSocket, messageId, messageType, message, senderName, sendTime, isHistory)); + } + catch (Exception ex) + { + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); + } + } + if (receiveResult.MessageType == WebSocketMessageType.Binary) + { + try + { + var messageType = XCCBinaryMessageType.Binary; + var xFEBuffer = XFEBuffer.ToXFEBuffer(receivedBinaryBuffer); + var sender = Encoding.UTF8.GetString(xFEBuffer["Sender"]); + var signature = Encoding.UTF8.GetString(xFEBuffer["Type"]); + var messageId = Encoding.UTF8.GetString(xFEBuffer["ID"]); + byte[] unPackedBuffer = signature == "callback" ? null : xFEBuffer[sender]; + switch (signature) + { + case "text": + messageType = XCCBinaryMessageType.Text; + break; + case "image": + messageType = XCCBinaryMessageType.Image; + break; + case "audio": + messageType = XCCBinaryMessageType.Audio; + break; + case "audio-buffer": + messageType = XCCBinaryMessageType.AudioBuffer; + break; + case "video": + messageType = XCCBinaryMessageType.Video; + break; + case "callback": + UpdateTaskTrigger?.Invoke(true, messageId); + continue; + default: + messageType = XCCBinaryMessageType.Binary; + break; + } + workBase.binaryMessageReceived?.Invoke(this, new XCCBinaryMessageReceivedEventArgsImpl(this, ClientWebSocket, sender, messageId, unPackedBuffer, messageType, signature)); + } + catch (Exception ex) + { + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); + } + } + } + catch (Exception ex) + { + try { await ClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } catch { } + if (IsConnected == true) + { + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, false)); + } + IsConnected = false; + if (autoReconnect) + { + if (autoReconnect) + { + Thread.Sleep(reconnectTryDelay); + if (reconnectTimes <= reconnectMaxTimes || reconnectMaxTimes == -1) + goto XCCReconnect; + } + } + else + { + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("与XCC网络通讯服务器建立连接时发生异常", ex))); + return; + } + } + } + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, true)); + } + /// + /// 发送文本消息,返回消息ID + /// + /// 待发送的文本 + /// 最长超时时长 + /// 服务器接收校验是否成功 + public async Task SendTextMessage(string message, int timeout = 30000) + { + var messageId = Guid.NewGuid().ToString(); + return await SendTextMessage(message, messageId, timeout); + } + /// + /// 发送文本消息 + /// + /// 待发送的文本 + /// 消息ID + /// 最长超时时长 + /// + /// 服务器接收校验是否成功 + public async Task SendTextMessage(string message, string messageId, int timeout) + { + try + { + byte[] sendBuffer = Encoding.UTF8.GetBytes(new string[] { messageId, "[XCCTextMessage]", message }.ToXFEString()); + await ClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); + var endTask = Task.Run(async () => + { + await Task.Delay(timeout); + UpdateTaskTrigger?.Invoke(false, messageId); + }); + return await new XFEWaitTask(ref UpdateTaskTrigger, messageId); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端发送文本到服务器时出现异常", ex); + } + } + /// + /// 发送标准的文本消息 + /// + /// 发送者角色 + /// 待发送的文本 + /// + /// 服务器接收校验是否成功 + [Obsolete("发送者已统一,请使用SendTextMessage或SendBinaryTextMessage")] + public async Task SendStandardTextMessage(string role, string message) + { + try + { + return await SendTextMessage(message); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端发送文本到服务器时出现异常", ex); + } + } + /// + /// 发送签名二进制消息,返回消息ID + /// + /// 二进制消息 + /// 签名标识 + /// 最长超时时长 + /// 服务器接收校验是否成功 + public async Task SendSignedBinaryMessage(byte[] message, string signature, int timeout = 10000) + { + var messageId = Guid.NewGuid().ToString(); + return await SendSignedBinaryMessage(message, messageId, signature, timeout); + } + /// + /// 发送签名二进制消息 + /// + /// 二进制消息 + /// 消息ID + /// 签名标识 + /// 最长超时时长 + /// 服务器接收校验是否成功 + /// + public async Task SendSignedBinaryMessage(byte[] message, string messageId, string signature, int timeout) + { + try + { + var xFEBuffer = new XFEBuffer(Sender, message, "Type", Encoding.UTF8.GetBytes(signature), "ID", Encoding.UTF8.GetBytes(messageId)); + await ClientWebSocket.SendAsync(new ArraySegment(xFEBuffer.ToBuffer()), WebSocketMessageType.Binary, true, CancellationToken.None); + var endTask = Task.Run(async () => + { + await Task.Delay(timeout); + UpdateTaskTrigger?.Invoke(false, messageId); + }); + return await new XFEWaitTask(ref UpdateTaskTrigger, messageId); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端发送二进制数据到服务器时出现异常", ex); + } + } + /// + /// 发送二进制文本消息 + /// + /// 消息 + /// 服务器接收校验是否成功 + /// + public async Task SendBinaryTextMessage(string message) + { + try + { + return await SendSignedBinaryMessage(Encoding.UTF8.GetBytes(message), "text"); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端发送文本到服务器时出现异常", ex); + } + } + /// + /// 发送默认标准的二进制消息 + /// + /// 待发送的二进制数据 + /// 最长超时时长 + /// + /// 服务器接收校验是否成功 + public async Task SendBinaryMessage(byte[] message, int timeout = 1000) + { + try + { + return await SendSignedBinaryMessage(message, "binary", timeout); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端发送二进制数据到服务器时出现异常", ex); + } + } + /// + /// 发送图片 + /// + /// 图片路径 + /// 服务器接收校验是否成功 + /// + public async Task SendImage(string filePath) + { + try + { + return await SendSignedBinaryMessage(File.ReadAllBytes(filePath), "image", 60000); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端发送图片到服务器时出现异常", ex); + } + } + /// + /// 发送视频 + /// + /// 视频路径 + /// 服务器接收校验是否成功 + /// + public async Task SendVideo(string filePath) + { + try + { + return await SendSignedBinaryMessage(File.ReadAllBytes(filePath), "video", 300000); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端发送视频到服务器时出现异常", ex); + } + } + /// + /// 发送音频 + /// + /// 音频路径 + /// 服务器接收校验是否成功 + /// + public async Task SendAudio(string filePath) + { + try + { + return await SendSignedBinaryMessage(File.ReadAllBytes(filePath), "audio"); + } + catch (Exception ex) { throw new XFECyberCommException("客户端发送音频到服务器时出现异常", ex); } + } + /// + /// 发送音频字节流(服务器不会缓存) + /// + /// 二进制音频流 + /// 服务器接收校验是否成功 + /// + public async Task SendAudioBuffer(byte[] buffer) + { + try + { + return await SendSignedBinaryMessage(buffer, "audio-buffer"); + } + catch (Exception ex) { throw new XFECyberCommException("客户端发送音频到服务器时出现异常", ex); } + } + /// + /// 获取历史记录 + /// + /// + public async Task GetHistory() + { + try + { + var messageId = Guid.NewGuid().ToString(); + byte[] sendBuffer = Encoding.UTF8.GetBytes(new string[] { messageId, "[XCCGetHistory]", "[XCCGetHistory]" }.ToXFEString()); + await ClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); + var endTask = Task.Run(async () => + { + await Task.Delay(5000); + UpdateTaskTrigger?.Invoke(false, messageId); + }); + return await new XFEWaitTask(ref UpdateTaskTrigger, messageId); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端获取历史记录时出现异常", ex); + } + } + /// + /// 关闭XCC会话 + /// + /// + /// + public async Task CloseXCC() + { + try + { + await ClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端关闭连接时出现异常", ex); + } + } + #endregion + internal XCCGroup(string groupId, string sender, XCCNetWorkBase xCCNetWorkBase) + { + GroupId = groupId; + Sender = sender; + workBase = xCCNetWorkBase; + } + } + /// + /// XCC文件类型 + /// + public enum XCCFileType + { + /// + /// 图片 + /// + Image, + /// + /// 视频 + /// + Video, + /// + /// 音频 + /// + Audio + } + /// + /// XCC消息接收器 + /// + public class XCCMessageReceiveHelper + { + private readonly Dictionary xCCFileDictionary = new Dictionary(); + private readonly Dictionary> xCCMessageDictionary = new Dictionary>(); + /// + /// 自动保存到本地 + /// + public bool AutoSaveInLocal { get; set; } + /// + /// 保存的根目录 + /// + public string SavePathRoot { get; set; } + /// + /// 接收到文件事件 + /// + public event EventHandler FileReceived; + /// + /// 接收到文本事件 + /// + public event EventHandler TextReceived; + /// + /// 接收到历史文件事件 + /// + public event EventHandler HistoryFileReceived; + /// + /// 接收到历史文本事件 + /// + public event EventHandler HistoryTextReceived; + /// + /// 从设置的根目录加载 + /// + /// + public async Task Load() + { + await Task.Run(() => + { + foreach (var groupId in Directory.EnumerateDirectories(SavePathRoot)) + { + if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) + { + var xCCMessageList = new List(); + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage.xfe"))) + { + xCCMessageList.Add(XCCMessage.ConvertToXCCMessage(entry.Content, groupId)); + } + xCCMessageDictionary.Add(groupId, xCCMessageList); + } + foreach (var file in Directory.EnumerateFiles($"{SavePathRoot}/{groupId}")) + { + var filePath = $"{SavePathRoot}/{groupId}/{file}"; + LoadFile(groupId, filePath); + } + } + }); + } + /// + /// 从设置的根目录的指定群组加载 + /// + /// 群组ID + /// + public async Task LoadGroup(string groupId) + { + await Task.Run(() => + { + if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) + { + var xCCMessageList = new List(); + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage.xfe"))) + { + xCCMessageList.Add(XCCMessage.ConvertToXCCMessage(entry.Content, groupId)); + } + xCCMessageDictionary.Add(groupId, xCCMessageList); + } + foreach (var file in Directory.EnumerateFiles($"{SavePathRoot}/{groupId}")) + { + var filePath = $"{SavePathRoot}/{groupId}/{file}"; + LoadFile(groupId, filePath); + } + }); + } + private void LoadFile(string groupId, string filePath) + { + var messageId = Path.GetFileNameWithoutExtension(filePath); + var fileBuffer = File.ReadAllBytes(filePath); + if (xCCMessageDictionary.ContainsKey(groupId)) + { + var xCCMessage = xCCMessageDictionary[groupId].Find(x => x.MessageId == messageId); + if (xCCMessage == null) + { + File.Delete(filePath); + } + else + { + switch (xCCMessage.MessageType) + { + case XCCTextMessageType.Text: + break; + case XCCTextMessageType.Image: + xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Image, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer)); + break; + case XCCTextMessageType.Audio: + xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Audio, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer)); + break; + case XCCTextMessageType.Video: + xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Video, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer)); + break; + default: + break; + } + } + } + else + { + File.Delete(filePath); + } + } + /// + /// 获取文件 + /// + /// 消息ID + /// + public XCCFile GetFile(string messageId) + { + return xCCFileDictionary.ContainsKey(messageId) ? xCCFileDictionary[messageId] : null; + } + /// + /// 添加文件 + /// + /// XCC文件实例 + public void AddFile(XCCFile xCCFile) + { + xCCFileDictionary.Add(xCCFile.MessageId, xCCFile); + if (AutoSaveInLocal && xCCFile.FileBuffer != null) + SaveFile(xCCFile); + } + /// + /// 保存文件 + /// + /// XCC文件实例 + public void SaveFile(XCCFile xCCFile) + { + if (!Directory.Exists($"{SavePathRoot}/{xCCFile.GroupId}")) + { + Directory.CreateDirectory($"{SavePathRoot}/{xCCFile.GroupId}"); + } + switch (xCCFile.FileType) + { + case XCCFileType.Image: + File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.png", xCCFile.FileBuffer); + break; + case XCCFileType.Video: + File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.mp4", xCCFile.FileBuffer); + break; + case XCCFileType.Audio: + File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.mp3", xCCFile.FileBuffer); + break; + default: + break; + } + } + public void SaveMessage(string groupId) + { + var filePath = $"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe"; + + } + private void ReceiveFilePlaceHolder(XCCTextMessageReceivedEventArgs e, XCCFileType fileType) + { + var xCCFile = new XCCFile(e.GroupId, e.MessageId, fileType, e.Sender, e.SendTime); + if (!xCCFileDictionary.ContainsKey(e.MessageId)) + { + xCCFileDictionary.Add(e.MessageId, xCCFile); + } + if (e.IsHistory) + HistoryFileReceived.Invoke(this, xCCFile); + else + FileReceived.Invoke(this, xCCFile); + } + /// + /// 接收文本消息 + /// + /// 发送者 + /// 事件参数 + public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) + { + var message = new XCCMessage(e.MessageId, e.MessageType, e.TextMessage, e.Sender, e.SendTime, e.GroupId); + if (xCCMessageDictionary.ContainsKey(e.GroupId)) + { + if (xCCMessageDictionary[e.GroupId].Find(x => x.MessageId == e.MessageId) == null) + xCCMessageDictionary[e.GroupId].Add(message); + } + else + { + xCCMessageDictionary.Add(e.GroupId, new List() { message }); + } + switch (e.MessageType) + { + case XCCTextMessageType.Text: + if (e.IsHistory) + HistoryTextReceived.Invoke(this, message); + else + TextReceived.Invoke(this, message); + break; + case XCCTextMessageType.Image: + ReceiveFilePlaceHolder(e, XCCFileType.Image); + break; + case XCCTextMessageType.Audio: + ReceiveFilePlaceHolder(e, XCCFileType.Audio); + break; + case XCCTextMessageType.Video: + ReceiveFilePlaceHolder(e, XCCFileType.Video); + break; + default: + break; + } + } + /// + /// 接收二进制消息 + /// + /// 发送者 + /// 事件参数 + public void ReceiveBinaryMessage(object sender, XCCBinaryMessageReceivedEventArgs e) + { + if (xCCFileDictionary.ContainsKey(e.MessageId)) + { + var xCCFile = xCCFileDictionary[e.MessageId]; + if (!xCCFile.Loaded) + { + xCCFileDictionary[e.MessageId].LoadFile(e.BinaryMessage); + if (AutoSaveInLocal) + SaveFile(xCCFile); + } + } + } + /// + /// XCC消息接收器 + /// + /// 保存根目录 + /// 自动保存 + public XCCMessageReceiveHelper(string savePathRoot, bool autoSaveInLocal = true) + { + AutoSaveInLocal = autoSaveInLocal; + SavePathRoot = savePathRoot; + } + } + /// + /// XCC文件 + /// + public class XCCFile + { + /// + /// 文件加载完成时触发 + /// + public event EventHandler FileLoaded; + /// + /// 群组ID + /// + public string GroupId { get; } + /// + /// 消息ID + /// + public string MessageId { get; } + /// + /// 发送者 + /// + public string Sender { get; } + /// + /// 发送时间 + /// + public DateTime SendTime { get; } + /// + /// XCC文件类型 + /// + public XCCFileType FileType { get; } + /// + /// 是否已加载 + /// + public bool Loaded { get; private set; } + /// + /// 文件流 + /// + public byte[] FileBuffer { get; set; } + /// + /// 加载文件 + /// + /// 文件流 + public void LoadFile(byte[] fileBuffer) + { + FileBuffer = fileBuffer; + Loaded = true; + FileLoaded?.Invoke(this, fileBuffer); + } + /// + /// XCC文件 + /// + /// 群组ID + /// 文件消息ID + /// 文件类型 + /// 发送者 + /// 发送时间 + /// 文件的Buffer + public XCCFile(string groupId, string messageId, XCCFileType fileType, string sender, DateTime sendTime, byte[] fileBuffer = null) + { + GroupId = groupId; + MessageId = messageId; + FileType = fileType; + Sender = sender; + SendTime = sendTime; + FileBuffer = fileBuffer; + Loaded = fileBuffer != null; + } + } + /// + /// XCC消息 + /// + public class XCCMessage + { + /// + /// 消息ID + /// + public string MessageId { get; } + /// + /// 消息类型 + /// + public XCCTextMessageType MessageType { get; } + /// + /// 消息内容 + /// + public string Message { get; } + /// + /// 发送者 + /// + public string Sender { get; } + /// + /// 发送时间 + /// + public DateTime SendTime { get; } + /// + /// 群组ID + /// + public string GroupId { get; } + /// + /// 封装为字符串 + /// + /// + public override string ToString() + { + return new string[] { MessageId, MessageType.ToString(), Message, Sender, SendTime.ToString() }.ToXFEString(); + } + /// + /// 将封装后的XCC消息字符串转换为XCC消息对象 + /// + /// + /// + /// + public static XCCMessage ConvertToXCCMessage(string xCCMessageStringFormat, string groupId) + { + var unPackedMessage = xCCMessageStringFormat.ToXFEArray(); + return new XCCMessage(unPackedMessage[0], (XCCTextMessageType)Enum.Parse(typeof(XCCTextMessageType), unPackedMessage[1]), unPackedMessage[2], unPackedMessage[3], DateTime.Parse(unPackedMessage[4]), groupId); + } + /// + /// XCC消息 + /// + /// 消息ID + /// 消息类型 + /// 消息内容 + /// 发送者 + /// 发送时间 + /// 群组ID + public XCCMessage(string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, string groupId) + { + MessageId = messageId; + MessageType = messageType; + Message = message; + Sender = sender; + SendTime = sendTime; + GroupId = groupId; + } + } + /// + /// XCC网络通讯事件 + /// + public abstract class XCCMessageReceivedEventArgs : EventArgs + { + /// + /// 当前WebSocket + /// + public ClientWebSocket CurrentWebSocket { get; } + /// + /// 触发事件的群组 + /// + public XCCGroup Group { get; } + /// + /// 消息ID + /// + public string MessageId { get; } + /// + /// 群组ID + /// + public string GroupId + { + get + { + return Group.GroupId; + } + } + /// + /// 发送者 + /// + public string Sender { get; } + /// + /// 回复文本消息 + /// + /// 待发送的文本 + /// 发送进程 + public async Task ReplyTextMessage(string message) + { + try + { + byte[] sendBuffer = Encoding.UTF8.GetBytes(message); + await CurrentWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); + } + catch (Exception ex) + { + throw new XFECyberCommException("收到服务器端数据后客户端回复文本数据时出现异常", ex); + } + } + /// + /// 回复二进制消息 + /// + /// 二进制消息 + /// + public async Task ReplyBinaryMessage(byte[] message) + { + try + { + await CurrentWebSocket.SendAsync(new ArraySegment(message), WebSocketMessageType.Binary, true, CancellationToken.None); + } + catch (Exception ex) + { + throw new XFECyberCommException("收到服务器端数据后客户端回复文本数据时出现异常", ex); + } + } + /// + /// 关闭连接 + /// + /// + public async Task Close() + { + try + { + await CurrentWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); + } + catch (Exception ex) + { + throw new XFECyberCommException("客户端关闭连接时出现异常", ex); + } + } + internal XCCMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId) + { + Group = group; + CurrentWebSocket = clientWebSocket; + Sender = sender; + MessageId = messageId; + } + } + /// + /// XFE网络通信明文返回消息类型 + /// + public enum XCCTextMessageType + { + /// + /// 文本消息 + /// + Text, + /// + /// 图片消息 + /// + Image, + /// + /// 音频消息 + /// + Audio, + /// + /// 视频消息 + /// + Video + } + /// + /// XCC网络通讯接收到明文消息事件 + /// + public abstract class XCCTextMessageReceivedEventArgs : XCCMessageReceivedEventArgs + { + /// + /// 返回文本消息类型 + /// + public XCCTextMessageType MessageType { get; } + /// + /// 文本消息 + /// + public string TextMessage { get; } + /// + /// 发送时间 + /// + public DateTime SendTime { get; } + /// + /// 是否为历史消息 + /// + public bool IsHistory { get; } + internal XCCTextMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, bool isHistory) : base(group, clientWebSocket, sender, messageId) + { + MessageType = messageType; + TextMessage = message; + SendTime = sendTime; + IsHistory = isHistory; + } + + } + /// + /// XFE网络通信二进制返回消息类型 + /// + public enum XCCBinaryMessageType + { + /// + /// 文本消息 + /// + Text, + /// + /// 二进制消息 + /// + Binary, + /// + /// 图片消息 + /// + Image, + /// + /// 音频消息 + /// + Audio, + /// + /// 实时音频 + /// + AudioBuffer, + /// + /// 视频消息 + /// + Video + } + /// + /// XCC网络通讯接收到二进制消息事件 + /// + public abstract class XCCBinaryMessageReceivedEventArgs : XCCMessageReceivedEventArgs + { + /// + /// 返回二进制消息类型 + /// + public XCCBinaryMessageType MessageType { get; } + /// + /// 消息签名 + /// + public string Signature { get; } + /// + /// 二进制消息 + /// + public byte[] BinaryMessage { get; } + internal XCCBinaryMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, clientWebSocket, sender, messageId) + { + BinaryMessage = buffer; + MessageType = messageType; + Signature = signature; + } + } + /// + /// XCC网络通讯期间异常事件 + /// + public abstract class XCCExceptionMessageReceivedEventArgs : XCCMessageReceivedEventArgs + { + /// + /// 异常信息 + /// + public XFECyberCommException Exception { get; } + internal XCCExceptionMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, XFECyberCommException exception) : base(group, clientWebSocket, sender, messageId) + { + Exception = exception; + } + } + /// + /// XCC会话关闭事件 + /// + public abstract class XCCConnectionClosedEventArgs : EventArgs + { + /// + /// 当前WebSocket + /// + public ClientWebSocket CurrentWebSocket { get; } + /// + /// 是否正常关闭 + /// + public bool ClosedNormally { get; } + /// + /// 触发事件的群组 + /// + public XCCGroup Group { get; } + internal XCCConnectionClosedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, bool closeNormally) + { + CurrentWebSocket = clientWebSocket; + Group = group; + ClosedNormally = closeNormally; + } + } + /// + /// XCC连接事件 + /// + public abstract class XCCConnectedEventArgs : EventArgs + { + /// + /// 当前WebSocket + /// + public ClientWebSocket CurrentWebSocket { get; } + /// + /// 触发事件的群组 + /// + public XCCGroup Group { get; } + internal XCCConnectedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket) + { + CurrentWebSocket = clientWebSocket; + Group = group; + } + } + class XCCGroupImpl : XCCGroup + { + internal XCCGroupImpl(string groupId, string sender, XCCNetWorkBase xCCNetWorkBase) : base(groupId, sender, xCCNetWorkBase) { } + } + class XCCConnectionClosedEventArgsImpl : XCCConnectionClosedEventArgs + { + internal XCCConnectionClosedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, bool closeNormally) : base(group, clientWebSocket, closeNormally) { } + } + class XCCConnectedEventArgsImpl : XCCConnectedEventArgs + { + internal XCCConnectedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket) : base(group, clientWebSocket) { } + } + class XCCTextMessageReceivedEventArgsImpl : XCCTextMessageReceivedEventArgs + { + internal XCCTextMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, bool isHistory) : base(group, clientWebSocket, messageId, messageType, message, sender, sendTime, isHistory) { } + } + class XCCBinaryMessageReceivedEventArgsImpl : XCCBinaryMessageReceivedEventArgs + { + internal XCCBinaryMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, clientWebSocket, sender, messageId, buffer, messageType, signature) { } + } + class XCCExceptionMessageReceivedEventArgsImpl : XCCExceptionMessageReceivedEventArgs + { + internal XCCExceptionMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, XFECyberCommException exception) : base(group, clientWebSocket, sender, messageId, exception) { } + } +} \ No newline at end of file diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFE\345\220\204\347\261\273\346\213\223\345\261\225.csproj" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFE\345\220\204\347\261\273\346\213\223\345\261\225.csproj" index 3b171d4..dfee12e 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFE\345\220\204\347\261\273\346\213\223\345\261\225.csproj" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFE\345\220\204\347\261\273\346\213\223\345\261\225.csproj" @@ -63,6 +63,7 @@ + From ee918dfeacc6a81da7a2c8f04b8540c31556447e Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Thu, 9 Nov 2023 02:14:55 +0800 Subject: [PATCH 04/22] =?UTF-8?q?=E5=AE=8C=E5=96=84XCC=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E5=8A=A9=E6=89=8B=20=E7=8E=B0=E5=9C=A8?= =?UTF-8?q?=EF=BC=8CXCC=E6=B6=88=E6=81=AF=E6=8E=A5=E6=94=B6=E5=8A=A9?= =?UTF-8?q?=E6=89=8B=E5=8F=AF=E4=BB=A5=E5=AE=8C=E6=95=B4=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E6=B6=88=E6=81=AF=E7=9A=84=E6=9C=AC=E5=9C=B0=E5=82=A8?= =?UTF-8?q?=E5=AD=98=E5=92=8C=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CyberComm.cs" | 5 ---- .../XCCNetWork.cs" | 24 ++++++++++++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" index d563d62..45c72d8 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" @@ -1,17 +1,12 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; -using System.IO; using System.Linq; using System.Net; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using XFE各类拓展.ArrayExtension; -using XFE各类拓展.BufferExtension; -using XFE各类拓展.FormatExtension; -using XFE各类拓展.TaskExtension; namespace XFE各类拓展.CyberComm { diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index d8ffa32..e3b543e 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -1,16 +1,15 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.WebSockets; using System.Text; -using System.Threading.Tasks; using System.Threading; -using System; +using System.Threading.Tasks; using XFE各类拓展.ArrayExtension; using XFE各类拓展.BufferExtension; -using XFE各类拓展.TaskExtension; -using XFE各类拓展; using XFE各类拓展.FormatExtension; +using XFE各类拓展.TaskExtension; namespace XFE各类拓展.CyberComm.XCCNetWork { @@ -754,10 +753,19 @@ public void SaveFile(XCCFile xCCFile) break; } } + /// + /// 保存群组消息 + /// + /// public void SaveMessage(string groupId) { var filePath = $"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe"; - + var storageDictionary = new XFEDictionary(); + foreach (var xCCMessage in xCCMessageDictionary[groupId]) + { + storageDictionary.Add(xCCMessage.MessageId, xCCMessage.ToString()); + } + File.WriteAllText(filePath, storageDictionary.ToString()); } private void ReceiveFilePlaceHolder(XCCTextMessageReceivedEventArgs e, XCCFileType fileType) { @@ -770,6 +778,8 @@ private void ReceiveFilePlaceHolder(XCCTextMessageReceivedEventArgs e, XCCFileTy HistoryFileReceived.Invoke(this, xCCFile); else FileReceived.Invoke(this, xCCFile); + if (AutoSaveInLocal) + SaveMessage(e.GroupId); } /// /// 接收文本消息 @@ -795,6 +805,8 @@ public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) HistoryTextReceived.Invoke(this, message); else TextReceived.Invoke(this, message); + if (AutoSaveInLocal) + SaveMessage(e.GroupId); break; case XCCTextMessageType.Image: ReceiveFilePlaceHolder(e, XCCFileType.Image); From 9ba6d0ded48cde8d351e8a02ec17c6cccd54ba35 Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Thu, 9 Nov 2023 02:25:12 +0800 Subject: [PATCH 05/22] =?UTF-8?q?XCC=E6=B6=88=E6=81=AF=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=E5=8A=A9=E6=89=8B=E7=8E=B0=E5=9C=A8=E6=94=AF=E6=8C=81=E4=BC=A0?= =?UTF-8?q?=E5=85=A5XCCNetWork=E5=AE=9E=E4=BE=8B=E6=9D=A5=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=BB=91=E5=AE=9A=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index e3b543e..91f4d04 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -849,6 +849,19 @@ public XCCMessageReceiveHelper(string savePathRoot, bool autoSaveInLocal = true) AutoSaveInLocal = autoSaveInLocal; SavePathRoot = savePathRoot; } + /// + /// XCC消息接收器 + /// + /// 保存根目录 + /// XCC网络通讯实例 + /// 自动保存 + public XCCMessageReceiveHelper(string savePathRoot, XCCNetWork xCCNetWork, bool autoSaveInLocal = true) + { + AutoSaveInLocal = autoSaveInLocal; + SavePathRoot = savePathRoot; + xCCNetWork.TextMessageReceived += ReceiveTextMessage; + xCCNetWork.BinaryMessageReceived += ReceiveBinaryMessage; + } } /// /// XCC文件 From 2421ef98837e1cb232a97afd4f6347205283e42e Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Thu, 9 Nov 2023 02:39:30 +0800 Subject: [PATCH 06/22] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=8F=91=E9=80=81=E9=80=94=E5=BE=84=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=B5=B7=E6=9D=A5=E6=9B=B4=E5=8A=A0=E7=AE=80?= =?UTF-8?q?=E6=B4=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 91f4d04..659a118 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -591,6 +591,13 @@ public enum XCCFileType Audio } /// + /// 消息接收触发器 + /// + /// + /// 是否为历史消息 + /// 消息 + public delegate void MessageReceivedHandler(bool isHistory, T message); + /// /// XCC消息接收器 /// public class XCCMessageReceiveHelper @@ -608,19 +615,11 @@ public class XCCMessageReceiveHelper /// /// 接收到文件事件 /// - public event EventHandler FileReceived; + public event MessageReceivedHandler FileReceived; /// /// 接收到文本事件 /// - public event EventHandler TextReceived; - /// - /// 接收到历史文件事件 - /// - public event EventHandler HistoryFileReceived; - /// - /// 接收到历史文本事件 - /// - public event EventHandler HistoryTextReceived; + public event MessageReceivedHandler TextReceived; /// /// 从设置的根目录加载 /// @@ -774,10 +773,7 @@ private void ReceiveFilePlaceHolder(XCCTextMessageReceivedEventArgs e, XCCFileTy { xCCFileDictionary.Add(e.MessageId, xCCFile); } - if (e.IsHistory) - HistoryFileReceived.Invoke(this, xCCFile); - else - FileReceived.Invoke(this, xCCFile); + FileReceived.Invoke(e.IsHistory, xCCFile); if (AutoSaveInLocal) SaveMessage(e.GroupId); } @@ -801,10 +797,7 @@ public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) switch (e.MessageType) { case XCCTextMessageType.Text: - if (e.IsHistory) - HistoryTextReceived.Invoke(this, message); - else - TextReceived.Invoke(this, message); + TextReceived.Invoke(e.IsHistory, message); if (AutoSaveInLocal) SaveMessage(e.GroupId); break; From d5016a7d16c64f5a2aa0e43af86ca3a0593ac649 Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Thu, 9 Nov 2023 02:52:43 +0800 Subject: [PATCH 07/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8DXCC=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E5=8A=A9=E6=89=8B=E4=B8=AD=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=E5=B0=B1=E5=82=A8=E5=AD=98=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=87=BA=E9=94=99=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 659a118..00cabd3 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -758,13 +758,17 @@ public void SaveFile(XCCFile xCCFile) /// public void SaveMessage(string groupId) { - var filePath = $"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe"; + var filePath = $"{SavePathRoot}/{groupId}/XFEMessage"; + if (!Directory.Exists(filePath)) + { + Directory.CreateDirectory(filePath); + } var storageDictionary = new XFEDictionary(); foreach (var xCCMessage in xCCMessageDictionary[groupId]) { storageDictionary.Add(xCCMessage.MessageId, xCCMessage.ToString()); } - File.WriteAllText(filePath, storageDictionary.ToString()); + File.WriteAllText(filePath + "/XFEMessage.xfe", storageDictionary.ToString()); } private void ReceiveFilePlaceHolder(XCCTextMessageReceivedEventArgs e, XCCFileType fileType) { From 4f8c0ca37f298aea2bfe8eb6c9a610365fe66b60 Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Thu, 9 Nov 2023 03:37:22 +0800 Subject: [PATCH 08/22] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E7=BB=93=E6=9E=84=EF=BC=8C=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=8F=91=E9=80=81=E6=AC=A1=E5=BA=8F=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B8=85=E7=90=86=E6=97=A0=E7=94=A8=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 111 +++++++++--------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 00cabd3..199c406 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -4,6 +4,7 @@ using System.Linq; using System.Net.WebSockets; using System.Text; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using XFE各类拓展.ArrayExtension; @@ -604,6 +605,7 @@ public class XCCMessageReceiveHelper { private readonly Dictionary xCCFileDictionary = new Dictionary(); private readonly Dictionary> xCCMessageDictionary = new Dictionary>(); + private bool loaded = false; /// /// 自动保存到本地 /// @@ -635,17 +637,18 @@ await Task.Run(() => var xCCMessageList = new List(); foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage.xfe"))) { - xCCMessageList.Add(XCCMessage.ConvertToXCCMessage(entry.Content, groupId)); + var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); + xCCMessageList.Add(xCCMessage); + if (xCCMessage.MessageType == XCCTextMessageType.Text) + TextReceived?.Invoke(true, xCCMessage); + else + LoadFile(xCCMessage); } xCCMessageDictionary.Add(groupId, xCCMessageList); } - foreach (var file in Directory.EnumerateFiles($"{SavePathRoot}/{groupId}")) - { - var filePath = $"{SavePathRoot}/{groupId}/{file}"; - LoadFile(groupId, filePath); - } } }); + loaded = true; } /// /// 从设置的根目录的指定群组加载 @@ -661,52 +664,63 @@ await Task.Run(() => var xCCMessageList = new List(); foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage.xfe"))) { - xCCMessageList.Add(XCCMessage.ConvertToXCCMessage(entry.Content, groupId)); + var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); + xCCMessageList.Add(xCCMessage); + if (xCCMessage.MessageType == XCCTextMessageType.Text) + TextReceived?.Invoke(true, xCCMessage); + else + LoadFile(xCCMessage); } xCCMessageDictionary.Add(groupId, xCCMessageList); } - foreach (var file in Directory.EnumerateFiles($"{SavePathRoot}/{groupId}")) - { - var filePath = $"{SavePathRoot}/{groupId}/{file}"; - LoadFile(groupId, filePath); - } }); + loaded = true; } - private void LoadFile(string groupId, string filePath) + /// + /// 清理无用文件 + /// + /// + public async Task ClearUselessFile() { - var messageId = Path.GetFileNameWithoutExtension(filePath); - var fileBuffer = File.ReadAllBytes(filePath); - if (xCCMessageDictionary.ContainsKey(groupId)) + if (!loaded) + throw new XFEExtensionException("不能在加载完成前调用清理"); + await Task.Run(() => { - var xCCMessage = xCCMessageDictionary[groupId].Find(x => x.MessageId == messageId); - if (xCCMessage == null) + foreach (var groupId in xCCMessageDictionary.Keys) { - File.Delete(filePath); - } - else - { - switch (xCCMessage.MessageType) + foreach (var file in Directory.EnumerateFiles($"{SavePathRoot}/{groupId}")) { - case XCCTextMessageType.Text: - break; - case XCCTextMessageType.Image: - xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Image, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer)); - break; - case XCCTextMessageType.Audio: - xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Audio, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer)); - break; - case XCCTextMessageType.Video: - xCCFileDictionary.Add(messageId, new XCCFile(groupId, messageId, XCCFileType.Video, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer)); - break; - default: - break; + var filePath = $"{SavePathRoot}/{groupId}/{file}"; + var messageId = Path.GetFileNameWithoutExtension(filePath); + if (!xCCMessageDictionary.ContainsKey(groupId) || xCCMessageDictionary[groupId].Find(x => x.MessageId == messageId) == null) + { + File.Delete(filePath); + } } } - } - else + }); + } + private XCCFile LoadFile(XCCMessage xCCMessage) + { + var filePath = $"{SavePathRoot}/{xCCMessage.GroupId}/{xCCMessage.MessageId}"; + var fileBuffer = File.ReadAllBytes(filePath); + XCCFile xCCFile = null; + switch (xCCMessage.MessageType) { - File.Delete(filePath); + case XCCTextMessageType.Image: + xCCFile = new XCCFile(xCCMessage.GroupId, xCCMessage.MessageId, XCCFileType.Image, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer); + break; + case XCCTextMessageType.Audio: + xCCFile = new XCCFile(xCCMessage.GroupId, xCCMessage.MessageId, XCCFileType.Audio, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer); + break; + case XCCTextMessageType.Video: + xCCFile = new XCCFile(xCCMessage.GroupId, xCCMessage.MessageId, XCCFileType.Video, xCCMessage.Sender, xCCMessage.SendTime, fileBuffer); + break; + default: + return null; } + xCCFileDictionary.Add(xCCMessage.MessageId, xCCFile); + return xCCFile; } /// /// 获取文件 @@ -737,20 +751,7 @@ public void SaveFile(XCCFile xCCFile) { Directory.CreateDirectory($"{SavePathRoot}/{xCCFile.GroupId}"); } - switch (xCCFile.FileType) - { - case XCCFileType.Image: - File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.png", xCCFile.FileBuffer); - break; - case XCCFileType.Video: - File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.mp4", xCCFile.FileBuffer); - break; - case XCCFileType.Audio: - File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.mp3", xCCFile.FileBuffer); - break; - default: - break; - } + File.WriteAllBytes($"{SavePathRoot}/{xCCFile.GroupId}/{xCCFile.MessageId}.xfe", xCCFile.FileBuffer); } /// /// 保存群组消息 @@ -777,7 +778,7 @@ private void ReceiveFilePlaceHolder(XCCTextMessageReceivedEventArgs e, XCCFileTy { xCCFileDictionary.Add(e.MessageId, xCCFile); } - FileReceived.Invoke(e.IsHistory, xCCFile); + FileReceived?.Invoke(e.IsHistory, xCCFile); if (AutoSaveInLocal) SaveMessage(e.GroupId); } @@ -801,7 +802,7 @@ public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) switch (e.MessageType) { case XCCTextMessageType.Text: - TextReceived.Invoke(e.IsHistory, message); + TextReceived?.Invoke(e.IsHistory, message); if (AutoSaveInLocal) SaveMessage(e.GroupId); break; From 1abc9aeea50022a90e43c718b6f0108e1d47e252 Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Thu, 9 Nov 2023 03:42:37 +0800 Subject: [PATCH 09/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 199c406..c946e22 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -635,14 +635,14 @@ await Task.Run(() => if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) { var xCCMessageList = new List(); - foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage.xfe"))) + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe"))) { var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); xCCMessageList.Add(xCCMessage); if (xCCMessage.MessageType == XCCTextMessageType.Text) TextReceived?.Invoke(true, xCCMessage); else - LoadFile(xCCMessage); + FileReceived?.Invoke(true, LoadFile(xCCMessage)); } xCCMessageDictionary.Add(groupId, xCCMessageList); } @@ -662,7 +662,7 @@ await Task.Run(() => if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) { var xCCMessageList = new List(); - foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage.xfe"))) + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe"))) { var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); xCCMessageList.Add(xCCMessage); From 0ff86e0c60490e4fe9ea642acc8056d9ea5656ee Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Thu, 9 Nov 2023 04:01:41 +0800 Subject: [PATCH 10/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=82=A8=E5=AD=98?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E9=83=A8=E5=88=86bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index c946e22..f2873c9 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -632,10 +632,11 @@ await Task.Run(() => { foreach (var groupId in Directory.EnumerateDirectories(SavePathRoot)) { - if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) + if (File.Exists($"{groupId}/XFEMessage/XFEMessage.xfe")) { + Console.WriteLine("有XCC消息"); var xCCMessageList = new List(); - foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe"))) + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{groupId}/XFEMessage/XFEMessage.xfe"))) { var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); xCCMessageList.Add(xCCMessage); @@ -643,6 +644,7 @@ await Task.Run(() => TextReceived?.Invoke(true, xCCMessage); else FileReceived?.Invoke(true, LoadFile(xCCMessage)); + Console.WriteLine("实际有"); } xCCMessageDictionary.Add(groupId, xCCMessageList); } @@ -659,17 +661,17 @@ public async Task LoadGroup(string groupId) { await Task.Run(() => { - if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) + if (File.Exists($"{groupId}/XFEMessage/XFEMessage.xfe")) { var xCCMessageList = new List(); - foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe"))) + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{groupId}/XFEMessage/XFEMessage.xfe"))) { var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); xCCMessageList.Add(xCCMessage); if (xCCMessage.MessageType == XCCTextMessageType.Text) TextReceived?.Invoke(true, xCCMessage); else - LoadFile(xCCMessage); + FileReceived?.Invoke(true, LoadFile(xCCMessage)); } xCCMessageDictionary.Add(groupId, xCCMessageList); } From a76380deb94eba06cb2973588a3df52c8b3fd3c6 Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Thu, 9 Nov 2023 14:04:09 +0800 Subject: [PATCH 11/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E5=A4=84bug?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=E6=B6=88=E6=81=AF=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index f2873c9..36b3b4b 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -4,7 +4,6 @@ using System.Linq; using System.Net.WebSockets; using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using XFE各类拓展.ArrayExtension; @@ -630,25 +629,30 @@ public async Task Load() { await Task.Run(() => { - foreach (var groupId in Directory.EnumerateDirectories(SavePathRoot)) + if (Directory.Exists(SavePathRoot)) { - if (File.Exists($"{groupId}/XFEMessage/XFEMessage.xfe")) + foreach (var groupId in Directory.EnumerateDirectories(SavePathRoot)) { - Console.WriteLine("有XCC消息"); - var xCCMessageList = new List(); - foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{groupId}/XFEMessage/XFEMessage.xfe"))) + if (File.Exists($"{groupId}/XFEMessage/XFEMessage.xfe")) { - var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); - xCCMessageList.Add(xCCMessage); - if (xCCMessage.MessageType == XCCTextMessageType.Text) - TextReceived?.Invoke(true, xCCMessage); - else - FileReceived?.Invoke(true, LoadFile(xCCMessage)); - Console.WriteLine("实际有"); + var xCCMessageList = new List(); + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{groupId}/XFEMessage/XFEMessage.xfe"))) + { + var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); + xCCMessageList.Add(xCCMessage); + if (xCCMessage.MessageType == XCCTextMessageType.Text) + TextReceived?.Invoke(true, xCCMessage); + else + FileReceived?.Invoke(true, LoadFile(xCCMessage)); + } + xCCMessageDictionary.Add(groupId, xCCMessageList); } - xCCMessageDictionary.Add(groupId, xCCMessageList); } } + else + { + Directory.CreateDirectory(SavePathRoot); + } }); loaded = true; } @@ -796,6 +800,8 @@ public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) { if (xCCMessageDictionary[e.GroupId].Find(x => x.MessageId == e.MessageId) == null) xCCMessageDictionary[e.GroupId].Add(message); + else + return; } else { From fe9b3b497da074ba02cc69df6f7bcc86d21cb08d Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Thu, 9 Nov 2023 14:31:21 +0800 Subject: [PATCH 12/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B0=91=E9=87=8Fbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 36b3b4b..c374519 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -645,7 +645,7 @@ await Task.Run(() => else FileReceived?.Invoke(true, LoadFile(xCCMessage)); } - xCCMessageDictionary.Add(groupId, xCCMessageList); + xCCMessageDictionary.Add(Path.GetFileName(groupId), xCCMessageList); } } } @@ -677,7 +677,7 @@ await Task.Run(() => else FileReceived?.Invoke(true, LoadFile(xCCMessage)); } - xCCMessageDictionary.Add(groupId, xCCMessageList); + xCCMessageDictionary.Add(Path.GetFileName(groupId), xCCMessageList); } }); loaded = true; @@ -799,9 +799,13 @@ public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) if (xCCMessageDictionary.ContainsKey(e.GroupId)) { if (xCCMessageDictionary[e.GroupId].Find(x => x.MessageId == e.MessageId) == null) + { xCCMessageDictionary[e.GroupId].Add(message); + } else + { return; + } } else { From 55d5c56f408b190cde8c5ad3405406dee752968f Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Thu, 9 Nov 2023 14:38:43 +0800 Subject: [PATCH 13/22] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=A7=94=E6=89=98?= =?UTF-8?q?=E6=8B=93=E5=B1=95=EF=BC=9A=20=E4=BD=BF=E7=94=A8XFE=E5=A7=94?= =?UTF-8?q?=E6=89=98=E4=BA=8B=E4=BB=B6=E5=8D=B3=E5=8F=AF=E4=BD=BF=E5=BE=97?= =?UTF-8?q?sender=E5=85=B7=E6=9C=89=E5=85=B7=E8=B1=A1=E7=9A=84=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=EF=BC=8C=E4=BE=BF=E4=BA=8E=E6=8E=A5=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DelegateExtension.cs" | 23 +++++++++++++++++++ .../XCCNetWork.cs" | 5 ++-- ...47\261\273\346\213\223\345\261\225.csproj" | 1 + 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 "XFE\345\220\204\347\261\273\346\213\223\345\261\225/DelegateExtension.cs" diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/DelegateExtension.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/DelegateExtension.cs" new file mode 100644 index 0000000..350e5e1 --- /dev/null +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/DelegateExtension.cs" @@ -0,0 +1,23 @@ +namespace XFE各类拓展.DelegateExtension +{ + /// + /// 指定发送者泛型的委托事件 + /// + /// 发送者泛型 + /// 发送者 + public delegate void XFEEventHandler(T sender); + /// + /// 指定发送者泛型的委托事件 + /// + /// 发送者泛型 + /// 事件参数泛型 + /// 发送者 + /// 事件参数 + public delegate void XFEEventHandler(T1 sender, T2 e); + /// + /// 委托事件拓展 + /// + public static class DelegateExtension + { + } +} diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index c374519..697243a 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -8,6 +8,7 @@ using System.Threading.Tasks; using XFE各类拓展.ArrayExtension; using XFE各类拓展.BufferExtension; +using XFE各类拓展.DelegateExtension; using XFE各类拓展.FormatExtension; using XFE各类拓展.TaskExtension; @@ -881,7 +882,7 @@ public class XCCFile /// /// 文件加载完成时触发 /// - public event EventHandler FileLoaded; + public event XFEEventHandler FileLoaded; /// /// 群组ID /// @@ -918,7 +919,7 @@ public void LoadFile(byte[] fileBuffer) { FileBuffer = fileBuffer; Loaded = true; - FileLoaded?.Invoke(this, fileBuffer); + FileLoaded?.Invoke(this); } /// /// XCC文件 diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFE\345\220\204\347\261\273\346\213\223\345\261\225.csproj" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFE\345\220\204\347\261\273\346\213\223\345\261\225.csproj" index dfee12e..4c08423 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFE\345\220\204\347\261\273\346\213\223\345\261\225.csproj" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFE\345\220\204\347\261\273\346\213\223\345\261\225.csproj" @@ -57,6 +57,7 @@ + From a4fe22da6e8da61597d654a38f890c247f7d5980 Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Thu, 9 Nov 2023 14:58:02 +0800 Subject: [PATCH 14/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8DXCC=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E5=99=A8=E7=9A=84=E5=82=A8=E5=AD=98=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E8=B7=AF=E5=BE=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 697243a..1fc26b3 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -632,12 +632,13 @@ await Task.Run(() => { if (Directory.Exists(SavePathRoot)) { - foreach (var groupId in Directory.EnumerateDirectories(SavePathRoot)) + foreach (var groupIdFullPath in Directory.EnumerateDirectories(SavePathRoot)) { - if (File.Exists($"{groupId}/XFEMessage/XFEMessage.xfe")) + var groupId = Path.GetFileName(groupIdFullPath); + if (File.Exists($"{groupIdFullPath}/XFEMessage/XFEMessage.xfe")) { var xCCMessageList = new List(); - foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{groupId}/XFEMessage/XFEMessage.xfe"))) + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{groupIdFullPath}/XFEMessage/XFEMessage.xfe"))) { var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); xCCMessageList.Add(xCCMessage); @@ -646,7 +647,7 @@ await Task.Run(() => else FileReceived?.Invoke(true, LoadFile(xCCMessage)); } - xCCMessageDictionary.Add(Path.GetFileName(groupId), xCCMessageList); + xCCMessageDictionary.Add(groupId, xCCMessageList); } } } @@ -666,7 +667,7 @@ public async Task LoadGroup(string groupId) { await Task.Run(() => { - if (File.Exists($"{groupId}/XFEMessage/XFEMessage.xfe")) + if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) { var xCCMessageList = new List(); foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{groupId}/XFEMessage/XFEMessage.xfe"))) @@ -678,7 +679,7 @@ await Task.Run(() => else FileReceived?.Invoke(true, LoadFile(xCCMessage)); } - xCCMessageDictionary.Add(Path.GetFileName(groupId), xCCMessageList); + xCCMessageDictionary.Add(groupId, xCCMessageList); } }); loaded = true; @@ -709,7 +710,7 @@ await Task.Run(() => } private XCCFile LoadFile(XCCMessage xCCMessage) { - var filePath = $"{SavePathRoot}/{xCCMessage.GroupId}/{xCCMessage.MessageId}"; + var filePath = $"{SavePathRoot}/{xCCMessage.GroupId}/{xCCMessage.MessageId}.xfe"; var fileBuffer = File.ReadAllBytes(filePath); XCCFile xCCFile = null; switch (xCCMessage.MessageType) From 14b39838b9f39287802434eeca0f79c5cdd48607 Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Thu, 9 Nov 2023 15:47:22 +0800 Subject: [PATCH 15/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 1fc26b3..b750691 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -670,7 +670,7 @@ await Task.Run(() => if (File.Exists($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe")) { var xCCMessageList = new List(); - foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{groupId}/XFEMessage/XFEMessage.xfe"))) + foreach (var entry in new XFEMultiDictionary(File.ReadAllText($"{SavePathRoot}/{groupId}/XFEMessage/XFEMessage.xfe"))) { var xCCMessage = XCCMessage.ConvertToXCCMessage(entry.Content, groupId); xCCMessageList.Add(xCCMessage); @@ -711,8 +711,10 @@ await Task.Run(() => private XCCFile LoadFile(XCCMessage xCCMessage) { var filePath = $"{SavePathRoot}/{xCCMessage.GroupId}/{xCCMessage.MessageId}.xfe"; - var fileBuffer = File.ReadAllBytes(filePath); - XCCFile xCCFile = null; + byte[] fileBuffer = null; + if (File.Exists(filePath)) + fileBuffer = File.ReadAllBytes(filePath); + XCCFile xCCFile; switch (xCCMessage.MessageType) { case XCCTextMessageType.Image: From 8b3e5c4294257454574175a7d733c9461caadf94 Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Fri, 10 Nov 2023 01:10:05 +0800 Subject: [PATCH 16/22] =?UTF-8?q?XCC=E7=BD=91=E7=BB=9C=E9=80=9A=E8=AE=AF?= =?UTF-8?q?=E7=8E=B0=E5=9C=A8=E5=88=86=E4=B8=BA=E6=98=8E=E6=96=87=E5=92=8C?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=A4=E4=B8=AA=E6=9C=8D=E5=8A=A1=E5=99=A8?= =?UTF-8?q?=E5=88=86=E5=88=AB=E4=BC=A0=E8=BE=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 310 ++++++++++++++---- 1 file changed, 254 insertions(+), 56 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index b750691..29cd767 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -38,6 +38,20 @@ class XCCNetWorkBase public EventHandler connected; } /// + /// XCC客户端连接类型 + /// + public enum XCCClientType + { + /// + /// 明文类型 + /// + TextMessageClient, + /// + /// 文件类型 + /// + FileTransportClient + } + /// /// XCC网络通讯 /// public class XCCNetWork @@ -156,9 +170,13 @@ public abstract class XCCGroup /// public string Sender { get; } /// - /// WebSocket客户端 + /// WebSocket明文传输客户端 + /// + public ClientWebSocket TextMessageClientWebSocket { get; private set; } + /// + /// WebSocket文件传输客户端 /// - public ClientWebSocket ClientWebSocket { get; private set; } + public ClientWebSocket FileTransportClientWebSocket { get; private set; } /// /// 是否已连接 /// @@ -173,24 +191,169 @@ public abstract class XCCGroup /// 重连尝试延迟 /// public async Task StartXCC(bool autoReconnect = true, int reconnectMaxTimes = -1, int reconnectTryDelay = 100) + { + var textMessageXCCTask = StartTextMessageXCC(autoReconnect, reconnectMaxTimes, reconnectTryDelay); + var fileTransportXCCTask = StartFileTransportXCC(autoReconnect, reconnectMaxTimes, reconnectTryDelay); + await Task.WhenAll(textMessageXCCTask, fileTransportXCCTask); + } + /// + /// 启动XCC文本会话 + /// + /// 是否自动重连 + /// 最大重连次数,-1则为无限次 + /// 重连尝试延迟 + /// + public async Task StartTextMessageXCC(bool autoReconnect = true, int reconnectMaxTimes = -1, int reconnectTryDelay = 100) + { + XCCReconnect: + TextMessageClientWebSocket = new ClientWebSocket(); + Uri serverUri = new Uri("ws://xcc.api.xfegzs.com"); + var base64GroupId = Convert.ToBase64String(Encoding.UTF8.GetBytes(GroupId)); + var base64SenderId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Sender)); + TextMessageClientWebSocket.Options.SetRequestHeader("Group", base64GroupId); + TextMessageClientWebSocket.Options.SetRequestHeader("Sender", base64SenderId); + TextMessageClientWebSocket.Options.SetRequestHeader("Type", "Text"); + reconnectTimes++; + try + { + if (TextMessageClientWebSocket.State != WebSocketState.Open) + await TextMessageClientWebSocket.ConnectAsync(serverUri, CancellationToken.None); + } + catch (Exception ex) + { + if (IsConnected == true) + { + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.TextMessageClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); + } + IsConnected = false; + if (autoReconnect) + { + if (reconnectTimes <= reconnectMaxTimes || reconnectMaxTimes == -1) + { + Thread.Sleep(reconnectTryDelay); + goto XCCReconnect; + } + } + else + { + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.TextMessageClient, null, null, new XFECyberCommException("与XCC网络通讯明文服务器建立连接时发生异常", ex))); + return; + } + } + reconnectTimes = 0; + workBase.connected?.Invoke(this, new XCCConnectedEventArgsImpl(this, XCCClientType.TextMessageClient, TextMessageClientWebSocket, FileTransportClientWebSocket)); + IsConnected = true; + while (TextMessageClientWebSocket.State == WebSocketState.Open) + { + try + { + byte[] receiveBuffer = new byte[1024]; + WebSocketReceiveResult receiveResult = await TextMessageClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); + var bufferList = new List(); + bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); + //ReceiveCompletedMessageByUsingWhile + while (!receiveResult.EndOfMessage) + { + receiveResult = await TextMessageClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); + bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); + } + var receivedBinaryBuffer = bufferList.ToArray(); + if (receiveResult.MessageType == WebSocketMessageType.Text) + { + try + { + var receivedMessage = Encoding.UTF8.GetString(receivedBinaryBuffer); + var isHistory = receivedMessage.IndexOf("[XCCGetHistory]") == 0; + if (isHistory) + { + receivedMessage = receivedMessage.Substring(15); + } + var unPackedMessage = receivedMessage.ToXFEArray(); + var messageId = unPackedMessage[0]; + var signature = unPackedMessage[1]; + var message = unPackedMessage[2]; + var senderName = unPackedMessage[3]; + var sendTime = DateTime.Parse(unPackedMessage[4]); + var messageType = XCCTextMessageType.Text; + switch (signature) + { + case "[XCCTextMessage]": + messageType = XCCTextMessageType.Text; + break; + case "[XCCImage]": + messageType = XCCTextMessageType.Image; + break; + case "[XCCAudio]": + messageType = XCCTextMessageType.Audio; + break; + case "[XCCVideo]": + messageType = XCCTextMessageType.Video; + break; + default: + break; + } + workBase.textMessageReceived?.Invoke(this, new XCCTextMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.TextMessageClient, messageId, messageType, message, senderName, sendTime, isHistory)); + } + catch (Exception ex) + { + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.TextMessageClient, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); + } + } + } + catch (Exception ex) + { + try { await TextMessageClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } catch { } + if (IsConnected == true) + { + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.TextMessageClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); + } + IsConnected = false; + if (autoReconnect) + { + if (autoReconnect) + { + Thread.Sleep(reconnectTryDelay); + if (reconnectTimes <= reconnectMaxTimes || reconnectMaxTimes == -1) + goto XCCReconnect; + } + } + else + { + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.TextMessageClient, null, null, new XFECyberCommException("与XCC网络通讯服务器建立连接时发生异常", ex))); + return; + } + } + } + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.TextMessageClient, TextMessageClientWebSocket, FileTransportClientWebSocket, true)); + } + /// + /// 启动XCC文件传输会话 + /// + /// 是否自动重连 + /// 最大重连次数,-1则为无限次 + /// 重连尝试延迟 + /// + public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnectMaxTimes = -1, int reconnectTryDelay = 100) { XCCReconnect: - ClientWebSocket = new ClientWebSocket(); + FileTransportClientWebSocket = new ClientWebSocket(); Uri serverUri = new Uri("ws://xcc.api.xfegzs.com"); var base64GroupId = Convert.ToBase64String(Encoding.UTF8.GetBytes(GroupId)); var base64SenderId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Sender)); - ClientWebSocket.Options.SetRequestHeader("Group", base64GroupId); - ClientWebSocket.Options.SetRequestHeader("Sender", base64SenderId); + FileTransportClientWebSocket.Options.SetRequestHeader("Group", base64GroupId); + FileTransportClientWebSocket.Options.SetRequestHeader("Sender", base64SenderId); + FileTransportClientWebSocket.Options.SetRequestHeader("Type", "File"); reconnectTimes++; try { - await ClientWebSocket.ConnectAsync(serverUri, CancellationToken.None); + if (FileTransportClientWebSocket.State != WebSocketState.Open) + await FileTransportClientWebSocket.ConnectAsync(serverUri, CancellationToken.None); } catch (Exception ex) { if (IsConnected == true) { - workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, false)); + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); } IsConnected = false; if (autoReconnect) @@ -203,25 +366,25 @@ public async Task StartXCC(bool autoReconnect = true, int reconnectMaxTimes = -1 } else { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("与XCC网络通讯服务器建立连接时发生异常", ex))); + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, null, null, new XFECyberCommException("与XCC网络通讯明文服务器建立连接时发生异常", ex))); return; } } reconnectTimes = 0; - workBase.connected?.Invoke(this, new XCCConnectedEventArgsImpl(this, ClientWebSocket)); + workBase.connected?.Invoke(this, new XCCConnectedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket)); IsConnected = true; - while (ClientWebSocket.State == WebSocketState.Open) + while (FileTransportClientWebSocket.State == WebSocketState.Open) { try { byte[] receiveBuffer = new byte[1024]; - WebSocketReceiveResult receiveResult = await ClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); + WebSocketReceiveResult receiveResult = await TextMessageClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); var bufferList = new List(); bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); //ReceiveCompletedMessageByUsingWhile while (!receiveResult.EndOfMessage) { - receiveResult = await ClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); + receiveResult = await TextMessageClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); } var receivedBinaryBuffer = bufferList.ToArray(); @@ -259,11 +422,11 @@ public async Task StartXCC(bool autoReconnect = true, int reconnectMaxTimes = -1 default: break; } - workBase.textMessageReceived?.Invoke(this, new XCCTextMessageReceivedEventArgsImpl(this, ClientWebSocket, messageId, messageType, message, senderName, sendTime, isHistory)); + workBase.textMessageReceived?.Invoke(this, new XCCTextMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, messageId, messageType, message, senderName, sendTime, isHistory)); } catch (Exception ex) { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); } } if (receiveResult.MessageType == WebSocketMessageType.Binary) @@ -300,20 +463,20 @@ public async Task StartXCC(bool autoReconnect = true, int reconnectMaxTimes = -1 messageType = XCCBinaryMessageType.Binary; break; } - workBase.binaryMessageReceived?.Invoke(this, new XCCBinaryMessageReceivedEventArgsImpl(this, ClientWebSocket, sender, messageId, unPackedBuffer, messageType, signature)); + workBase.binaryMessageReceived?.Invoke(this, new XCCBinaryMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, sender, messageId, unPackedBuffer, messageType, signature)); } catch (Exception ex) { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); } } } catch (Exception ex) { - try { await ClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } catch { } + try { await TextMessageClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } catch { } if (IsConnected == true) { - workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, false)); + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); } IsConnected = false; if (autoReconnect) @@ -327,12 +490,12 @@ public async Task StartXCC(bool autoReconnect = true, int reconnectMaxTimes = -1 } else { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, ClientWebSocket, null, null, new XFECyberCommException("与XCC网络通讯服务器建立连接时发生异常", ex))); + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, null, null, new XFECyberCommException("与XCC网络通讯服务器建立连接时发生异常", ex))); return; } } } - workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, ClientWebSocket, true)); + workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket, true)); } /// /// 发送文本消息,返回消息ID @@ -358,7 +521,7 @@ public async Task SendTextMessage(string message, string messageId, int ti try { byte[] sendBuffer = Encoding.UTF8.GetBytes(new string[] { messageId, "[XCCTextMessage]", message }.ToXFEString()); - await ClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); + await TextMessageClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); var endTask = Task.Run(async () => { await Task.Delay(timeout); @@ -416,7 +579,7 @@ public async Task SendSignedBinaryMessage(byte[] message, string messageId try { var xFEBuffer = new XFEBuffer(Sender, message, "Type", Encoding.UTF8.GetBytes(signature), "ID", Encoding.UTF8.GetBytes(messageId)); - await ClientWebSocket.SendAsync(new ArraySegment(xFEBuffer.ToBuffer()), WebSocketMessageType.Binary, true, CancellationToken.None); + await TextMessageClientWebSocket.SendAsync(new ArraySegment(xFEBuffer.ToBuffer()), WebSocketMessageType.Binary, true, CancellationToken.None); var endTask = Task.Run(async () => { await Task.Delay(timeout); @@ -536,7 +699,7 @@ public async Task GetHistory() { var messageId = Guid.NewGuid().ToString(); byte[] sendBuffer = Encoding.UTF8.GetBytes(new string[] { messageId, "[XCCGetHistory]", "[XCCGetHistory]" }.ToXFEString()); - await ClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); + await TextMessageClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); var endTask = Task.Run(async () => { await Task.Delay(5000); @@ -558,7 +721,7 @@ public async Task CloseXCC() { try { - await ClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); + await TextMessageClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); } catch (Exception ex) { @@ -1016,15 +1179,23 @@ public XCCMessage(string messageId, XCCTextMessageType messageType, string messa /// public abstract class XCCMessageReceivedEventArgs : EventArgs { - /// - /// 当前WebSocket - /// - public ClientWebSocket CurrentWebSocket { get; } /// /// 触发事件的群组 /// public XCCGroup Group { get; } /// + /// WebSocket明文传输客户端 + /// + public ClientWebSocket TextMessageClientWebSocket { get; private set; } + /// + /// WebSocket文件传输客户端 + /// + public ClientWebSocket FileTransportClientWebSocket { get; private set; } + /// + /// XCC服务器连接类型 + /// + public XCCClientType XCCClientType { get; } + /// /// 消息ID /// public string MessageId { get; } @@ -1052,7 +1223,7 @@ public async Task ReplyTextMessage(string message) try { byte[] sendBuffer = Encoding.UTF8.GetBytes(message); - await CurrentWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); + await TextMessageClientWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } catch (Exception ex) { @@ -1068,7 +1239,7 @@ public async Task ReplyBinaryMessage(byte[] message) { try { - await CurrentWebSocket.SendAsync(new ArraySegment(message), WebSocketMessageType.Binary, true, CancellationToken.None); + await FileTransportClientWebSocket.SendAsync(new ArraySegment(message), WebSocketMessageType.Binary, true, CancellationToken.None); } catch (Exception ex) { @@ -1083,17 +1254,22 @@ public async Task Close() { try { - await CurrentWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); + if (TextMessageClientWebSocket.State == WebSocketState.Open) + await TextMessageClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); + if (FileTransportClientWebSocket.State == WebSocketState.Open) + await FileTransportClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); } catch (Exception ex) { throw new XFECyberCommException("客户端关闭连接时出现异常", ex); } } - internal XCCMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId) + internal XCCMessageReceivedEventArgs(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId) { Group = group; - CurrentWebSocket = clientWebSocket; + TextMessageClientWebSocket = textMessageClientWebSocket; + FileTransportClientWebSocket = fileTransportClientWebSocket; + XCCClientType = xCCClientType; Sender = sender; MessageId = messageId; } @@ -1141,7 +1317,7 @@ public abstract class XCCTextMessageReceivedEventArgs : XCCMessageReceivedEventA /// 是否为历史消息 /// public bool IsHistory { get; } - internal XCCTextMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, bool isHistory) : base(group, clientWebSocket, sender, messageId) + internal XCCTextMessageReceivedEventArgs(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, bool isHistory) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId) { MessageType = messageType; TextMessage = message; @@ -1197,7 +1373,7 @@ public abstract class XCCBinaryMessageReceivedEventArgs : XCCMessageReceivedEven /// 二进制消息 /// public byte[] BinaryMessage { get; } - internal XCCBinaryMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, clientWebSocket, sender, messageId) + internal XCCBinaryMessageReceivedEventArgs(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId) { BinaryMessage = buffer; MessageType = messageType; @@ -1213,7 +1389,7 @@ public abstract class XCCExceptionMessageReceivedEventArgs : XCCMessageReceivedE /// 异常信息 /// public XFECyberCommException Exception { get; } - internal XCCExceptionMessageReceivedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, XFECyberCommException exception) : base(group, clientWebSocket, sender, messageId) + internal XCCExceptionMessageReceivedEventArgs(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId, XFECyberCommException exception) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId) { Exception = exception; } @@ -1224,22 +1400,33 @@ internal XCCExceptionMessageReceivedEventArgs(XCCGroup group, ClientWebSocket cl public abstract class XCCConnectionClosedEventArgs : EventArgs { /// - /// 当前WebSocket + /// 触发事件的群组 /// - public ClientWebSocket CurrentWebSocket { get; } + public XCCGroup Group { get; } /// - /// 是否正常关闭 + /// XCC服务器连接类型 /// - public bool ClosedNormally { get; } + public XCCClientType XCCClientType { get; } /// - /// 触发事件的群组 + /// WebSocket明文传输客户端 /// - public XCCGroup Group { get; } - internal XCCConnectionClosedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket, bool closeNormally) + public ClientWebSocket TextMessageClientWebSocket { get; private set; } + /// + /// WebSocket文件传输客户端 + /// + public ClientWebSocket FileTransportClientWebSocket { get; private set; } + /// + /// 是否正常关闭 + /// + public bool ClosedNormally { get; } + + internal XCCConnectionClosedEventArgs(XCCGroup group, XCCClientType xCCClientType, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, bool closedNormally) { - CurrentWebSocket = clientWebSocket; Group = group; - ClosedNormally = closeNormally; + XCCClientType = xCCClientType; + TextMessageClientWebSocket = textMessageClientWebSocket; + FileTransportClientWebSocket = fileTransportClientWebSocket; + ClosedNormally = closedNormally; } } /// @@ -1247,18 +1434,29 @@ internal XCCConnectionClosedEventArgs(XCCGroup group, ClientWebSocket clientWebS /// public abstract class XCCConnectedEventArgs : EventArgs { - /// - /// 当前WebSocket - /// - public ClientWebSocket CurrentWebSocket { get; } /// /// 触发事件的群组 /// public XCCGroup Group { get; } - internal XCCConnectedEventArgs(XCCGroup group, ClientWebSocket clientWebSocket) + /// + /// XCC服务器连接类型 + /// + public XCCClientType XCCClientType { get; } + /// + /// WebSocket明文传输客户端 + /// + public ClientWebSocket TextMessageClientWebSocket { get; private set; } + /// + /// WebSocket文件传输客户端 + /// + public ClientWebSocket FileTransportClientWebSocket { get; private set; } + + internal XCCConnectedEventArgs(XCCGroup group, XCCClientType xCCClientType, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket) { - CurrentWebSocket = clientWebSocket; Group = group; + XCCClientType = xCCClientType; + TextMessageClientWebSocket = textMessageClientWebSocket; + FileTransportClientWebSocket = fileTransportClientWebSocket; } } class XCCGroupImpl : XCCGroup @@ -1267,22 +1465,22 @@ internal XCCGroupImpl(string groupId, string sender, XCCNetWorkBase xCCNetWorkBa } class XCCConnectionClosedEventArgsImpl : XCCConnectionClosedEventArgs { - internal XCCConnectionClosedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, bool closeNormally) : base(group, clientWebSocket, closeNormally) { } + public XCCConnectionClosedEventArgsImpl(XCCGroup group, XCCClientType xCCClientType, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, bool closedNormally) : base(group, xCCClientType, textMessageClientWebSocket, fileTransportClientWebSocket, closedNormally) { } } class XCCConnectedEventArgsImpl : XCCConnectedEventArgs { - internal XCCConnectedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket) : base(group, clientWebSocket) { } + public XCCConnectedEventArgsImpl(XCCGroup group, XCCClientType xCCClientType, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket) : base(group, xCCClientType, textMessageClientWebSocket, fileTransportClientWebSocket) { } } class XCCTextMessageReceivedEventArgsImpl : XCCTextMessageReceivedEventArgs { - internal XCCTextMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, bool isHistory) : base(group, clientWebSocket, messageId, messageType, message, sender, sendTime, isHistory) { } + internal XCCTextMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string messageId, XCCTextMessageType messageType, string message, string sender, DateTime sendTime, bool isHistory) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, messageId, messageType, message, sender, sendTime, isHistory) { } } class XCCBinaryMessageReceivedEventArgsImpl : XCCBinaryMessageReceivedEventArgs { - internal XCCBinaryMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, clientWebSocket, sender, messageId, buffer, messageType, signature) { } + internal XCCBinaryMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId, buffer, messageType, signature) { } } class XCCExceptionMessageReceivedEventArgsImpl : XCCExceptionMessageReceivedEventArgs { - internal XCCExceptionMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket clientWebSocket, string sender, string messageId, XFECyberCommException exception) : base(group, clientWebSocket, sender, messageId, exception) { } + internal XCCExceptionMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId, XFECyberCommException exception) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId, exception) { } } } \ No newline at end of file From a21c9a309b89258ce7c1c15c91c55c1f6c6a1b29 Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Sat, 11 Nov 2023 02:51:24 +0800 Subject: [PATCH 17/22] =?UTF-8?q?=E9=80=82=E9=85=8D=E5=8F=8C=E6=9C=8D?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 56 +++++-------------- 1 file changed, 15 insertions(+), 41 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 29cd767..bd57525 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -299,6 +299,21 @@ public async Task StartTextMessageXCC(bool autoReconnect = true, int reconnectMa workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.TextMessageClient, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); } } + else if (receiveResult.MessageType == WebSocketMessageType.Binary) + { + try + { + var xFEBuffer = XFEBuffer.ToXFEBuffer(receivedBinaryBuffer); + var signature = Encoding.UTF8.GetString(xFEBuffer["Type"]); + var messageId = Encoding.UTF8.GetString(xFEBuffer["ID"]); + if (signature == "callback") + UpdateTaskTrigger?.Invoke(true, messageId); + } + catch (Exception ex) + { + workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.TextMessageClient, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); + } + } } catch (Exception ex) { @@ -388,47 +403,6 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); } var receivedBinaryBuffer = bufferList.ToArray(); - if (receiveResult.MessageType == WebSocketMessageType.Text) - { - try - { - var receivedMessage = Encoding.UTF8.GetString(receivedBinaryBuffer); - var isHistory = receivedMessage.IndexOf("[XCCGetHistory]") == 0; - if (isHistory) - { - receivedMessage = receivedMessage.Substring(15); - } - var unPackedMessage = receivedMessage.ToXFEArray(); - var messageId = unPackedMessage[0]; - var signature = unPackedMessage[1]; - var message = unPackedMessage[2]; - var senderName = unPackedMessage[3]; - var sendTime = DateTime.Parse(unPackedMessage[4]); - var messageType = XCCTextMessageType.Text; - switch (signature) - { - case "[XCCTextMessage]": - messageType = XCCTextMessageType.Text; - break; - case "[XCCImage]": - messageType = XCCTextMessageType.Image; - break; - case "[XCCAudio]": - messageType = XCCTextMessageType.Audio; - break; - case "[XCCVideo]": - messageType = XCCTextMessageType.Video; - break; - default: - break; - } - workBase.textMessageReceived?.Invoke(this, new XCCTextMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, messageId, messageType, message, senderName, sendTime, isHistory)); - } - catch (Exception ex) - { - workBase.exceptionMessageReceived?.Invoke(this, new XCCExceptionMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, null, null, new XFECyberCommException("接收XCC服务器消息时发生异常", ex))); - } - } if (receiveResult.MessageType == WebSocketMessageType.Binary) { try From 4ff231e0340c772796e0eebb5426a31c89b39879 Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Mon, 13 Nov 2023 00:40:47 +0800 Subject: [PATCH 18/22] =?UTF-8?q?XCC=E5=8A=A9=E6=89=8B=E4=BF=AE=E5=A4=8Dbu?= =?UTF-8?q?g=EF=BC=8C=E4=BF=AE=E5=A4=8DXCC=E7=BD=91=E7=BB=9C=E9=80=9A?= =?UTF-8?q?=E8=AE=AFbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CyberComm.cs" | 96 ++++++++++++------- .../XCCNetWork.cs" | 91 +++++++++++++----- 2 files changed, 129 insertions(+), 58 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" index 45c72d8..957365a 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/CyberComm.cs" @@ -588,7 +588,7 @@ internal CyberCommServerEventArgsImpl(WebSocket webSocket, XFECyberCommException /// public class CyberCommGroup { - private readonly List webSockets = new List(); + private readonly List cyberCommList = new List(); /// /// 组ID /// @@ -596,18 +596,18 @@ public class CyberCommGroup /// /// 添加客户端 /// - /// 客户端 - public void Add(WebSocket webSocket) + /// 客户端 + public void Add(CyberCommServerEventArgs e) { - webSockets.Add(webSocket); + cyberCommList.Add(e); } /// - /// 获取指定的客户端 + /// 移除指定的客户端 /// /// 客户端 public void Remove(WebSocket webSocket) { - webSockets.Remove(webSocket); + cyberCommList.Remove(cyberCommList.Find(x => x.CurrentWebSocket == webSocket)); } /// /// 移除指定索引的客户端 @@ -615,14 +615,14 @@ public void Remove(WebSocket webSocket) /// 客户单索引 public void RemoveAt(int index) { - webSockets.RemoveAt(index); + cyberCommList.RemoveAt(index); } /// /// 清空列表 /// public void Clear() { - webSockets.Clear(); + cyberCommList.Clear(); } /// /// 群组客户端数量 @@ -631,19 +631,19 @@ public int Count { get { - return webSockets.Count; + return cyberCommList.Count; } } /// /// 索引器 /// - /// 索引 + /// 查找 /// 客户端 - public WebSocket this[int index] + public CyberCommServerEventArgs this[Predicate findFunc] { get { - return webSockets[index]; + return cyberCommList.Find(findFunc); } } /// @@ -652,27 +652,29 @@ public WebSocket this[int index] /// 群发文本消息 public async Task SendGroupTextMessage(string message) { - byte[] sendBuffer = Encoding.UTF8.GetBytes(message); - foreach (WebSocket webSocket in webSockets) + List tasks = new List(); + foreach (CyberCommServerEventArgs cyberCommServerEventArgs in cyberCommList) { - await webSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); + tasks.Add(cyberCommServerEventArgs.ReplyMessage(message)); } + await Task.WhenAll(tasks); } /// - /// 向除了指定的WS客户端外的客户端发送群组文本消息 + /// 向指定的WS客户端发送群组文本消息 /// /// 群发文本消息 - /// 除了指定的WS客户端外的客户端 - public async Task SendGroupTextMessageExcept(string message, WebSocket exceptWebSocket) + /// 指定的WS客户端 + public async Task SendGroupTextMessage(string message, Func findFunc) { - byte[] sendBuffer = Encoding.UTF8.GetBytes(message); - foreach (WebSocket webSocket in webSockets) + List tasks = new List(); + foreach (CyberCommServerEventArgs cyberCommServerEventArgs in cyberCommList) { - if (webSocket != exceptWebSocket) + if (findFunc.Invoke(cyberCommServerEventArgs)) { - await webSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); + tasks.Add(cyberCommServerEventArgs.ReplyMessage(message)); } } + await Task.WhenAll(tasks); } /// /// 发送群组二进制消息 @@ -680,25 +682,29 @@ public async Task SendGroupTextMessageExcept(string message, WebSocket exceptWeb /// 群发二进制消息 public async Task SendGroupBinaryMessage(byte[] bytes) { - foreach (WebSocket webSocket in webSockets) + List tasks = new List(); + foreach (CyberCommServerEventArgs cyberCommServerEventArgs in cyberCommList) { - await webSocket.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Binary, true, CancellationToken.None); + tasks.Add(cyberCommServerEventArgs.ReplyBinaryMessage(bytes)); } + await Task.WhenAll(tasks); } /// - /// 向除了指定的WS客户端外的客户端发送群组二进制消息 + /// 向指定的WS客户端发送群组二进制消息 /// /// 群发二进制消息 - /// 除了指定的WS客户端外的客户端 - public async Task SendGroupBinaryMessageExcept(byte[] bytes, WebSocket exceptWebSocket) + /// 指定的WS客户端 + public async Task SendGroupBinaryMessage(byte[] bytes, Func findFunc) { - foreach (WebSocket webSocket in webSockets) + List tasks = new List(); + foreach (CyberCommServerEventArgs cyberCommServerEventArgs in cyberCommList) { - if (webSocket != exceptWebSocket) + if (findFunc.Invoke(cyberCommServerEventArgs)) { - await webSocket.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Binary, true, CancellationToken.None); + tasks.Add(cyberCommServerEventArgs.ReplyBinaryMessage(bytes)); } } + await Task.WhenAll(tasks); } /// /// 客户端群组 @@ -712,11 +718,35 @@ public CyberCommGroup(string GroupId) /// 客户端群组 /// /// 群组ID - /// 客户端群组 - public CyberCommGroup(string GroupId, List webSockets) + /// 客户端群组 + public CyberCommGroup(string GroupId, List cyberCommList) { this.GroupId = GroupId; - this.webSockets = webSockets; + this.cyberCommList = cyberCommList; + } + } + /// + /// 代签名的WebSocket + /// + public class SignedWebSocket + { + /// + /// 签名 + /// + public string Signature { get; set; } + /// + /// 服务器 + /// + public WebSocket WebSocket { get; set; } + /// + /// 签名WebSocket + /// + /// 签名 + /// WebSocket + public SignedWebSocket(string signature, WebSocket webSocket) + { + Signature = signature; + WebSocket = webSocket; } } /// diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index bd57525..4852321 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -139,7 +139,7 @@ public event EventHandler Connected /// public XCCGroup CreateGroup(string groupId, string sender) { - var group = new XCCGroupImpl(groupId, sender, xCCNetWorkBase); + var group = new XCCGroupImpl(Guid.NewGuid().ToString(), groupId, sender, xCCNetWorkBase); Groups.Add(group); return group; } @@ -162,6 +162,10 @@ public abstract class XCCGroup private int reconnectTimes = -1; #region 公有属性 /// + /// 客户端标识名 + /// + public string Signature { get; } + /// /// 群组ID /// public string GroupId { get; } @@ -170,6 +174,14 @@ public abstract class XCCGroup /// public string Sender { get; } /// + /// 明文传输服务器是否连接 + /// + public bool TextMessageClientConnected { get; private set; } = false; + /// + /// 文件传输服务器是否连接 + /// + public bool FileTransportClientConnected { get; private set; } = false; + /// /// WebSocket明文传输客户端 /// public ClientWebSocket TextMessageClientWebSocket { get; private set; } @@ -177,10 +189,6 @@ public abstract class XCCGroup /// WebSocket文件传输客户端 /// public ClientWebSocket FileTransportClientWebSocket { get; private set; } - /// - /// 是否已连接 - /// - public bool IsConnected { get; private set; } = false; #endregion #region 公有方法 /// @@ -213,6 +221,7 @@ public async Task StartTextMessageXCC(bool autoReconnect = true, int reconnectMa TextMessageClientWebSocket.Options.SetRequestHeader("Group", base64GroupId); TextMessageClientWebSocket.Options.SetRequestHeader("Sender", base64SenderId); TextMessageClientWebSocket.Options.SetRequestHeader("Type", "Text"); + TextMessageClientWebSocket.Options.SetRequestHeader("Signature", Signature); reconnectTimes++; try { @@ -221,11 +230,11 @@ public async Task StartTextMessageXCC(bool autoReconnect = true, int reconnectMa } catch (Exception ex) { - if (IsConnected == true) + if (TextMessageClientConnected == true) { workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.TextMessageClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); } - IsConnected = false; + TextMessageClientConnected = false; if (autoReconnect) { if (reconnectTimes <= reconnectMaxTimes || reconnectMaxTimes == -1) @@ -241,8 +250,8 @@ public async Task StartTextMessageXCC(bool autoReconnect = true, int reconnectMa } } reconnectTimes = 0; + TextMessageClientConnected = true; workBase.connected?.Invoke(this, new XCCConnectedEventArgsImpl(this, XCCClientType.TextMessageClient, TextMessageClientWebSocket, FileTransportClientWebSocket)); - IsConnected = true; while (TextMessageClientWebSocket.State == WebSocketState.Open) { try @@ -318,11 +327,11 @@ public async Task StartTextMessageXCC(bool autoReconnect = true, int reconnectMa catch (Exception ex) { try { await TextMessageClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } catch { } - if (IsConnected == true) + if (TextMessageClientConnected == true) { workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.TextMessageClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); } - IsConnected = false; + TextMessageClientConnected = false; if (autoReconnect) { if (autoReconnect) @@ -358,6 +367,7 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect FileTransportClientWebSocket.Options.SetRequestHeader("Group", base64GroupId); FileTransportClientWebSocket.Options.SetRequestHeader("Sender", base64SenderId); FileTransportClientWebSocket.Options.SetRequestHeader("Type", "File"); + FileTransportClientWebSocket.Options.SetRequestHeader("Signature", Signature); reconnectTimes++; try { @@ -366,11 +376,11 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect } catch (Exception ex) { - if (IsConnected == true) + if (FileTransportClientConnected == true) { workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); } - IsConnected = false; + FileTransportClientConnected = false; if (autoReconnect) { if (reconnectTimes <= reconnectMaxTimes || reconnectMaxTimes == -1) @@ -386,20 +396,20 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect } } reconnectTimes = 0; + FileTransportClientConnected = true; workBase.connected?.Invoke(this, new XCCConnectedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket)); - IsConnected = true; while (FileTransportClientWebSocket.State == WebSocketState.Open) { try { byte[] receiveBuffer = new byte[1024]; - WebSocketReceiveResult receiveResult = await TextMessageClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); + WebSocketReceiveResult receiveResult = await FileTransportClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); var bufferList = new List(); bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); //ReceiveCompletedMessageByUsingWhile while (!receiveResult.EndOfMessage) { - receiveResult = await TextMessageClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); + receiveResult = await FileTransportClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); } var receivedBinaryBuffer = bufferList.ToArray(); @@ -447,12 +457,12 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect } catch (Exception ex) { - try { await TextMessageClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } catch { } - if (IsConnected == true) + try { await FileTransportClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } catch { } + if (FileTransportClientConnected == true) { workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); } - IsConnected = false; + FileTransportClientConnected = false; if (autoReconnect) { if (autoReconnect) @@ -472,7 +482,15 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket, true)); } /// - /// 发送文本消息,返回消息ID + /// 等待明文服务器和文件服务器均连接 + /// + /// + public async Task WaitConnect() + { + await Task.Run(() => { while (!TextMessageClientConnected || !FileTransportClientConnected) { } }); + } + /// + /// 发送文本消息 /// /// 待发送的文本 /// 最长超时时长 @@ -528,7 +546,7 @@ public async Task SendStandardTextMessage(string role, string message) } } /// - /// 发送签名二进制消息,返回消息ID + /// 发送签名二进制消息 /// /// 二进制消息 /// 签名标识 @@ -553,7 +571,7 @@ public async Task SendSignedBinaryMessage(byte[] message, string messageId try { var xFEBuffer = new XFEBuffer(Sender, message, "Type", Encoding.UTF8.GetBytes(signature), "ID", Encoding.UTF8.GetBytes(messageId)); - await TextMessageClientWebSocket.SendAsync(new ArraySegment(xFEBuffer.ToBuffer()), WebSocketMessageType.Binary, true, CancellationToken.None); + await FileTransportClientWebSocket.SendAsync(new ArraySegment(xFEBuffer.ToBuffer()), WebSocketMessageType.Binary, true, CancellationToken.None); var endTask = Task.Run(async () => { await Task.Delay(timeout); @@ -703,8 +721,9 @@ public async Task CloseXCC() } } #endregion - internal XCCGroup(string groupId, string sender, XCCNetWorkBase xCCNetWorkBase) + internal XCCGroup(string signature, string groupId, string sender, XCCNetWorkBase xCCNetWorkBase) { + Signature = signature; GroupId = groupId; Sender = sender; workBase = xCCNetWorkBase; @@ -989,6 +1008,28 @@ public void ReceiveBinaryMessage(object sender, XCCBinaryMessageReceivedEventArg SaveFile(xCCFile); } } + else + { + var fileType = XCCFileType.Image; + switch (e.MessageType) + { + case XCCBinaryMessageType.Image: + fileType = XCCFileType.Image; + break; + case XCCBinaryMessageType.Audio: + fileType = XCCFileType.Audio; + break; + case XCCBinaryMessageType.AudioBuffer: + break; + case XCCBinaryMessageType.Video: + fileType = XCCFileType.Video; + break; + default: + break; + } + xCCFileDictionary.Add(e.MessageId, new XCCFile(e.GroupId, e.MessageId, fileType, e.Sender, null, e.BinaryMessage)); + FileReceived?.Invoke(e.) + } } /// /// XCC消息接收器 @@ -1038,7 +1079,7 @@ public class XCCFile /// /// 发送时间 /// - public DateTime SendTime { get; } + public DateTime? SendTime { get; } /// /// XCC文件类型 /// @@ -1070,7 +1111,7 @@ public void LoadFile(byte[] fileBuffer) /// 发送者 /// 发送时间 /// 文件的Buffer - public XCCFile(string groupId, string messageId, XCCFileType fileType, string sender, DateTime sendTime, byte[] fileBuffer = null) + public XCCFile(string groupId, string messageId, XCCFileType fileType, string sender, DateTime? sendTime, byte[] fileBuffer = null) { GroupId = groupId; MessageId = messageId; @@ -1435,7 +1476,7 @@ internal XCCConnectedEventArgs(XCCGroup group, XCCClientType xCCClientType, Clie } class XCCGroupImpl : XCCGroup { - internal XCCGroupImpl(string groupId, string sender, XCCNetWorkBase xCCNetWorkBase) : base(groupId, sender, xCCNetWorkBase) { } + internal XCCGroupImpl(string signature, string groupId, string sender, XCCNetWorkBase xCCNetWorkBase) : base(signature, groupId, sender, xCCNetWorkBase) { } } class XCCConnectionClosedEventArgsImpl : XCCConnectionClosedEventArgs { From e35c04d888003e605c8805860680c6a7c8424ec4 Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Tue, 14 Nov 2023 10:36:47 +0800 Subject: [PATCH 19/22] =?UTF-8?q?=E4=B8=BA=E6=96=87=E4=BB=B6=E4=BC=A0?= =?UTF-8?q?=E8=BE=93=E5=8D=8F=E8=AE=AE=E6=B7=BB=E5=8A=A0=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E5=A4=B4=E6=A0=87=E8=AF=86=E4=BF=A1=E6=81=AF=EF=BC=8C=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8=E5=9C=A8=E4=BC=A0=E8=BE=93=E6=96=87=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E6=97=B6=E5=80=99=E5=8F=AF=E4=BB=A5=E8=8E=B7=E5=8F=96=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=8F=91=E9=80=81=E7=9A=84=E6=97=B6=E9=97=B4=E5=92=8C?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E4=B8=BA=E5=8E=86=E5=8F=B2=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 34 +++++++++++++++---- .../XFEChatGPT.cs" | 4 --- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 4852321..8b995ca 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -421,8 +421,12 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect var xFEBuffer = XFEBuffer.ToXFEBuffer(receivedBinaryBuffer); var sender = Encoding.UTF8.GetString(xFEBuffer["Sender"]); var signature = Encoding.UTF8.GetString(xFEBuffer["Type"]); + if (signature == "callback") + return; var messageId = Encoding.UTF8.GetString(xFEBuffer["ID"]); - byte[] unPackedBuffer = signature == "callback" ? null : xFEBuffer[sender]; + bool isHistory = Encoding.UTF8.GetString(xFEBuffer["IsHistory"]) == "True"; + var sendTime = DateTime.Parse(Encoding.UTF8.GetString(xFEBuffer["SendTime"])); + byte[] unPackedBuffer = xFEBuffer[sender]; switch (signature) { case "text": @@ -447,7 +451,7 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect messageType = XCCBinaryMessageType.Binary; break; } - workBase.binaryMessageReceived?.Invoke(this, new XCCBinaryMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, sender, messageId, unPackedBuffer, messageType, signature)); + workBase.binaryMessageReceived?.Invoke(this, new XCCBinaryMessageReceivedEventArgsImpl(this, TextMessageClientWebSocket, FileTransportClientWebSocket, XCCClientType.FileTransportClient, sender, messageId, unPackedBuffer, messageType, signature, sendTime, isHistory)); } catch (Exception ex) { @@ -871,6 +875,12 @@ private XCCFile LoadFile(XCCMessage xCCMessage) if (File.Exists(filePath)) fileBuffer = File.ReadAllBytes(filePath); XCCFile xCCFile; + if (xCCFileDictionary.ContainsKey(xCCMessage.MessageId)) + { + if (!xCCFileDictionary[xCCMessage.MessageId].Loaded && fileBuffer != null) + xCCFileDictionary[xCCMessage.MessageId].LoadFile(fileBuffer); + return xCCFileDictionary[xCCMessage.MessageId]; + } switch (xCCMessage.MessageType) { case XCCTextMessageType.Image: @@ -1027,8 +1037,10 @@ public void ReceiveBinaryMessage(object sender, XCCBinaryMessageReceivedEventArg default: break; } - xCCFileDictionary.Add(e.MessageId, new XCCFile(e.GroupId, e.MessageId, fileType, e.Sender, null, e.BinaryMessage)); - FileReceived?.Invoke(e.) + var xCCFile = new XCCFile(e.GroupId, e.MessageId, fileType, e.Sender, e.SendTime, e.BinaryMessage); + xCCFileDictionary.Add(e.MessageId, xCCFile); + if (!e.IsHistory) + FileReceived?.Invoke(e.IsHistory, xCCFile); } } /// @@ -1388,11 +1400,21 @@ public abstract class XCCBinaryMessageReceivedEventArgs : XCCMessageReceivedEven /// 二进制消息 /// public byte[] BinaryMessage { get; } - internal XCCBinaryMessageReceivedEventArgs(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId) + /// + /// 发送时间 + /// + public DateTime SendTime { get; } + /// + /// 是否为历史消息 + /// + public bool IsHistory { get; } + internal XCCBinaryMessageReceivedEventArgs(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature, DateTime sendTime, bool isHistory) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId) { BinaryMessage = buffer; MessageType = messageType; Signature = signature; + SendTime = sendTime; + IsHistory = isHistory; } } /// @@ -1492,7 +1514,7 @@ internal XCCTextMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket tex } class XCCBinaryMessageReceivedEventArgsImpl : XCCBinaryMessageReceivedEventArgs { - internal XCCBinaryMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId, buffer, messageType, signature) { } + internal XCCBinaryMessageReceivedEventArgsImpl(XCCGroup group, ClientWebSocket textMessageClientWebSocket, ClientWebSocket fileTransportClientWebSocket, XCCClientType xCCClientType, string sender, string messageId, byte[] buffer, XCCBinaryMessageType messageType, string signature, DateTime sendTime, bool isHistory) : base(group, textMessageClientWebSocket, fileTransportClientWebSocket, xCCClientType, sender, messageId, buffer, messageType, signature, sendTime, isHistory) { } } class XCCExceptionMessageReceivedEventArgsImpl : XCCExceptionMessageReceivedEventArgs { diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFEChatGPT.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFEChatGPT.cs" index a0fea90..154c7df 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFEChatGPT.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFEChatGPT.cs" @@ -67,22 +67,18 @@ public enum ChatGPTModel /// /// 比任何 GPT-3.5 型号都更强大,能够执行更复杂的任务,并针对聊天进行了优化。将在发布 2 周后使用我们最新的模型迭代进行更新。 /// - [Obsolete("该模型暂时不可使用", true)] gpt4, /// /// 13 年 2023 月 3 日带有函数调用数据的快照。与gpt-4不同,此模型不会收到更新,并将在新版本发布3个月后弃用。基于gpt-4 /// - [Obsolete("该模型暂时不可使用", true)] gpt40613, /// /// 功能与gpt4基本模型相同,但上下文长度是其 4 倍。将使用最新的模型迭代进行更新。基于gpt-4 /// - [Obsolete("该模型暂时不可使用", true)] gpt432k, /// /// 13 年 2023 月 3 日的快照。与GPT-4-32K不同,此模型不会收到更新,并将在新版本发布 3 个月后弃用。基于gpt-4-32k /// - [Obsolete("该模型暂时不可使用", true)] gpt432k0613, /// /// 功能最强大的 GPT-3.5 型号,针对聊天进行了优化,成本仅为 .将在发布 1 周后使用最新的模型迭代进行更新。 From 0629da0aed9e7fbae5a07c70bfdfe87c23bf9cb8 Mon Sep 17 00:00:00 2001 From: xfe18827675401 Date: Tue, 14 Nov 2023 10:54:38 +0800 Subject: [PATCH 20/22] =?UTF-8?q?XCC=E6=B6=88=E6=81=AF=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=E5=99=A8=E6=B7=BB=E5=8A=A0=E5=AE=9E=E6=97=B6=E9=9F=B3=E9=A2=91?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E5=92=8C=E5=BC=82=E5=B8=B8=E6=8A=9B=E5=87=BA?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index 8b995ca..be165e0 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -783,6 +783,14 @@ public class XCCMessageReceiveHelper /// public event MessageReceivedHandler TextReceived; /// + /// 错误发生事件 + /// + public event XFEEventHandler ExceptionOccurred; + /// + /// 接收到实时音频字节流事件 + /// + public event XFEEventHandler AudioBufferReceived; + /// /// 从设置的根目录加载 /// /// @@ -958,12 +966,7 @@ private void ReceiveFilePlaceHolder(XCCTextMessageReceivedEventArgs e, XCCFileTy if (AutoSaveInLocal) SaveMessage(e.GroupId); } - /// - /// 接收文本消息 - /// - /// 发送者 - /// 事件参数 - public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) + private void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) { var message = new XCCMessage(e.MessageId, e.MessageType, e.TextMessage, e.Sender, e.SendTime, e.GroupId); if (xCCMessageDictionary.ContainsKey(e.GroupId)) @@ -1001,13 +1004,13 @@ public void ReceiveTextMessage(object sender, XCCTextMessageReceivedEventArgs e) break; } } - /// - /// 接收二进制消息 - /// - /// 发送者 - /// 事件参数 - public void ReceiveBinaryMessage(object sender, XCCBinaryMessageReceivedEventArgs e) + private void ReceiveBinaryMessage(object sender, XCCBinaryMessageReceivedEventArgs e) { + if (e.MessageType == XCCBinaryMessageType.AudioBuffer) + { + AudioBufferReceived?.Invoke(e.BinaryMessage); + return; + } if (xCCFileDictionary.ContainsKey(e.MessageId)) { var xCCFile = xCCFileDictionary[e.MessageId]; @@ -1043,6 +1046,10 @@ public void ReceiveBinaryMessage(object sender, XCCBinaryMessageReceivedEventArg FileReceived?.Invoke(e.IsHistory, xCCFile); } } + private void XCCNetWork_ExceptionMessageReceived(object sender, XCCExceptionMessageReceivedEventArgs e) + { + ExceptionOccurred?.Invoke(e.Exception); + } /// /// XCC消息接收器 /// @@ -1065,6 +1072,7 @@ public XCCMessageReceiveHelper(string savePathRoot, XCCNetWork xCCNetWork, bool SavePathRoot = savePathRoot; xCCNetWork.TextMessageReceived += ReceiveTextMessage; xCCNetWork.BinaryMessageReceived += ReceiveBinaryMessage; + xCCNetWork.ExceptionMessageReceived += XCCNetWork_ExceptionMessageReceived; } } /// From ccc156a5e5b0e855fe55d44823d01f76912d2b47 Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Tue, 14 Nov 2023 20:16:29 +0800 Subject: [PATCH 21/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8DCloseXCC=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E6=97=A0=E6=B3=95=E5=85=B3=E9=97=AD=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCCNetWork.cs" | 11 ++++++++++ .../XFEChatGPT.cs" | 20 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" index be165e0..f09e20f 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XCCNetWork.cs" @@ -160,6 +160,7 @@ public abstract class XCCGroup private event EndTaskTrigger UpdateTaskTrigger; private readonly XCCNetWorkBase workBase; private int reconnectTimes = -1; + private bool readyToClose = false; #region 公有属性 /// /// 客户端标识名 @@ -230,6 +231,10 @@ public async Task StartTextMessageXCC(bool autoReconnect = true, int reconnectMa } catch (Exception ex) { + if (readyToClose) + { + return; + } if (TextMessageClientConnected == true) { workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.TextMessageClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); @@ -376,6 +381,10 @@ public async Task StartFileTransportXCC(bool autoReconnect = true, int reconnect } catch (Exception ex) { + if (readyToClose) + { + return; + } if (FileTransportClientConnected == true) { workBase.connectionClosed?.Invoke(this, new XCCConnectionClosedEventArgsImpl(this, XCCClientType.FileTransportClient, TextMessageClientWebSocket, FileTransportClientWebSocket, false)); @@ -717,7 +726,9 @@ public async Task CloseXCC() { try { + readyToClose = true; await TextMessageClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); + await FileTransportClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端主动关闭连接", CancellationToken.None); } catch (Exception ex) { diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFEChatGPT.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFEChatGPT.cs" index 154c7df..ffd21e2 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFEChatGPT.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/XFEChatGPT.cs" @@ -69,6 +69,14 @@ public enum ChatGPTModel /// gpt4, /// + /// 最新的GPT-4模型,具有改进的指令跟随、JSON模式、可复制输出、并行函数调用等功能。最多返回4096个输出标记。此预览模型还不适合生产流量。 + /// + gpt4turbo, + /// + /// 能够理解图像,以及所有其他GPT-4 Turbo功能。最多返回4096个输出标记。这是一个预览模型版本,还不适合生产流量。 + /// + gpt4turbovision, + /// /// 13 年 2023 月 3 日带有函数调用数据的快照。与gpt-4不同,此模型不会收到更新,并将在新版本发布3个月后弃用。基于gpt-4 /// gpt40613, @@ -124,6 +132,18 @@ public static string GetModelString(this ChatGPTModel chatGPTModel) { switch (chatGPTModel) { + case ChatGPTModel.gpt4: + return "gpt-4"; + case ChatGPTModel.gpt4turbo: + return "gpt-4-1106-preview"; + case ChatGPTModel.gpt4turbovision: + return "gpt-4-vision-preview"; + case ChatGPTModel.gpt40613: + return "gpt-4-0613"; + case ChatGPTModel.gpt432k: + return "gpt-4-32k"; + case ChatGPTModel.gpt432k0613: + return "gpt-4-32k-0613"; case ChatGPTModel.gpt3point5turbo: return "gpt-3.5-turbo"; case ChatGPTModel.gpt3point5turbo16k: From 39fab9cda0d07bdf2db28f0e08b67c52be3ecfa1 Mon Sep 17 00:00:00 2001 From: XFEstudio Date: Wed, 15 Nov 2023 01:54:41 +0800 Subject: [PATCH 22/22] =?UTF-8?q?=E5=AE=8C=E5=85=A8=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=96=B0=E7=9A=84XCC=E5=8D=8F=E8=AE=AE=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E7=89=88=E6=9C=AC=E5=8F=B7=E4=B8=BA1.0.0.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Properties/AssemblyInfo.cs" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/Properties/AssemblyInfo.cs" "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/Properties/AssemblyInfo.cs" index e986368..ae35b7c 100644 --- "a/XFE\345\220\204\347\261\273\346\213\223\345\261\225/Properties/AssemblyInfo.cs" +++ "b/XFE\345\220\204\347\261\273\346\213\223\345\261\225/Properties/AssemblyInfo.cs" @@ -32,5 +32,5 @@ //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //通过使用 "*",如下所示: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.2")] -[assembly: AssemblyFileVersion("1.0.0.2")] +[assembly: AssemblyVersion("1.0.0.3")] +[assembly: AssemblyFileVersion("1.0.0.3")]