コード例 #1
0
        /// <summary>
        /// Creates new channel with custom event handler, authenticator and options
        /// </summary>
        /// <exception cref="OperationCanceledException">Thrown when channel limit is exceeded for the server</exception>
        /// <exception cref="DuplicateNameException">Thrown when there is already a channel with same name</exception>
        public Channel CreateChannel(string name,
                                     IChannelAuthenticator authenticator,
                                     IChannelEventHandler eventHandler,
                                     IMessageDeliveryHandler deliveryHandler,
                                     Action <ChannelOptions> optionsAction)
        {
            ChannelOptions options = ChannelOptions.CloneFrom(Options);

            optionsAction(options);
            return(CreateChannel(name, authenticator, eventHandler, deliveryHandler, options));
        }
コード例 #2
0
        /// <summary>
        /// Sets status of the queue
        /// </summary>
        public async Task SetStatus(QueueStatus status, IMessageDeliveryHandler newDeliveryHandler = null)
        {
            QueueStatus prevStatus = Status;
            IQueueState prevState  = State;

            if (prevStatus == status)
            {
                return;
            }

            QueueStatusAction leave = await State.LeaveStatus(status);

            if (leave == QueueStatusAction.Deny)
            {
                return;
            }

            if (leave == QueueStatusAction.DenyAndTrigger)
            {
                await Trigger();

                return;
            }

            Status = status;
            State  = QueueStateFactory.Create(this, status);

            QueueStatusAction enter = await State.EnterStatus(prevStatus);

            if (enter == QueueStatusAction.Deny || enter == QueueStatusAction.DenyAndTrigger)
            {
                Status = prevStatus;
                State  = prevState;
                await prevState.EnterStatus(prevStatus);

                if (enter == QueueStatusAction.DenyAndTrigger)
                {
                    await Trigger();
                }

                return;
            }

            if (Channel.EventHandler != null)
            {
                await Channel.EventHandler.OnQueueStatusChanged(this, prevStatus, status);
            }

            if (enter == QueueStatusAction.AllowAndTrigger)
            {
                _ = Trigger();
            }
        }
コード例 #3
0
        /// <summary>
        /// Creates new queue in the channel
        /// </summary>
        /// <exception cref="NoNullAllowedException">Thrown when server does not have default delivery handler implementation</exception>
        /// <exception cref="OperationCanceledException">Thrown when queue limit is exceeded for the channel</exception>
        /// <exception cref="DuplicateNameException">Thrown when there is already a queue with same id</exception>
        public async Task <ChannelQueue> CreateQueue(ushort queueId,
                                                     ChannelQueueOptions options,
                                                     IMessageDeliveryHandler deliveryHandler)
        {
            if (deliveryHandler == null)
            {
                throw new NoNullAllowedException("Delivery handler cannot be null.");
            }

            //multiple queues are not allowed
            if (!Options.AllowMultipleQueues && _queues.Count > 0)
            {
                return(null);
            }

            //if content type is not allowed for this channel, return null
            if (Options.AllowedQueues != null && Options.AllowedQueues.Length > 0)
            {
                if (!Options.AllowedQueues.Contains(queueId))
                {
                    return(null);
                }
            }

            if (Options.QueueLimit > 0 && Options.QueueLimit >= _queues.Count)
            {
                throw new OperationCanceledException("Queue limit is exceeded for the channel");
            }

            ChannelQueue queue = _queues.Find(x => x.Id == queueId);

            if (queue != null)
            {
                throw new DuplicateNameException($"The channel has already a queue with same content type: {queueId}");
            }

            queue = new ChannelQueue(this, queueId, options, deliveryHandler);
            _queues.Add(queue);

            if (EventHandler != null)
            {
                await EventHandler.OnQueueCreated(queue, this);
            }

            return(queue);
        }
コード例 #4
0
        /// <summary>
        /// Loads messages of queues in configuration
        /// </summary>
        public async Task LoadQueues(HorseMq server)
        {
            foreach (QueueConfiguration queueConfiguration in Config.Queues)
            {
                HorseQueue queue = server.FindQueue(queueConfiguration.Name);
                if (queue == null)
                {
                    if (server.DeliveryHandlerFactory != null)
                    {
                        queue = await server.CreateQueue(queueConfiguration.Name,
                                                         queueConfiguration.Configuration.ToOptions(),
                                                         async builder =>
                        {
                            builder.DeliveryHandlerHeader   = queueConfiguration.DeliveryHandler;
                            IMessageDeliveryHandler handler = await server.DeliveryHandlerFactory(builder);
                            builder.OnAfterCompleted(b => { });                                  //don't trigger created events, it's already created and reloading
                            return(handler);
                        });
                    }
                    else
                    {
                        queue = await Extensions.CreateQueue(server,
                                                             queueConfiguration.Name,
                                                             (DeleteWhen)queueConfiguration.DeleteWhen,
                                                             (ProducerAckDecision)queueConfiguration.ProducerAck,
                                                             queueConfiguration.Configuration.ToOptions());
                    }

                    //queue creation not permitted, skip
                    if (queue == null)
                    {
                        continue;
                    }
                }
                else
                {
                    if (queue.DeliveryHandler is IPersistentDeliveryHandler deliveryHandler)
                    {
                        await deliveryHandler.Initialize();
                    }
                }

                queueConfiguration.Queue = queue;
            }
        }
コード例 #5
0
        internal Channel(MqServer server,
                         ChannelOptions options,
                         string name,
                         IChannelAuthenticator authenticator,
                         IChannelEventHandler eventHandler,
                         IMessageDeliveryHandler deliveryHandler)
        {
            Server  = server;
            Options = options;
            Name    = name;

            Authenticator   = authenticator;
            EventHandler    = eventHandler;
            DeliveryHandler = deliveryHandler;

            _queues  = new SafeList <ChannelQueue>(8);
            _clients = new SafeList <ChannelClient>(256);
        }
コード例 #6
0
        /// <summary>
        /// Creates new channel with custom event handler, authenticator and options
        /// </summary>
        /// <exception cref="OperationCanceledException">Thrown when channel limit is exceeded for the server</exception>
        /// <exception cref="DuplicateNameException">Thrown when there is already a channel with same name</exception>
        public Channel CreateChannel(string name,
                                     IChannelAuthenticator authenticator,
                                     IChannelEventHandler eventHandler,
                                     IMessageDeliveryHandler deliveryHandler,
                                     ChannelOptions options)
        {
            if (Options.ChannelLimit > 0 && _channels.Count >= Options.ChannelLimit)
            {
                throw new OperationCanceledException("Channel limit is exceeded for the server");
            }

            Channel channel = _channels.Find(x => x.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));

            if (channel != null)
            {
                throw new DuplicateNameException("There is already a channel with same name: " + name);
            }

            channel = new Channel(this, options, name, authenticator, eventHandler, deliveryHandler);
            _channels.Add(channel);
            return(channel);
        }
コード例 #7
0
        /// <summary>
        /// Creates new queue and sends response
        /// </summary>
        private async Task CreateQueue(MqClient client, TmqMessage message)
        {
            ushort?contentType;
            NetworkOptionsBuilder builder = null;

            if (message.Length == 2)
            {
                byte[] bytes = new byte[2];
                await message.Content.ReadAsync(bytes);

                contentType = BitConverter.ToUInt16(bytes);
            }
            else
            {
                builder = new NetworkOptionsBuilder();
                builder.Load(message.ToString());
                contentType = builder.Id;
            }

            Channel channel = await CreateChannel(client, message, true);

            ChannelQueue queue = channel.FindQueue(contentType.Value);

            //if queue exists, we can't create. return duplicate response.
            if (queue != null)
            {
                if (message.ResponseRequired)
                {
                    await client.SendAsync(MessageBuilder.ResponseStatus(message, KnownContentTypes.Duplicate));
                }

                return;
            }

            //check authority if client can create queue
            if (_server.Authorization != null)
            {
                bool grant = await _server.Authorization.CanCreateQueue(client, channel, contentType.Value, builder);

                if (!grant)
                {
                    if (message.ResponseRequired)
                    {
                        await client.SendAsync(MessageBuilder.ResponseStatus(message, KnownContentTypes.Unauthorized));
                    }

                    return;
                }
            }

            //creates new queue
            ChannelQueueOptions     options  = ChannelQueueOptions.CloneFrom(channel.Options);
            IMessageDeliveryHandler delivery = channel.DeliveryHandler;

            if (builder != null)
            {
                builder.ApplyToQueue(options);
                if (!string.IsNullOrEmpty(builder.MessageDeliveryHandler))
                {
                    IMessageDeliveryHandler found = _server.Registry.GetMessageDelivery(builder.MessageDeliveryHandler);
                    if (found != null)
                    {
                        delivery = found;
                    }
                }
            }

            queue = await channel.CreateQueue(contentType.Value, options, delivery);

            //if creation successful, sends response
            if (queue != null && message.ResponseRequired)
            {
                await client.SendAsync(MessageBuilder.ResponseStatus(message, KnownContentTypes.Ok));
            }
        }
コード例 #8
0
        /// <summary>
        /// Creates new channel
        /// </summary>
        private async Task <Channel> CreateChannel(MqClient client, TmqMessage message, bool createForQueue)
        {
            Channel channel = _server.FindChannel(message.Target);

            if (channel != null)
            {
                return(channel);
            }

            //check create channel access
            if (_server.Authorization != null)
            {
                bool grant = await _server.Authorization.CanCreateChannel(client, _server, message.Target);

                if (!grant)
                {
                    if (message.ResponseRequired)
                    {
                        await client.SendAsync(MessageBuilder.ResponseStatus(message, KnownContentTypes.Unauthorized));
                    }

                    return(null);
                }
            }

            if (!createForQueue && message.Length > 0 && message.Content != null && message.Content.Length > 0)
            {
                NetworkOptionsBuilder builder = new NetworkOptionsBuilder();
                builder.Load(message.ToString());

                ChannelOptions options = ChannelOptions.CloneFrom(_server.Options);
                builder.ApplyToChannel(options);

                IChannelEventHandler eventHandler = _server.DefaultChannelEventHandler;
                if (!string.IsNullOrEmpty(builder.ChannelEventHandler))
                {
                    IChannelEventHandler e = _server.Registry.GetChannelEvent(builder.ChannelEventHandler);
                    if (e != null)
                    {
                        eventHandler = e;
                    }
                }

                IChannelAuthenticator authenticator = _server.DefaultChannelAuthenticator;
                if (!string.IsNullOrEmpty(builder.ChannelAuthenticator))
                {
                    IChannelAuthenticator e = _server.Registry.GetChannelAuthenticator(builder.ChannelAuthenticator);
                    if (e != null)
                    {
                        authenticator = e;
                    }
                }

                IMessageDeliveryHandler deliveryHandler = _server.DefaultDeliveryHandler;
                if (!string.IsNullOrEmpty(builder.MessageDeliveryHandler))
                {
                    IMessageDeliveryHandler e = _server.Registry.GetMessageDelivery(builder.MessageDeliveryHandler);
                    if (e != null)
                    {
                        deliveryHandler = e;
                    }
                }

                Channel ch = _server.CreateChannel(message.Target, authenticator, eventHandler, deliveryHandler, options);

                if (ch != null && message.ResponseRequired)
                {
                    await client.SendAsync(MessageBuilder.ResponseStatus(message, KnownContentTypes.Ok));
                }
            }

            Channel c = _server.CreateChannel(message.Target);

            if (!createForQueue && c != null && message.ResponseRequired)
            {
                await client.SendAsync(MessageBuilder.ResponseStatus(message, KnownContentTypes.Ok));
            }

            return(c);
        }
コード例 #9
0
ファイル: ServerBuilder.cs プロジェクト: Akrotiri/twino
        /// <summary>
        /// Adds default delivery handler implementation to builder
        /// </summary>
        public void AddDefaultDeliveryHandler <T>(params object[] ctorArgs) where T : class, IMessageDeliveryHandler, new()
        {
            IMessageDeliveryHandler handler = Activator.CreateInstance(typeof(T), ctorArgs) as IMessageDeliveryHandler;

            _messageDeliveryHandler = handler;
        }
コード例 #10
0
ファイル: ServerBuilder.cs プロジェクト: Akrotiri/twino
 /// <summary>
 /// Adds default delivery handler implementation to builder
 /// </summary>
 public void AddDefaultDeliveryHandler <T>() where T : class, IMessageDeliveryHandler, new()
 {
     _messageDeliveryHandler = new T();
 }
コード例 #11
0
ファイル: ServerBuilder.cs プロジェクト: Akrotiri/twino
 /// <summary>
 /// Adds default delivery handler implementation to builder
 /// </summary>
 public void AddDefaultDeliveryHandler(IMessageDeliveryHandler handler)
 {
     _messageDeliveryHandler = handler;
 }
コード例 #12
0
 /// <summary>
 /// Register a message delivery handler to the container
 /// </summary>
 public void Register(string key, IMessageDeliveryHandler value)
 {
     lock (_messageDeliveryHandlers)
         _messageDeliveryHandlers.Add(key, value);
 }
コード例 #13
0
        /// <summary>
        /// Pushes a message into the queue.
        /// </summary>
        internal async Task <PushResult> Push(QueueMessage message, MqClient sender)
        {
            if (!IsInitialized)
            {
                try
                {
                    UpdateOptionsByMessage(message.Message);
                    DeliveryHandlerBuilder handlerBuilder = new DeliveryHandlerBuilder
                    {
                        Server  = Server,
                        Queue   = this,
                        Headers = message.Message.Headers,
                        DeliveryHandlerHeader = message.Message.FindHeader(HorseHeaders.DELIVERY_HANDLER)
                    };

                    IMessageDeliveryHandler deliveryHandler = await Server.DeliveryHandlerFactory(handlerBuilder);

                    InitializeQueue(deliveryHandler);

                    handlerBuilder.TriggerAfterCompleted();
                }
                catch (Exception e)
                {
                    Server.SendError("INITIALIZE_IN_PUSH", e, $"QueueName:{Name}");
                    throw;
                }
            }

            if (Status == QueueStatus.Stopped)
            {
                return(PushResult.StatusNotSupported);
            }

            if (Options.MessageLimit > 0 && PriorityMessagesList.Count + MessagesList.Count >= Options.MessageLimit)
            {
                return(PushResult.LimitExceeded);
            }

            if (Options.MessageSizeLimit > 0 && message.Message.Length > Options.MessageSizeLimit)
            {
                return(PushResult.LimitExceeded);
            }

            //remove operational headers that are should not be sent to consumers or saved to disk
            message.Message.RemoveHeaders(HorseHeaders.DELAY_BETWEEN_MESSAGES,
                                          HorseHeaders.ACKNOWLEDGE,
                                          HorseHeaders.QUEUE_NAME,
                                          HorseHeaders.QUEUE_STATUS,
                                          HorseHeaders.QUEUE_TOPIC,
                                          HorseHeaders.PUT_BACK_DELAY,
                                          HorseHeaders.DELIVERY,
                                          HorseHeaders.DELIVERY_HANDLER,
                                          HorseHeaders.CC);

            //prepare properties
            message.Message.WaitResponse = Options.Acknowledge != QueueAckDecision.None;

            //if message doesn't have message id and "UseMessageId" option is enabled, create new message id for the message
            if (Options.UseMessageId && string.IsNullOrEmpty(message.Message.MessageId))
            {
                message.Message.SetMessageId(Server.MessageIdGenerator.Create());
            }

            //if we have an option maximum wait duration for message, set it after message joined to the queue.
            //time keeper will check this value and if message time is up, it will remove message from the queue.
            if (Options.MessageTimeout > TimeSpan.Zero)
            {
                message.Deadline = DateTime.UtcNow.Add(Options.MessageTimeout);
            }

            if (Options.HideClientNames)
            {
                message.Message.SetSource(null);
            }

            try
            {
                //fire message receive event
                Info.AddMessageReceive();
                Decision decision = await DeliveryHandler.ReceivedFromProducer(this, message, sender);

                message.Decision = decision;

                bool allow = await ApplyDecision(decision, message);

                if (!allow)
                {
                    return(PushResult.Success);
                }

                //trigger message produced event
                OnMessageProduced.Trigger(message);

                if (State.CanEnqueue(message))
                {
                    await RunInListSync(() => AddMessage(message));

                    if (State.TriggerSupported && !_triggering)
                    {
                        _ = Trigger();
                    }
                }
                else
                {
                    _ = State.Push(message);
                }

                return(PushResult.Success);
            }
            catch (Exception ex)
            {
                Server.SendError("PUSH", ex, $"QueueName:{Name}");
                Info.AddError();
                try
                {
                    Decision decision = await DeliveryHandler.ExceptionThrown(this, State.ProcessingMessage, ex);

                    if (State.ProcessingMessage != null)
                    {
                        await ApplyDecision(decision, State.ProcessingMessage);

                        if (!State.ProcessingMessage.IsInQueue)
                        {
                            if (decision.PutBack == PutBackDecision.Start)
                            {
                                AddMessage(State.ProcessingMessage, false);
                            }
                            else if (decision.PutBack == PutBackDecision.End)
                            {
                                AddMessage(State.ProcessingMessage);
                            }
                        }
                    }
                }
                catch //if developer does wrong operation, we should not stop
                {
                }
            }

            return(PushResult.Success);
        }
コード例 #14
0
        /// <summary>
        /// Sets status of the queue
        /// </summary>
        public async Task SetStatus(QueueStatus status, IMessageDeliveryHandler newDeliveryHandler = null)
        {
            QueueStatus prevStatus = Status;

            try
            {
                IQueueState prevState = State;
                if (prevStatus == status)
                {
                    return;
                }

                QueueStatusAction leave = await State.LeaveStatus(status);

                if (leave == QueueStatusAction.Deny)
                {
                    return;
                }

                if (leave == QueueStatusAction.DenyAndTrigger)
                {
                    await Trigger();

                    return;
                }

                Status = status;
                State  = QueueStateFactory.Create(this, status);

                QueueStatusAction enter = await State.EnterStatus(prevStatus);

                if (enter == QueueStatusAction.Deny || enter == QueueStatusAction.DenyAndTrigger)
                {
                    Status = prevStatus;
                    State  = prevState;
                    await prevState.EnterStatus(prevStatus);

                    if (enter == QueueStatusAction.DenyAndTrigger)
                    {
                        await Trigger();
                    }

                    return;
                }

                if (newDeliveryHandler != null)
                {
                    DeliveryHandler = newDeliveryHandler;
                }

                foreach (IQueueEventHandler handler in Server.QueueEventHandlers)
                {
                    await handler.OnStatusChanged(this, prevStatus, status);
                }

                if (enter == QueueStatusAction.AllowAndTrigger)
                {
                    _ = Trigger();
                }
            }
            catch (Exception e)
            {
                Server.SendError("SET_QUEUE_STATUS", e, $"QueueName:{Name}, PrevStatus:{prevStatus} NextStatus:{status}");
            }
        }
コード例 #15
0
ファイル: HorseMq.cs プロジェクト: erkantaylan/horse-mq
        internal async Task <HorseQueue> CreateQueue(string queueName,
                                                     QueueOptions options,
                                                     HorseMessage requestMessage,
                                                     Func <DeliveryHandlerBuilder, Task <IMessageDeliveryHandler> > asyncHandler,
                                                     bool hideException,
                                                     bool returnIfExists)
        {
            await _createQueueLocker.WaitAsync();

            try
            {
                if (!Filter.CheckNameEligibility(queueName))
                {
                    throw new InvalidOperationException("Invalid queue name");
                }

                if (Options.QueueLimit > 0 && Options.QueueLimit >= _queues.Count)
                {
                    throw new OperationCanceledException("Queue limit is exceeded for the server");
                }

                HorseQueue queue = _queues.Find(x => x.Name == queueName);

                if (queue != null)
                {
                    if (returnIfExists)
                    {
                        return(queue);
                    }

                    throw new DuplicateNameException($"The server has already a queue with same name: {queueName}");
                }

                string topic           = null;
                bool   statusSpecified = false; //when queue is created by subscriber, it will be initialized if status is specified
                if (requestMessage != null)
                {
                    string waitForAck = requestMessage.FindHeader(HorseHeaders.ACKNOWLEDGE);
                    if (!string.IsNullOrEmpty(waitForAck))
                    {
                        switch (waitForAck.Trim().ToLower())
                        {
                        case "none":
                            options.Acknowledge = QueueAckDecision.None;
                            break;

                        case "request":
                            options.Acknowledge = QueueAckDecision.JustRequest;
                            break;

                        case "wait":
                            options.Acknowledge = QueueAckDecision.WaitForAcknowledge;
                            break;
                        }
                    }

                    string queueStatus = requestMessage.FindHeader(HorseHeaders.QUEUE_STATUS);
                    if (queueStatus != null)
                    {
                        statusSpecified = true;
                        options.Status  = QueueStatusHelper.FindStatus(queueStatus);
                    }

                    topic = requestMessage.FindHeader(HorseHeaders.QUEUE_TOPIC);

                    string delay = requestMessage.FindHeader(HorseHeaders.DELAY_BETWEEN_MESSAGES);
                    if (!string.IsNullOrEmpty(delay))
                    {
                        options.DelayBetweenMessages = Convert.ToInt32(delay);
                    }
                }

                queue = new HorseQueue(this, queueName, options);
                if (!string.IsNullOrEmpty(topic))
                {
                    queue.Topic = topic;
                }

                DeliveryHandlerBuilder handlerBuilder = new DeliveryHandlerBuilder
                {
                    Server = this,
                    Queue  = queue
                };
                if (requestMessage != null)
                {
                    handlerBuilder.DeliveryHandlerHeader = requestMessage.FindHeader(HorseHeaders.DELIVERY_HANDLER);
                    handlerBuilder.Headers = requestMessage.Headers;
                }

                bool initialize;
                //if queue creation is triggered by consumer subscription, we might skip initialization
                if (requestMessage != null && requestMessage.Type == MessageType.Server && requestMessage.ContentType == KnownContentTypes.Subscribe)
                {
                    initialize = statusSpecified;
                }
                else
                {
                    initialize = true;
                }

                if (initialize)
                {
                    IMessageDeliveryHandler deliveryHandler = await asyncHandler(handlerBuilder);

                    queue.InitializeQueue(deliveryHandler);
                }

                _queues.Add(queue);
                foreach (IQueueEventHandler handler in _queueEventHandlers)
                {
                    await handler.OnCreated(queue);
                }

                if (initialize)
                {
                    handlerBuilder.TriggerAfterCompleted();
                }

                OnQueueCreated.Trigger(queue);
                return(queue);
            }
            catch (Exception e)
            {
                SendError("CREATE_QUEUE", e, $"QueueName:{queueName}");

                if (!hideException)
                {
                    throw;
                }

                return(null);
            }
            finally
            {
                try
                {
                    _createQueueLocker.Release();
                }
                catch
                {
                }
            }
        }