/// <summary> /// Constructs a new <see cref="BaseSocketClientAbstraction"/> around an existing <see cref="WebSocket.BaseSocketClient"/>. /// </summary> /// <param name="baseSocketClient">The value to use for <see cref="WebSocket.BaseSocketClient"/>.</param> /// <exception cref="ArgumentNullException">Throws for <paramref name="baseSocketClient"/>.</exception> protected BaseSocketClientAbstraction(BaseSocketClient baseSocketClient) : base(baseSocketClient) { baseSocketClient.ChannelCreated += x => ChannelCreated?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.ChannelDestroyed += x => ChannelDestroyed?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.ChannelUpdated += (x, y) => ChannelUpdated?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.CurrentUserUpdated += (x, y) => CurrentUserUpdated?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.GuildAvailable += x => GuildAvailable?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.GuildMembersDownloaded += x => GuildMembersDownloaded?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.GuildMemberUpdated += (x, y) => GuildMemberUpdated?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.GuildUnavailable += x => GuildUnavailable?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.GuildUpdated += (x, y) => GuildUpdated?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.JoinedGuild += x => JoinedGuild?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.LeftGuild += x => LeftGuild?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.MessageReceived += x => MessageReceived?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.MessageUpdated += (x, y, z) => MessageUpdated?.InvokeAsync(x.Abstract(), y.Abstract(), z.Abstract()) ?? Task.CompletedTask; baseSocketClient.MessageDeleted += (x, y) => MessageDeleted?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.ReactionAdded += (x, y, z) => ReactionAdded?.InvokeAsync(x.Abstract(), y.Abstract(), z.Abstract()) ?? Task.CompletedTask; baseSocketClient.ReactionRemoved += (x, y, z) => ReactionRemoved?.InvokeAsync(x.Abstract(), y.Abstract(), z.Abstract()) ?? Task.CompletedTask; baseSocketClient.ReactionsCleared += (x, y) => ReactionsCleared?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.RecipientAdded += x => RecipientAdded?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.RecipientRemoved += x => RecipientRemoved?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.RoleCreated += x => RoleCreated?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.RoleDeleted += x => RoleDeleted?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.RoleUpdated += (x, y) => RoleUpdated?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.UserBanned += (x, y) => UserBanned?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.UserIsTyping += (x, y) => UserIsTyping?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.UserJoined += x => UserJoined?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.UserLeft += x => UserLeft?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; baseSocketClient.UserUnbanned += (x, y) => UserUnbanned?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.UserUpdated += (x, y) => UserUpdated?.InvokeAsync(x.Abstract(), y.Abstract()) ?? Task.CompletedTask; baseSocketClient.UserVoiceStateUpdated += (x, y, z) => UserVoiceStateUpdated?.InvokeAsync(x.Abstract(), y.Abstract(), z.Abstract()) ?? Task.CompletedTask; baseSocketClient.VoiceServerUpdated += x => VoiceServerUpdated?.InvokeAsync(x.Abstract()) ?? Task.CompletedTask; }
private async Task RequestReceivedHandler(object sender, RequestReceivedEventArgs e) { try { var sw = Stopwatch.StartNew(); if (MessageReceived != null) { await MessageReceived.InvokeAsync(this, new MessageEventArgs(e.Request)).ConfigureAwait(false); } if (e.Request?.Body is null) { return; } var body = e.Request.Body.GetValue(); if (EnableCompleteMessageCache) { RequestMessageCache.Add(body, e.Request); } object result; Status.IncrementCurrentMessagesBeingProcessed(); try { result = await Processor.ProcessAsync(body, e.ProcessResponseTimeoutCancellationToken).ConfigureAwait(false); e.SetResponseBody(result); } catch (Exception ex) { Core.Log.Write(ex); Status.IncrementTotalExceptions(); } sw.Stop(); Status.ReportProcessingTime(sw.Elapsed.TotalMilliseconds); Status.DecrementCurrentMessagesBeingProcessed(); Status.IncrementTotalMessagesProccesed(); if (EnableCompleteMessageCache) { RequestMessageCache.Remove(body); } } catch (Exception ex) { Core.Log.Write(ex); Status.IncrementTotalExceptions(); } }
private async Task ReceiveAsync(CancellationToken cancellationToken) { Task _sentData = Task.CompletedTask; try { while (!cancellationToken.IsCancellationRequested) { if (!_networkStream.CanRead) { continue; } if (!_client.Connected) { throw new SocketException((int)SocketError.ConnectionReset); } byte[] bytes = new byte[8]; if ((await _networkStream.ReadAsync(bytes, 0, bytes.Length).ConfigureAwait(false)) == 0) { throw new SocketException((int)SocketError.ConnectionReset); } uint length = BitConverter.ToUInt32(bytes, 0); uint magic = BitConverter.ToUInt32(bytes, 4); if (magic != _tcpMagic) { throw new InvalidDataException("The provided packet does not have the correct magic value"); } bytes = new byte[length]; await ReceiveDataAsync(bytes, bytes.Length).ConfigureAwait(false); await _sentData.ConfigureAwait(false); _sentData = MessageReceived.InvokeAsync(this, new DataReceivedEventArgs(bytes)); } } catch (Exception ex) { var _ = OnClosed(ex); } }
/// <inheritdoc /> /// <summary> /// On Service Start method /// </summary> /// <param name="args">Start arguments</param> public void OnStart(string[] args) { try { Core.Log.InfoBasic("Starting messaging service"); _cTokenSource = new CancellationTokenSource(); OnInit(args); QueueServer = GetQueueServer(); if (QueueServer is null) { throw new Exception("The queue server is null, please check the configuration file and ensure the Types assemblies are on the assembly folder."); } Processor = GetMessageProcessorAsync(QueueServer); if (Processor is null) { throw new Exception("The message processor is null, please check your GetMessageProcessor method implementation."); } if (QueueServer.ResponseServer) { QueueServer.ResponseReceived += async(s, e) => { if (MessageReceived != null) { await MessageReceived.InvokeAsync(this, new RawMessageEventArgs(e.Message, e.CorrelationId)).ConfigureAwait(false); } await Processor.ProcessAsync(e, _cTokenSource.Token).ConfigureAwait(false); }; } else { QueueServer.RequestReceived += async(s, e) => { if (MessageReceived != null) { await MessageReceived.InvokeAsync(this, new RawMessageEventArgs(e.Request, e.CorrelationId)).ConfigureAwait(false); } var result = await Processor.ProcessAsync(e, _cTokenSource.Token).ConfigureAwait(false); if (result != ResponseMessage.NoResponse && result != null) { if (result is byte[] rBytes) { e.Response = rBytes; } else if (result is MultiArray <byte> mBytes) { e.Response = mBytes; } else { e.Response = QueueServer.SenderSerializer.Serialize(result); } } }; QueueServer.BeforeSendResponse += async(s, e) => { if (BeforeSendMessage != null) { await BeforeSendMessage.InvokeAsync(this, new RawMessageEventArgs(e.Message, e.CorrelationId)).ConfigureAwait(false); } }; QueueServer.ResponseSent += async(s, e) => { if (MessageSent != null) { await MessageSent.InvokeAsync(this, new RawMessageEventArgs(e.Message, e.CorrelationId)).ConfigureAwait(false); } }; } Processor.Init(); QueueServer.StartListeners(); Core.Log.InfoBasic("Messaging service started."); Core.Status.Attach(collection => { Core.Status.AttachChild(Processor, this); Core.Status.AttachChild(QueueServer, this); }); } catch (Exception ex) { Core.Log.Write(ex); throw; } }
private async Task RunAsync(CancellationToken cancelToken) { var buffer = new ArraySegment <byte>(new byte[ReceiveChunkSize]); try { while (!cancelToken.IsCancellationRequested) { WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); byte[] result; int resultCount; if (socketResult.MessageType == WebSocketMessageType.Close) { throw new WebSocketClosedException((int)socketResult.CloseStatus, socketResult.CloseStatusDescription); } if (!socketResult.EndOfMessage) { //This is a large message (likely just READY), lets create a temporary expandable stream using (var stream = new MemoryStream()) { stream.Write(buffer.Array, 0, socketResult.Count); do { if (cancelToken.IsCancellationRequested) { return; } socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); stream.Write(buffer.Array, 0, socketResult.Count); }while (socketResult == null || !socketResult.EndOfMessage); //Use the internal buffer if we can get it resultCount = (int)stream.Length; #if MSTRYBUFFER if (stream.TryGetBuffer(out var streamBuffer)) { result = streamBuffer.Array; } else { result = stream.ToArray(); } #else result = stream.GetBuffer(); #endif } } else { //Small message result = new byte[socketResult.Count]; Buffer.BlockCopy(buffer.Array, 0, result, 0, socketResult.Count); } if (socketResult.MessageType == WebSocketMessageType.Text) { throw new NotSupportedException(); } else { await MessageReceived.InvokeAsync(this, new DataReceivedEventArgs(result)).ConfigureAwait(false); } } } catch (Win32Exception ex) when(ex.HResult == HR_TIMEOUT) { var _ = OnClosed(new Exception("Connection timed out.", ex)); } catch (OperationCanceledException) { } catch (Exception ex) { //This cannot be awaited otherwise we'll deadlock when DiscordApiClient waits for this task to complete. var _ = OnClosed(ex); } }
/// <inheritdoc /> /// <summary> /// On Service Start method /// </summary> /// <param name="args">Start arguments</param> public void OnStart(string[] args) { try { Core.Log.InfoBasic("Starting messaging service"); _cTokenSource = new CancellationTokenSource(); OnInit(args); Status = new MessagingServiceStatus(this); QueueServer = GetQueueServer(); if (QueueServer == null) { throw new Exception("The queue server is null, please check the configuration file and ensure the Types assemblies are on the assembly folder."); } Processor = GetMessageProcessorAsync(QueueServer); if (Processor == null) { throw new Exception("The message processor is null, please check your GetMessageProcessor method implementation."); } if (QueueServer.ResponseServer) { QueueServer.ResponseReceived += async(s, e) => { if (MessageReceived != null) { await MessageReceived.InvokeAsync(this, new MessageEventArgs(e.Message)).ConfigureAwait(false); } if (e.Message?.Body == null) { return; } ReceivedMessagesCache.TryAdd(e.Message.Body, e.Message); Status.IncrementCurrentMessagesBeingProcessed(); var sw = Stopwatch.StartNew(); try { await Processor.ProcessAsync(e.Message.Body, _cTokenSource.Token).ConfigureAwait(false); } catch (Exception ex) { Core.Log.Write(ex); Status.IncrementTotalExceptions(); } sw.Stop(); Status.ReportProcessingTime(sw.Elapsed.TotalMilliseconds); Status.DecrementCurrentMessagesBeingProcessed(); Status.IncrementTotalMessagesProccesed(); ReceivedMessagesCache.TryRemove(e.Message.Body, out object _); }; } else { QueueServer.RequestReceived += async(s, e) => { if (MessageReceived != null) { await MessageReceived.InvokeAsync(this, new MessageEventArgs(e.Request)).ConfigureAwait(false); } if (e.Request?.Body == null) { return; } ReceivedMessagesCache.TryAdd(e.Request.Body, e.Request); object result = null; Status.IncrementCurrentMessagesBeingProcessed(); var sw = Stopwatch.StartNew(); try { result = await Processor.ProcessAsync(e.Request.Body, e.ProcessResponseTimeoutCancellationToken).ConfigureAwait(false); } catch (Exception ex) { Core.Log.Write(ex); Status.IncrementTotalExceptions(); } sw.Stop(); Status.ReportProcessingTime(sw.Elapsed.TotalMilliseconds); Status.DecrementCurrentMessagesBeingProcessed(); Status.IncrementTotalMessagesProccesed(); e.Response.Body = result; ReceivedMessagesCache.TryRemove(e.Request.Body, out object _); }; QueueServer.BeforeSendResponse += async(s, e) => { if (BeforeSendMessage != null) { await BeforeSendMessage.InvokeAsync(this, new MessageEventArgs(e.Message)).ConfigureAwait(false); } }; QueueServer.ResponseSent += async(s, e) => { if (MessageSent != null) { await MessageSent.InvokeAsync(this, new MessageEventArgs(e.Message)).ConfigureAwait(false); } }; } Processor.Init(); QueueServer.StartListeners(); Core.Log.InfoBasic("Messaging service started."); } catch (Exception ex) { Core.Log.Write(ex); throw; } }