/// <summary> /// Clears messages in a queue /// </summary> private async Task ClearMessages(MqClient client, HorseMessage message) { HorseQueue queue = _server.FindQueue(message.Target); if (queue == null) { if (message.WaitResponse) { await client.SendAsync(message.CreateResponse(HorseResultCode.NotFound)); } return; } string prio = message.FindHeader(HorseHeaders.PRIORITY_MESSAGES); string msgs = message.FindHeader(HorseHeaders.MESSAGES); bool clearPrio = !string.IsNullOrEmpty(prio) && prio.Equals("yes", StringComparison.InvariantCultureIgnoreCase); bool clearMsgs = !string.IsNullOrEmpty(msgs) && msgs.Equals("yes", StringComparison.InvariantCultureIgnoreCase); foreach (IAdminAuthorization authorization in _server.AdminAuthorizations) { bool grant = await authorization.CanClearQueueMessages(client, queue, clearPrio, clearMsgs); if (!grant) { if (message.WaitResponse) { await client.SendAsync(message.CreateResponse(HorseResultCode.Unauthorized)); } return; } } if (clearPrio && clearMsgs) { queue.ClearAllMessages(); } else if (clearPrio) { queue.ClearHighPriorityMessages(); } else if (clearMsgs) { queue.ClearRegularMessages(); } //if creation successful, sends response if (message.WaitResponse) { await client.SendAsync(message.CreateResponse(HorseResultCode.Ok)); } }
/// <summary> /// Gets queue. /// If it's not cached, finds and caches it before returns. /// </summary> /// <returns></returns> private async Task <HorseQueue> GetQueue(HorseMessage message) { if (_targetQueue != null) { return(_targetQueue); } string queueName = message.FindHeader(HorseHeaders.QUEUE_NAME); if (queueName == null) { return(null); } HorseQueue queue = Router.Server.FindQueue(queueName); if (queue != null) { _targetQueue = queue; return(_targetQueue); } _targetQueue = await Router.Server.CreateQueue(queueName, Router.Server.Options, message, null, true, true); return(_targetQueue); }
/// <summary> /// Reads Clear header value and returns as enum /// </summary> private static ClearDecision FindClearDecision(HorseMessage request) { string clearStr = request.FindHeader(HorseHeaders.CLEAR); if (string.IsNullOrEmpty(clearStr)) { return(ClearDecision.None); } clearStr = clearStr.Trim(); if (clearStr.Equals("all", StringComparison.InvariantCultureIgnoreCase)) { return(ClearDecision.All); } if (clearStr.Equals("high-priority", StringComparison.InvariantCultureIgnoreCase)) { return(ClearDecision.HighPriority); } if (clearStr.Equals("default-priority", StringComparison.InvariantCultureIgnoreCase)) { return(ClearDecision.DefaultPriority); } return(ClearDecision.None); }
public async Task Handle(MqClient client, HorseMessage message, bool fromNode) { HorseQueue queue = await FindQueue(client, message.Target, message); if (queue == null) { return; } //if there is at least one cc header //we need to create a clone of the message //clone does not have cc headers but others HorseMessage clone = null; List <string> ccList = null; List <KeyValuePair <string, string> > additionalHeaders = null; if (message.HasHeader && message.FindHeader(HorseHeaders.CC) != null) { additionalHeaders = message.Headers.Where(x => !x.Key.Equals(HorseHeaders.CC, StringComparison.InvariantCultureIgnoreCase)).ToList(); ccList = new List <string>(message.Headers.Where(x => x.Key.Equals(HorseHeaders.CC, StringComparison.InvariantCultureIgnoreCase)).Select(x => x.Value)); clone = message.Clone(false, true, _server.MessageIdGenerator.Create(), additionalHeaders); } await HandlePush(client, message, queue, true); //if there are cc headers, we will push the message to other queues if (clone != null) { await PushOtherQueues(client, clone, ccList, additionalHeaders); } }
/// <summary> /// Creates new router /// </summary> private async Task CreateRouter(MqClient client, HorseMessage message) { IRouter found = _server.FindRouter(message.Target); if (found != null) { await client.SendAsync(message.CreateResponse(HorseResultCode.Ok)); return; } string methodHeader = message.FindHeader(HorseHeaders.ROUTE_METHOD); RouteMethod method = RouteMethod.Distribute; if (!string.IsNullOrEmpty(methodHeader)) { method = (RouteMethod)Convert.ToInt32(methodHeader); } //check create queue access foreach (IClientAuthorization authorization in _server.Authorizations) { bool grant = await authorization.CanCreateRouter(client, message.Target, method); if (!grant) { await client.SendAsync(message.CreateResponse(HorseResultCode.Unauthorized)); return; } } _server.AddRouter(message.Target, method); await client.SendAsync(message.CreateResponse(HorseResultCode.Ok)); }
/// <summary> /// Reads Count header value and returns as integer /// </summary> private static int FindCount(HorseMessage request) { string countStr = request.FindHeader(HorseHeaders.COUNT); if (string.IsNullOrEmpty(countStr)) { return(0); } return(Convert.ToInt32(countStr.Trim())); }
/// <summary> /// Reads Order header value and returns as true false. /// If true, it's fifo (as default). /// If false, it's lifo. /// </summary> private static bool FindOrder(HorseMessage request) { string orderStr = request.FindHeader(HorseHeaders.ORDER); if (string.IsNullOrEmpty(orderStr)) { return(true); } bool lifo = orderStr.Trim().Equals(HorseHeaders.LIFO, StringComparison.InvariantCultureIgnoreCase); return(!lifo); }
/// <summary> /// Removes a router with it's bindings /// </summary> private async Task RemoveRouterBinding(MqClient client, HorseMessage message) { IRouter router = _server.FindRouter(message.Target); if (router == null) { await client.SendAsync(message.CreateResponse(HorseResultCode.NotFound)); return; } string name = message.FindHeader(HorseHeaders.BINDING_NAME); if (string.IsNullOrEmpty(name)) { await client.SendAsync(message.CreateResponse(HorseResultCode.NotFound)); return; } Binding[] bindings = router.GetBindings(); Binding binding = bindings.FirstOrDefault(x => x.Name == name); if (binding == null) { await client.SendAsync(message.CreateResponse(HorseResultCode.NotFound)); return; } //check create queue access foreach (IClientAuthorization authorization in _server.Authorizations) { bool grant = await authorization.CanRemoveBinding(client, binding); if (!grant) { await client.SendAsync(message.CreateResponse(HorseResultCode.Unauthorized)); return; } } router.RemoveBinding(binding); await client.SendAsync(message.CreateResponse(HorseResultCode.Ok)); }
public async Task InPersistentHandler() { ConfigurationFactory.Destroy(); PersistentDeliveryHandler handler = null; HorseServer server = new HorseServer(); HorseMq mq = server.UseHorseMq(cfg => cfg .AddPersistentQueues(q => q.KeepLastBackup()) .UseDeliveryHandler(async builder => { DatabaseOptions options = new DatabaseOptions { Filename = "redelivery-test.tdb", InstantFlush = true, CreateBackupOnShrink = false, ShrinkInterval = TimeSpan.FromSeconds(60) }; handler = new PersistentDeliveryHandler(builder.Queue, options, DeleteWhen.AfterSend, ProducerAckDecision.None, true); await handler.Initialize(); return(handler); })); HorseQueue queue = await mq.CreateQueue("test"); HorseMessage message = new HorseMessage(MessageType.QueueMessage, "test"); message.SetMessageId("id"); message.SetStringContent("Hello, World!"); QueueMessage queueMessage = new QueueMessage(message); await handler.BeginSend(queue, queueMessage); List <KeyValuePair <string, int> > deliveries = handler.RedeliveryService.GetDeliveries(); Assert.Single(deliveries); Assert.Equal("id", deliveries[0].Key); Assert.Equal(1, deliveries[0].Value); string header = message.FindHeader(HorseHeaders.DELIVERY); Assert.Null(header); await handler.BeginSend(queue, queueMessage); deliveries = handler.RedeliveryService.GetDeliveries(); Assert.Single(deliveries); Assert.Equal("id", deliveries[0].Key); Assert.Equal(2, deliveries[0].Value); header = message.FindHeader(HorseHeaders.DELIVERY); Assert.NotNull(header); Assert.Equal(2, Convert.ToInt32(header)); queueMessage.MarkAsSent(); await handler.EndSend(queue, queueMessage); deliveries = handler.RedeliveryService.GetDeliveries(); Assert.Empty(deliveries); }
/// <summary> /// Reads Info header value and returns as boolean /// </summary> private static bool FindInfoRequest(HorseMessage request) { string infoStr = request.FindHeader(HorseHeaders.INFO); return(!string.IsNullOrEmpty(infoStr) && infoStr.Trim().Equals("Yes", StringComparison.InvariantCultureIgnoreCase)); }
public Task Handle(MqClient client, HorseMessage message, bool fromNode) { string eventName = message.Target; string queueName = message.FindHeader(HorseHeaders.QUEUE_NAME); bool subscribe = message.ContentType == 1; HorseQueue queue = !string.IsNullOrEmpty(queueName) ? _server.FindQueue(queueName) : null; if (subscribe) { foreach (IClientAuthorization authorization in _server.Authorizations) { if (!authorization.CanSubscribeEvent(client, queue)) { return(SendResponse(client, message, false)); } } } switch (eventName) { case EventNames.MessageProduced: if (queue == null) { return(SendResponse(client, message, false)); } if (subscribe) { queue.OnMessageProduced.Subscribe(client); } else { queue.OnMessageProduced.Unsubscribe(client); } return(SendResponse(client, message, true)); case EventNames.ClientConnected: if (subscribe) { _server.OnClientConnected.Subscribe(client); } else { _server.OnClientConnected.Unsubscribe(client); } return(SendResponse(client, message, true)); case EventNames.ClientDisconnected: if (subscribe) { _server.OnClientDisconnected.Subscribe(client); } else { _server.OnClientDisconnected.Unsubscribe(client); } return(SendResponse(client, message, true)); case EventNames.Subscribe: if (queue == null) { return(SendResponse(client, message, false)); } if (subscribe) { queue.OnConsumerSubscribed.Subscribe(client); } else { queue.OnConsumerSubscribed.Unsubscribe(client); } return(SendResponse(client, message, true)); case EventNames.Unsubscribe: if (queue == null) { return(SendResponse(client, message, false)); } if (subscribe) { queue.OnConsumerUnsubscribed.Subscribe(client); } else { queue.OnConsumerUnsubscribed.Unsubscribe(client); } return(SendResponse(client, message, true)); case EventNames.QueueCreated: if (subscribe) { _server.OnQueueCreated.Subscribe(client); } else { _server.OnQueueCreated.Unsubscribe(client); } return(SendResponse(client, message, true)); case EventNames.QueueUpdated: if (subscribe) { _server.OnQueueUpdated.Subscribe(client); } else { _server.OnQueueUpdated.Unsubscribe(client); } return(SendResponse(client, message, true)); case EventNames.QueueRemoved: if (subscribe) { _server.OnQueueRemoved.Subscribe(client); } else { _server.OnQueueRemoved.Unsubscribe(client); } return(SendResponse(client, message, true)); } return(Task.CompletedTask); }
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 { } } }