/// <summary> /// Triggers event and sends message to subscribers /// </summary> protected void Trigger(object model) { try { if (_subscribers.Count == 0) { return; } HorseMessage message = new HorseMessage(MessageType.Event, Target); message.SetSource(Name); if (model != null) { message.Serialize(model, _server.MessageContentSerializer); } byte[] data = HmqWriter.Create(message); List <MqClient> removing = null; lock (_subscribers) foreach (MqClient subscriber in _subscribers) { //if client is disconnected, add it into removing list if (!subscriber.IsConnected) { //removing list is created when it's needed if (removing == null) { removing = new List <MqClient>(); } removing.Add(subscriber); } else { _ = subscriber.SendAsync(data); } } //if there are some removing clients from subscribers list, remove them if (removing != null) { lock (_subscribers) foreach (MqClient remove in removing) { _subscribers.Remove(remove); } } } catch (Exception e) { _server.SendError("EVENT_TRIGGER", e, $"Name:{Name}, Type:{GetType().Name}"); } }
/// <summary> /// Writes a message to a stream /// </summary> public async Task Write(Stream stream, HorseMessage message) { WriteType(stream, DataType.Insert); await WriteId(stream, message.MessageId); message.Content.Position = 0; await using MemoryStream ms = new MemoryStream(); HmqWriter.Write(message, ms); ms.Position = 0; await WriteContent(Convert.ToInt32(ms.Length), ms, stream); }
/// <summary> /// /// </summary> public async Task <HorseServerSocket> Connected(IHorseServer server, IConnectionInfo connection, ConnectionData data) { string clientId; bool found = data.Properties.TryGetValue(HorseHeaders.CLIENT_ID, out clientId); if (!found || string.IsNullOrEmpty(clientId)) { clientId = _server.Server.ClientIdGenerator.Create(); } //if another client with same unique id is online, do not accept new client MqClient foundClient = _server.Clients.Find(x => x.UniqueId == clientId); if (foundClient != null) { await connection.Socket.SendAsync(HmqWriter.Create(MessageBuilder.Busy())); return(null); } //creates new node client object MqClient client = new MqClient(_server.Server, connection); client.Data = data; client.UniqueId = clientId.Trim(); client.Token = data.Properties.GetStringValue(HorseHeaders.CLIENT_TOKEN); client.Name = data.Properties.GetStringValue(HorseHeaders.CLIENT_NAME); client.Type = data.Properties.GetStringValue(HorseHeaders.CLIENT_TYPE); if (_server.Authenticator != null) { bool accepted = await _server.Authenticator.Authenticate(_server, client); if (!accepted) { return(null); } } client.RemoteHost = client.Info.Client.Client.RemoteEndPoint.ToString()?.Split(':')[0]; _server.Clients.Add(client); await client.SendAsync(MessageBuilder.Accepted(client.UniqueId)); return(client); }
public async Task DisconnectDueToPingTimeout() { TestHorseMq server = new TestHorseMq(); await server.Initialize(); int port = server.Start(); TcpClient client = new TcpClient(); await client.ConnectAsync("127.0.0.1", port); NetworkStream stream = client.GetStream(); stream.Write(PredefinedMessages.PROTOCOL_BYTES_V2); HorseMessage msg = new HorseMessage(); msg.Type = MessageType.Server; msg.ContentType = KnownContentTypes.Hello; msg.SetStringContent("GET /\r\nName: Test-" + port); msg.CalculateLengths(); HmqWriter.Write(msg, stream); await Task.Delay(1000); Assert.Equal(1, server.ClientConnected); ThreadPool.UnsafeQueueUserWorkItem(async s => { byte[] buffer = new byte[128]; while (client.Connected) { int r = await s.ReadAsync(buffer); if (r == 0) { client.Dispose(); break; } } }, stream, false); await Task.Delay(15000); Assert.False(client.Connected); Assert.Equal(1, server.ClientDisconnected); }
public async Task Handle(MqClient client, HorseMessage message, bool fromNode) { //if server is not set or there is no connected server if (_server.NodeManager.Connectors.Length == 0) { return; } byte[] mdata = HmqWriter.Create(message); foreach (HmqStickyConnector connector in _server.NodeManager.Connectors) { bool grant = _server.NodeManager.Authenticator == null || await _server.NodeManager.Authenticator.CanReceive(connector.GetClient(), message); if (grant) { _ = connector.SendAsync(mdata); } } }
private async Task <PushResult> ProcessMessage(QueueMessage message, QueueClient receiver) { //if we need acknowledge from receiver, it has a deadline. DateTime?deadline = null; if (_queue.Options.Acknowledge != QueueAckDecision.None) { deadline = DateTime.UtcNow.Add(_queue.Options.AcknowledgeTimeout); } //return if client unsubsribes while waiting ack of previous message if (!_queue.ClientsClone.Contains(receiver)) { _queue.AddMessage(message, false); return(PushResult.NoConsumers); } if (message.CurrentDeliveryReceivers.Count > 0) { message.CurrentDeliveryReceivers.Clear(); } message.Decision = await _queue.DeliveryHandler.BeginSend(_queue, message); if (!await _queue.ApplyDecision(message.Decision, message)) { return(PushResult.Success); } //create prepared message data byte[] messageData = HmqWriter.Create(message.Message); //call before send and check decision message.Decision = await _queue.DeliveryHandler.CanConsumerReceive(_queue, message, receiver.Client); if (!await _queue.ApplyDecision(message.Decision, message)) { return(PushResult.Success); } //create delivery object MessageDelivery delivery = new MessageDelivery(message, receiver, deadline); //send the message bool sent = await receiver.Client.SendAsync(messageData); if (sent) { if (_queue.Options.Acknowledge != QueueAckDecision.None) { receiver.CurrentlyProcessing = message; receiver.ProcessDeadline = deadline ?? DateTime.UtcNow; } message.CurrentDeliveryReceivers.Add(receiver); //adds the delivery to time keeper to check timing up _queue.TimeKeeper.AddAcknowledgeCheck(delivery); //mark message is sent delivery.MarkAsSent(); _queue.Info.AddMessageSend(); //do after send operations for per message _queue.Info.AddDelivery(); message.Decision = await _queue.DeliveryHandler.ConsumerReceived(_queue, delivery, receiver.Client); } else { message.Decision = await _queue.DeliveryHandler.ConsumerReceiveFailed(_queue, delivery, receiver.Client); } if (!await _queue.ApplyDecision(message.Decision, message)) { return(PushResult.Success); } message.Decision = await _queue.DeliveryHandler.EndSend(_queue, message); await _queue.ApplyDecision(message.Decision, message); if (message.Decision.Allow && message.Decision.PutBack == PutBackDecision.No) { _queue.Info.AddMessageRemove(); _ = _queue.DeliveryHandler.MessageDequeued(_queue, message); } return(PushResult.Success); }
/// <summary> /// Called when a new client is connected via HMQ protocol /// </summary> public async Task <HorseServerSocket> Connected(IHorseServer server, IConnectionInfo connection, ConnectionData data) { string clientId; bool found = data.Properties.TryGetValue(HorseHeaders.CLIENT_ID, out clientId); if (!found || string.IsNullOrEmpty(clientId)) { clientId = _server.ClientIdGenerator.Create(); } //if another client with same unique id is online, do not accept new client MqClient foundClient = _server.FindClient(clientId); if (foundClient != null) { await connection.Socket.SendAsync(HmqWriter.Create(MessageBuilder.Busy())); return(null); } if (_server.Options.ClientLimit > 0 && _server.GetOnlineClients() >= _server.Options.ClientLimit) { return(null); } //creates new mq client object MqClient client = new MqClient(_server, connection, _server.MessageIdGenerator, _server.Options.UseMessageId); client.Data = data; client.UniqueId = clientId.Trim(); client.Token = data.Properties.GetStringValue(HorseHeaders.CLIENT_TOKEN); client.Name = data.Properties.GetStringValue(HorseHeaders.CLIENT_NAME); client.Type = data.Properties.GetStringValue(HorseHeaders.CLIENT_TYPE); //authenticates client foreach (IClientAuthenticator authenticator in _server.Authenticators) { client.IsAuthenticated = await authenticator.Authenticate(_server, client); if (!client.IsAuthenticated) { await client.SendAsync(MessageBuilder.Unauthorized()); return(null); } } //client authenticated, add it into the connected clients list _server.AddClient(client); //send response message to the client, client should check unique id, //if client's unique id isn't permitted, server will create new id for client and send it as response await client.SendAsync(MessageBuilder.Accepted(client.UniqueId)); foreach (IClientHandler handler in _server.ClientHandlers) { await handler.Connected(_server, client); } return(client); }
private async Task <PushResult> ProcessMessage(QueueMessage message) { //if we need acknowledge from receiver, it has a deadline. DateTime?ackDeadline = null; if (_queue.Options.Acknowledge != QueueAckDecision.None) { ackDeadline = DateTime.UtcNow.Add(_queue.Options.AcknowledgeTimeout); } //if to process next message is requires previous message acknowledge, wait here if (_queue.Options.Acknowledge == QueueAckDecision.WaitForAcknowledge) { await _queue.WaitForAcknowledge(message); } //if there are not receivers, complete send operation List <QueueClient> clients = _queue.ClientsClone; if (clients.Count == 0) { _queue.AddMessage(message, false); return(PushResult.NoConsumers); } if (message.CurrentDeliveryReceivers.Count > 0) { message.CurrentDeliveryReceivers.Clear(); } message.Decision = await _queue.DeliveryHandler.BeginSend(_queue, message); if (!await _queue.ApplyDecision(message.Decision, message)) { return(PushResult.Success); } //create prepared message data byte[] messageData = HmqWriter.Create(message.Message); Decision final = new Decision(false, false, PutBackDecision.No, DeliveryAcknowledgeDecision.None); bool messageIsSent = false; //to all receivers foreach (QueueClient client in clients) { //to only online receivers if (!client.Client.IsConnected) { continue; } //call before send and check decision Decision ccrd = await _queue.DeliveryHandler.CanConsumerReceive(_queue, message, client.Client); final = HorseQueue.CreateFinalDecision(final, ccrd); if (!ccrd.Allow) { continue; } //create delivery object MessageDelivery delivery = new MessageDelivery(message, client, ackDeadline); //send the message bool sent = await client.Client.SendAsync(messageData); if (sent) { if (_queue.Options.Acknowledge != QueueAckDecision.None) { client.CurrentlyProcessing = message; client.ProcessDeadline = ackDeadline ?? DateTime.UtcNow; } messageIsSent = true; message.CurrentDeliveryReceivers.Add(client); //adds the delivery to time keeper to check timing up _queue.TimeKeeper.AddAcknowledgeCheck(delivery); //mark message is sent delivery.MarkAsSent(); //do after send operations for per message _queue.Info.AddDelivery(); Decision d = await _queue.DeliveryHandler.ConsumerReceived(_queue, delivery, client.Client); final = HorseQueue.CreateFinalDecision(final, d); } else { Decision d = await _queue.DeliveryHandler.ConsumerReceiveFailed(_queue, delivery, client.Client); final = HorseQueue.CreateFinalDecision(final, d); } } message.Decision = final; if (!await _queue.ApplyDecision(final, message)) { return(PushResult.Success); } //after all sending operations completed, calls implementation send completed method and complete the operation if (messageIsSent) { _queue.Info.AddMessageSend(); } message.Decision = await _queue.DeliveryHandler.EndSend(_queue, message); await _queue.ApplyDecision(message.Decision, message); if (message.Decision.Allow && message.Decision.PutBack == PutBackDecision.No) { _queue.Info.AddMessageRemove(); _ = _queue.DeliveryHandler.MessageDequeued(_queue, message); } return(PushResult.Success); }
private async Task <PushResult> ProcessMessage(QueueMessage message) { //if there are not receivers, complete send operation List <QueueClient> clients = _queue.ClientsClone; if (clients.Count == 0) { _queue.Info.AddMessageRemove(); return(PushResult.NoConsumers); } message.Decision = await _queue.DeliveryHandler.BeginSend(_queue, message); if (!await _queue.ApplyDecision(message.Decision, message)) { return(PushResult.Success); } //create prepared message data byte[] messageData = HmqWriter.Create(message.Message); bool messageIsSent = false; //to all receivers foreach (QueueClient client in clients) { //to only online receivers if (!client.Client.IsConnected) { continue; } //call before send and check decision Decision ccrd = await _queue.DeliveryHandler.CanConsumerReceive(_queue, message, client.Client); if (!ccrd.Allow) { continue; } //send the message _ = client.Client.SendAsync(messageData); messageIsSent = true; //do after send operations for per message _queue.Info.AddDelivery(); } //after all sending operations completed, calls implementation send completed method and complete the operation if (messageIsSent) { _queue.Info.AddMessageSend(); } message.Decision = await _queue.DeliveryHandler.EndSend(_queue, message); await _queue.ApplyDecision(message.Decision, message); if (message.Decision.Allow && message.Decision.PutBack == PutBackDecision.No) { _queue.Info.AddMessageRemove(); } return(PushResult.Success); }