public void ReadyMessagesShouldSerialize( uint version, ulong userId, int sequenceNumber ) { var serializer = CreateSerializer(); var gatewayMessage = new GatewayMessage { OpCode = GatewayOpCode.Dispatch, SequenceNumber = sequenceNumber, EventName = "READY", Data = new ReadyEvent { GatewayVersion = version, User = new User { Id = userId, }, }, }; var result = serializer.Serialize(gatewayMessage); result.Should().MatchRegex("\"op\":[ ]?0", "Op Code should equal 0."); result.Should().MatchRegex($"\"s\":[ ]?{sequenceNumber}", $"Sequence number should equal {sequenceNumber}"); result.Should().MatchRegex($"\"t\":[ ]?\"READY\"", $"Event name should equal READY"); result.Should().MatchRegex($"\"d\":[ ]?{{(.*?)\"v\":[ ]?{version}(.*?)}}", $"Data should contain version of {version}"); result.Should().MatchRegex($"\"d\":[ ]?{{(.*?)\"user\":[ ]?{{(.*?)\"id\":[ ]?\"{userId}\"(.*?)}}(.*?)}}", $"Data should contain userId of {userId}"); }
public bool IsCommand(GatewayMessage message) { return(message.Content.Length > 0 && message.Content.TrimStart()[0] == '?' && message.Author.Id != _clientInfoRepository.GetClientInfo().User.Id); // Disable bot possibility to handle own commands }
public async Task RunShouldWaitUntilTheWebSocketIsOpen( int sequenceNumber, [Substitute] IClientWebSocket clientWebSocket, [Frozen, Substitute] IGatewayService gateway, [Frozen, Substitute] IChannel <GatewayMessage> channel, [Frozen, Substitute] IGatewayUtilsFactory factory, [Target] DefaultGatewayTxWorker worker ) { var tries = 0; var message = new GatewayMessage { SequenceNumber = sequenceNumber }; var cancellationToken = new CancellationToken(false); clientWebSocket.State.Returns(WebSocketState.Connecting); channel.Read(Any <CancellationToken>()).Returns(new ValueTask <GatewayMessage>(message)); channel.WaitToRead(Any <CancellationToken>()).Returns(true); factory.CreateDelay(Any <uint>(), Any <CancellationToken>()).Returns(async x => { if (++tries == 2) { clientWebSocket.State.Returns(WebSocketState.Open); } await Task.CompletedTask; }); await worker.Start(gateway, clientWebSocket); await worker.Run(cancellationToken); await factory.Received(2).CreateDelay(100, Is(cancellationToken)); }
public async Task RunShouldReadFromChannelIfWaitToReadReturnsTrue( int sequenceNumber, [Substitute] IClientWebSocket clientWebSocket, [Frozen, Substitute] IGatewayService gateway, [Frozen, Substitute] IChannel <GatewayMessage> channel, [Frozen, Substitute] IGatewayUtilsFactory factory, [Target] DefaultGatewayTxWorker worker ) { var message = new GatewayMessage { SequenceNumber = sequenceNumber }; var cancellationToken = new CancellationToken(false); channel.Read(Any <CancellationToken>()).Returns(new ValueTask <GatewayMessage>(message)); clientWebSocket.State.Returns(WebSocketState.Open); await worker.Start(gateway, clientWebSocket); await worker.Run(cancellationToken); await channel.Received().WaitToRead(Is(cancellationToken)); await channel.Received().Read(Is(cancellationToken)); }
public static Metadata GetMeta(this GatewayMessage gatewayMessage, IMessageConsumeContext context) { var(_, _, metadata) = gatewayMessage; var meta = metadata == null ? new Metadata() : new Metadata(metadata); return(meta.WithCausationId(context.MessageId)); }
public async Task Produce(GatewayMessage message) { using var producer = new ProducerBuilder <Null, string>(_config) .SetErrorHandler((_, e) => { _logger.LogError($"Kafka Error {e.Code}: {e.Reason}"); }) .Build(); try { var jsonMessage = JsonConvert.SerializeObject(message); var dr = await producer.ProduceAsync( topic : _topic, message : new Message <Null, string> { Value = jsonMessage } ); _logger.LogInformation($"Delivered '{dr.Value}' to '{dr.TopicPartitionOffset}' with status {dr.Status.ToString()}"); } catch (ProduceException <Null, string> e) { _logger.LogError($"Delivery failed: {e.Error.Reason}"); } catch (Exception ex) { _logger.LogError($"Delivery failed: {ex.Message}"); } }
private static Task OnPacketReceivedAsync(GatewayMessage arg) { if (arg.EventName == "READY") { var ready = JsonSerializer.Deserialize <GatewayReadyPacket>( ((JsonElement)arg.Data).GetRawText(), options); Log.Message($"Shard {ready.CurrentShard} is connected"); } if (config.IgnorePackets.Contains(arg.EventName)) { return(Task.CompletedTask); } if (!queueSet.ContainsKey(arg.EventName)) { var queue = GetQueueNameFromEventName(arg.EventName); pusherModel.QueueDeclare(queue, true, false, false); pusherModel.QueueBind(queue, "gateway", arg.EventName); queueSet.TryAdd(arg.EventName, null); } try { pusherModel.BasicPublish( "gateway", arg.EventName, body: Encoding.UTF8.GetBytes(JsonSerializer.Serialize(arg))); } catch (AlreadyClosedException) { Log.Warning($"Event '{arg.EventName}' missed due to AMQP client closed."); } return(Task.CompletedTask); }
public async Task RunShouldRouteTheMessageIfEndOfMessageIsReached( byte[] bytes, uint interval, int sequenceNumber, [Frozen, Substitute] Stream stream, [Frozen, Substitute] IChannel <GatewayMessageChunk> channel, [Frozen, Substitute] IGatewayUtilsFactory factory, [Frozen, Substitute] IGatewayService gateway, [Frozen, Substitute] ISerializer serializer, [Frozen, Substitute] IEventRouter router, [Target] DefaultGatewayRxWorker worker ) { var @event = new HelloEvent { HeartbeatInterval = interval }; var message = new GatewayMessage { SequenceNumber = sequenceNumber, Data = @event }; var cancellationToken = new CancellationToken(false); serializer.Deserialize <GatewayMessage>(Any <Stream>(), Any <CancellationToken>()).Returns(message); channel.Read(Any <CancellationToken>()).Returns(new GatewayMessageChunk(bytes, bytes.Length, true)); await worker.Start(gateway); await worker.Run(cancellationToken); await router.Received().Route(Is(@event), Is(cancellationToken)); }
public async Task RunShouldNotUpdateSequenceNumberIfEndOfMessageIsReachedButSequenceNumberIsNull( byte[] bytes, int sequenceNumber, [Frozen, Substitute] Stream stream, [Frozen, Substitute] IChannel <GatewayMessageChunk> channel, [Frozen, Substitute] IGatewayUtilsFactory factory, [Frozen, Substitute] IGatewayService gateway, [Frozen, Substitute] ISerializer serializer, [Target] DefaultGatewayRxWorker worker ) { var message = new GatewayMessage { SequenceNumber = null }; serializer.Deserialize <GatewayMessage>(Any <Stream>(), Any <CancellationToken>()).Returns(message); channel.Read(Any <CancellationToken>()).Returns(new GatewayMessageChunk(bytes, bytes.Length, true)); gateway.SequenceNumber = sequenceNumber; await worker.Start(gateway); await worker.Run(); gateway.SequenceNumber.Should().Be(sequenceNumber); }
public void ResumeMessagesShouldSerialize( string token, string sessionId, int sequenceNumber ) { var serializer = CreateSerializer(); var gatewayMessage = new GatewayMessage { OpCode = GatewayOpCode.Resume, Data = new ResumeEvent { Token = token, SessionId = sessionId, SequenceNumber = sequenceNumber, }, }; var result = serializer.Serialize(gatewayMessage); result.Should().MatchRegex("\"op\":[ ]?6", "Op Code should equal 6."); result.Should().MatchRegex($"\"d\":[ ]?{{(.*?)\"token\":[ ]?\"{token}\"(.*?)}}", $"Data should contain the token."); result.Should().MatchRegex($"\"d\":[ ]?{{(.*?)\"session_id\":[ ]?\"{sessionId}\"(.*?)}}", $"Data should contain the session id."); result.Should().MatchRegex($"\"d\":[ ]?{{(.*?)\"seq\":[ ]?{sequenceNumber}(.*?)}}", $"Data should contain the sequence number."); }
public async Task RunShouldWriteBytesToWebSocket( int sequenceNumber, byte[] bytes, [Substitute] IClientWebSocket clientWebSocket, [Frozen, Substitute] IGatewayService gateway, [Frozen, Substitute] IChannel <GatewayMessage> channel, [Frozen, Substitute] ISerializer serializer, [Frozen, Substitute] IGatewayUtilsFactory factory, [Target] DefaultGatewayTxWorker worker ) { var message = new GatewayMessage { SequenceNumber = sequenceNumber }; var cancellationToken = new CancellationToken(false); serializer.SerializeToBytes(Any <GatewayMessage>()).Returns(bytes); channel.Read(Any <CancellationToken>()).Returns(new ValueTask <GatewayMessage>(message)); clientWebSocket.State.Returns(WebSocketState.Open); await worker.Start(gateway, clientWebSocket); await worker.Run(cancellationToken); await clientWebSocket.Received().Send(Is <ArraySegment <byte> >(bytes), Is(WebSocketMessageType.Text), Is(true), Is(cancellationToken)); }
protected sealed override async Task ProcessMessage(GatewayMessage message, CancellationToken cancellationToken) { try { switch (message.CommandName) { case nameof(GetAllProductsResponseCommand): { var getAllProductsCommand = JsonConvert.DeserializeObject <GetAllProductsResponseCommand>(message.Command); if (getAllProductsCommand != null) { await _mediator.Send(getAllProductsCommand, cancellationToken); } else { LogIncorrectCommandBody(); } /* TODO: --- * var requestHandler = new GetAllProductsResponseHandler(_productTaskKeeper); * requestHandler.Handle(command, CancellationToken.None); */ break; } case nameof(GetProductByIdResponseCommand): var getProductByIdCommand = JsonConvert.DeserializeObject <GetProductByIdResponseCommand>(message.Command); if (getProductByIdCommand != null) { await _mediator.Send(getProductByIdCommand, cancellationToken); } else { LogIncorrectCommandBody(); } break; case nameof(CreateProductResponseCommand): var createProductResponseCommand = JsonConvert.DeserializeObject <CreateProductResponseCommand>(message.Command); if (createProductResponseCommand != null) { await _mediator.Send(createProductResponseCommand, cancellationToken); } else { LogIncorrectCommandBody(); } break; default: _logger.LogWarning($"Unhandled command: {message.CommandName}"); break; } } catch (Exception e) { _logger.LogError(e, $"Unhandled {nameof(ProcessMessage)} error"); } }
public async Task Handle(GetAllProductsQuery command) { var products = _repository.GetAll().ToList(); var responseCommand = new GetAllProductsResponseCommand(products, command.CommandId); var gatewayMessage = new GatewayMessage(responseCommand); await _producer.Produce(gatewayMessage); }
/// <summary> /// Sends a Heartbeat through the gateway. /// </summary> /// <param name="cancellationToken">Token used to cancel the operation.</param> /// <returns>The resulting task.</returns> public async Task Heartbeat(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var message = new GatewayMessage { OpCode = GatewayOpCode.Heartbeat, Data = (HeartbeatEvent?)SequenceNumber }; await txWorker.Emit(message, cancellationToken); }
public Command(GatewayMessage message) { Member = message.Member; Author = message.Author; Arguments = message.Content.Split(' ', StringSplitOptions.RemoveEmptyEntries)[1..]; CommandName = message.Content.Split(' ')[0].ToLowerInvariant()[1..]; CalledFromChannel = message.ChannelId; CalledFromGuild = message.GuildId; }
public async Task Handle(GetProductByIdQuery command) { var product = await _repository.GetProductByIdAsync(command.Id); var responseCommand = new GetProductByIdResponseCommand(product, command.CommandId); var gatewayMessage = new GatewayMessage(responseCommand); await _producer.Produce(gatewayMessage); }
protected sealed override async Task ProcessMessage(GatewayMessage message, CancellationToken cancellationToken) { switch (message.CommandName) { case nameof(GetAllProductsQuery): { var getAllProductsQuery = JsonConvert.DeserializeObject <GetAllProductsQuery>(message.Command); if (getAllProductsQuery != null) { var requestHandler = new GetAllProductsRequestHandler(_productRepository, _producer); await requestHandler.Handle(getAllProductsQuery); } else { LogIncorrectCommandBody(); } break; } case nameof(GetProductByIdQuery): { var getProductByIdQuery = JsonConvert.DeserializeObject <GetProductByIdQuery>(message.Command); if (getProductByIdQuery != null) { var requestHandler = new GetProductByIdHandle(_productRepository, _producer); await requestHandler.Handle(getProductByIdQuery); } else { LogIncorrectCommandBody(); } break; } case nameof(CreateProductRequestCommand): { var createProductRequestCommand = JsonConvert.DeserializeObject <CreateProductRequestCommand>(message.Command); if (createProductRequestCommand != null) { var requestHandler = new CreateProductRequestHandler(_productRepository, _producer); await requestHandler.Handle(createProductRequestCommand); } else { LogIncorrectCommandBody(); } break; } default: _logger.LogWarning($"Unhandled command: {message.CommandName}"); break; } }
public async Task Handle(CreateProductRequestCommand command) { var product = await _repository.AddAsync(new Product { Name = command.Name, Price = command.Price, ExpirationDate = command.ExpirationDate }); var responseCommand = new CreateProductResponseCommand(product, command.CommandId); var gatewayMessage = new GatewayMessage(responseCommand); await _producer.Produce(gatewayMessage); }
public void Bot_cannot_handle_its_own_commands() { var testCommand = new GatewayMessage { Content = "?test-command", Author = new Author { Id = crabotFakeAuthorId } }; var validationResult = _commandValidator.IsCommand(testCommand); Assert.False(validationResult); }
public void Command_with_prefix_and_random_author_id_is_valid_command() { var testCommand = new GatewayMessage { Content = "?test-command", Author = new Author { Id = It.IsAny <string>() } }; var validationResult = _commandValidator.IsCommand(testCommand); Assert.True(validationResult); }
public static CommandMessage FromGatewayMessage <T>(int shardId, GatewayMessage message) where T : class { if (message.OpCode == null) { return(null); } return(new CommandMessage { ShardId = shardId, Opcode = message.OpCode.Value, Data = message.Data as T }); }
public void HeartbeatMessagesShouldSerialize( int sequenceNumber ) { var serializer = CreateSerializer(); var gatewayMessage = new GatewayMessage { OpCode = GatewayOpCode.Heartbeat, Data = new HeartbeatEvent(sequenceNumber), }; var result = serializer.Serialize(gatewayMessage); result.Should().MatchRegex("\"op\":[ ]?1", "Op Code should equal 1."); result.Should().MatchRegex($"\"d\":[ ]?{sequenceNumber}", $"Data should equal the sequence number ({sequenceNumber})"); }
public async Task SendShouldEmitTheMessageToTheTxWorker( int sequenceNumber, [Frozen, Substitute] IGatewayTxWorker txWorker, [Target] DefaultGatewayService gateway ) { var message = new GatewayMessage { SequenceNumber = sequenceNumber }; var cancellationToken = new CancellationToken(false); await gateway.StartAsync(); await gateway.Send(message, cancellationToken); await txWorker.Received().Emit(Is(message), Is(cancellationToken)); }
public async Task SendShouldThrowIfTheOperationWasCanceled( int sequenceNumber, [Frozen, Substitute] IGatewayTxWorker txWorker, [Target] DefaultGatewayService gateway ) { var message = new GatewayMessage { SequenceNumber = sequenceNumber }; var cancellationToken = new CancellationToken(false); await gateway.StartAsync(); var operationCancellationToken = new CancellationToken(true); Func <Task> func = () => gateway.Send(message, operationCancellationToken); await func.Should().ThrowAsync <OperationCanceledException>(); }
public async Task EmitShouldEmitTheMessageToTheChannel( int sequenceNumber, [Frozen, Substitute] IGatewayService gateway, [Frozen, Substitute] IClientWebSocket webSocket, [Frozen, Substitute] IChannel <GatewayMessage> channel, [Target] DefaultGatewayTxWorker worker ) { var message = new GatewayMessage { SequenceNumber = sequenceNumber }; var cancellationToken = new CancellationToken(false); await worker.Start(gateway, webSocket); await worker.Emit(message, cancellationToken); await channel.Received().Write(Is(message), Is(cancellationToken)); }
public async Task EmitShouldThrowIfTheOperationWasCanceled( int sequenceNumber, [Substitute] IClientWebSocket clientWebSocket, [Frozen, Substitute] IGatewayService gateway, [Target] DefaultGatewayTxWorker worker ) { var message = new GatewayMessage { SequenceNumber = sequenceNumber }; var cancellationToken = new CancellationToken(false); await worker.Start(gateway, clientWebSocket); var operationCancellationToken = new CancellationToken(true); Func <Task> func = () => worker.Emit(message, operationCancellationToken); await func.Should().ThrowAsync <OperationCanceledException>(); }
public async Task <Product> Handle(GetProductByIdQuery request, CancellationToken cancellationToken) { var message = new GatewayMessage(request); var tcs = new TaskCompletionSource <object>(); _taskKeeper.Keep(request.CommandId, tcs); await _producer.Produce(message); var result = await tcs.Task; if (result is Product product) { return(product); } else { throw new GatewayException("Incorrect response format"); } }
public void HelloMessagesShouldSerialize( uint interval, int sequenceNumber ) { var serializer = CreateSerializer(); var gatewayMessage = new GatewayMessage { OpCode = GatewayOpCode.Hello, SequenceNumber = sequenceNumber, Data = new HelloEvent { HeartbeatInterval = interval, }, }; var result = serializer.Serialize(gatewayMessage); result.Should().MatchRegex("\"op\":[ ]?10", "Op Code should equal 10."); result.Should().MatchRegex($"\"s\":[ ]?{sequenceNumber}", $"Sequence number should equal {sequenceNumber}"); result.Should().MatchRegex($"\"d\":[ ]?{{[ ]?\"heartbeat_interval\":[ ]?{interval}[ ]?}}", $"Data should contain heartbeat interval of {interval}"); }
/// <summary> /// Adds a new message. /// </summary> /// <param name="clientId">Client to add.</param> /// <param name="timeReceived">Time the message was received</param> /// <param name="message">The original message.</param> /// <param name="headers">The headers.</param> /// <returns><value>true</value> if successfully added.</returns> public bool InsertMessage(string clientId, DateTime timeReceived, Stream message, IDictionary <string, string> headers) { using (var session = SessionFactory.OpenSession()) using (var tx = session.BeginTransaction(IsolationLevel.ReadCommitted)) { var gatewayMessage = session.Get <GatewayMessage>(clientId); if (gatewayMessage != null) { tx.Commit(); return(false); } gatewayMessage = new GatewayMessage { Id = clientId, Headers = ConvertDictionaryToString(headers), TimeReceived = timeReceived, OriginalMessage = new byte[message.Length], }; message.Read(gatewayMessage.OriginalMessage, 0, (int)message.Length); try { session.Save(gatewayMessage); tx.Commit(); } catch (GenericADOException) { tx.Rollback(); return(false); } } return(true); }
public void On(string channel, GatewayMessage callback) { channels[channel] = callback; }
/// <summary> /// Adds a new message. /// </summary> /// <param name="clientId">Client to add.</param> /// <param name="timeReceived">Time the message was received</param> /// <param name="message">The original message.</param> /// <param name="headers">The headers.</param> /// <returns><value>true</value> if successfully added.</returns> public bool InsertMessage(string clientId, DateTime timeReceived, Stream message, IDictionary<string, string> headers) { using (var session = SessionFactory.OpenSession()) using (var tx = session.BeginTransaction(IsolationLevel.ReadCommitted)) { var gatewayMessage = session.Get<GatewayMessage>(clientId); if (gatewayMessage != null) { tx.Commit(); return false; } gatewayMessage = new GatewayMessage { Id = clientId, Headers = ConvertDictionaryToString(headers), TimeReceived = timeReceived, OriginalMessage = new byte[message.Length], }; message.Read(gatewayMessage.OriginalMessage, 0, (int) message.Length); try { session.Save(gatewayMessage); tx.Commit(); } catch (GenericADOException) { tx.Rollback(); return false; } } return true; }
/// <inheritdoc /> public async Task Emit(GatewayMessage message, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfNotRunning(); await channel.Write(message, cancellationToken); }