Ejemplo n.º 1
0
        /// <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}");
            }
        }
Ejemplo n.º 2
0
        /// <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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        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);
                }
            }
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
0
        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);
        }