Exemplo n.º 1
0
        /// <summary>
        /// Creates and returns a new brokered message based on the specified message descriptor.
        /// </summary>
        /// <param name="messageDescriptor">The <see cref="IMessageDescriptor">message descriptor</see> to prepare.</param>
        /// <returns>A new, prepared <see cref="BrokeredMessage">message</see>.</returns>
        protected virtual BrokeredMessage ToBrokeredMessage(IMessageDescriptor messageDescriptor)
        {
            Arg.NotNull(messageDescriptor, nameof(messageDescriptor));
            Contract.Ensures(Contract.Result <BrokeredMessage>() != null);

            var stream = new MemoryStream();
            var writer = new StreamWriter(stream, UTF8);

            Configuration.JsonSerializer.Serialize(writer, messageDescriptor.Message);
            writer.Flush();
            stream.Position = 0L;

            var brokeredMessage = new BrokeredMessage(stream, ownsStream: true)
            {
                MessageId     = messageDescriptor.MessageId,
                ContentType   = "application/json",
                CorrelationId = messageDescriptor.Message.CorrelationId,
                Label         = messageDescriptor.Message.GetType().Name,
                Properties    =
                {
                    ["Type"]     = messageDescriptor.MessageType,
                    ["Revision"] = messageDescriptor.Message.Revision,
                },
            };

            if (messageDescriptor.AggregateId != null)
            {
                brokeredMessage.Properties["AggregateId"] = messageDescriptor.AggregateId;
            }

            return(brokeredMessage);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Occurs when a message is received by the bus.
        /// </summary>
        /// <param name="messageDescriptor">The received <see cref="IMessageDescriptor">message descriptor</see>.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken">token</see> that can be used to cancel the operation.</param>
        /// <returns>The <see cref="Task">task</see> representing the asynchronous operation.</returns>
        protected virtual async Task OnMessageReceived(IMessageDescriptor messageDescriptor, CancellationToken cancellationToken)
        {
            Arg.NotNull(messageDescriptor, nameof(messageDescriptor));

            var context = NewMessageContext(commandSender, this, cancellationToken);
            await dispatcher.Dispatch(messageDescriptor.Message, context).ConfigureAwait(false);
        }
Exemplo n.º 3
0
 public void OnNext(IMessageDescriptor value)
 {
     foreach (var observer in observers)
     {
         observer.OnNext(value);
     }
 }
        /// <summary>
        /// Sends a message.
        /// </summary>
        /// <param name="messageSender">The extended <see cref="IMessageSender"/>.</param>
        /// <param name="message">The <see cref="IMessageDescriptor">message</see> to send.</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken">token</see> that can be used to cancel the operation.</param>
        /// <returns>A <see cref="Task">task</see> representing the asynchronous operation.</returns>
        public static Task Send(this IMessageSender messageSender, IMessageDescriptor message, CancellationToken cancellationToken)
        {
            Arg.NotNull(messageSender, nameof(messageSender));
            Arg.NotNull(message, nameof(message));

            return(messageSender.Send(new[] { message }, cancellationToken));
        }
Exemplo n.º 5
0
        public async ValueTask StoreAsync(IMessageDescriptor descriptor, IMessage message, CancellationToken cancellationToken = default)
        {
            if (descriptor == null)
            {
                throw new System.ArgumentNullException(nameof(descriptor));
            }
            if (message == null)
            {
                throw new System.ArgumentNullException(nameof(message));
            }
            var hash = await _messageHasher.HashAsync(descriptor, message, cancellationToken : cancellationToken);

            string messageString = null;

            try
            {
                if (descriptor is IRichMessageDescriptor rich && rich.Raw != null && rich.Raw.Length != 0)
                {
                    messageString = Encoding.UTF8.GetString(rich.Raw);
                }
                else
                {
                    messageString = _messageConverter.SerializeString(message);
                }
            }
Exemplo n.º 6
0
        public void Publish(IMessageDescriptor descriptor, byte[] message)
        {
            if (!_persistentConnection.IsConnected)
            {
                _persistentConnection.TryConnect();
            }

            using (var channel = _persistentConnection.CreateModel())
            {
                channel.ExchangeDeclare(exchange: descriptor.MessageGroup,
                                        durable: true,
                                        type: "topic");


                var properties = channel.CreateBasicProperties();
                properties.DeliveryMode = 2; // persistent

                if (descriptor is IRichMessageDescriptor rich && rich.Headers != null)
                {
                    var headers = properties.Headers = properties.Headers ?? new Dictionary <string, object>();
                    foreach (var item in rich.Headers)
                    {
                        headers.Add(item.Key, item.Value);
                    }
                }

                channel.BasicPublish(exchange: descriptor.MessageGroup,
                                     routingKey: descriptor.MessageTopic,
                                     mandatory: true,
                                     basicProperties: properties,
                                     body: message);
            }
        }
Exemplo n.º 7
0
        public Type Resolve(IMessageDescriptor descriptor, IEnumerable <Type> types)
        {
            if (descriptor == null)
            {
                return(null);
            }
            if (string.IsNullOrWhiteSpace(descriptor.MessageTopic))
            {
                return(null);
            }
            if (types == null)
            {
                return(null);
            }

            var messageType = types.Select(type => new
            {
                Type       = type,
                Descriptor = Resolve(type)
            })
                              .FirstOrDefault(x => MessageDescriptorEqualityComparer.Instance.Equals(x.Descriptor, descriptor))
                              ?.Type;

            return(messageType);
        }
Exemplo n.º 8
0
        protected async ValueTask <bool> IsExistsAsync(IMessageDescriptor descriptor, IMessage message, CancellationToken cancellationToken = default)
        {
            var hash = await _messageHasher.HashAsync(descriptor, message, cancellationToken : cancellationToken);

            var model = await _storageProvider.FindAsync(hash, cancellationToken);

            return
                (string.Equals(model.Group, descriptor?.MessageGroup)
                 &&
                 string.Equals(model.Topic, descriptor?.MessageTopic));
        }
Exemplo n.º 9
0
 public async ValueTask <bool> IsConsumedAsync(IMessageDescriptor descriptor, IMessage message, CancellationToken cancellationToken = default)
 {
     if (descriptor == null)
     {
         throw new System.ArgumentNullException(nameof(descriptor));
     }
     if (message == null)
     {
         throw new System.ArgumentNullException(nameof(message));
     }
     return(await base.IsExistsAsync(descriptor, message, cancellationToken));
 }
Exemplo n.º 10
0
        /// <summary>
        /// Saves the specified event descriptor using the provided command.
        /// </summary>
        /// <typeparam name="TKey">The type of key.</typeparam>
        /// <param name="command">The <see cref="DbCommand">database command</see> used to save the event.</param>
        /// <param name="eventDescriptor">The <see cref="EventDescriptor{TKey}">event descriptor</see> that
        /// describes the event being saved.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken">token</see> that can be used to cancel the operation.</param>
        /// <returns>A <see cref="Task">task</see> representing the asynchronous operation.</returns>
        public virtual Task SaveEvent <TKey>(DbCommand command, EventDescriptor <TKey> eventDescriptor, CancellationToken cancellationToken)
        {
            Arg.NotNull(command, nameof(command));
            Arg.NotNull(eventDescriptor, nameof(eventDescriptor));

            IMessageDescriptor messageDescriptor = eventDescriptor;

            command.Parameters["AggregateId"].Value = eventDescriptor.AggregateId;
            command.Parameters["Version"].Value     = eventDescriptor.Event.Version;
            command.Parameters["Sequence"].Value    = eventDescriptor.Event.Sequence;
            command.Parameters["Type"].Value        = messageDescriptor.MessageType;
            command.Parameters["Revision"].Value    = eventDescriptor.Event.Revision;
            command.Parameters["Message"].Value     = EventSerializer.Serialize(eventDescriptor.Event);

            return(command.ExecuteNonQueryAsync(cancellationToken));
        }
Exemplo n.º 11
0
    public MessageContext(Type messageType, IMessageDescriptor descriptor, IServiceProvider serviceProvider)
    {
        _messageType     = messageType;
        _serviceProvider = serviceProvider;

        Handlers         = ResolveHandlers(descriptor.Handlers).ToLazyReadOnlyCollection();
        IndirectHandlers = ResolveHandlers(descriptor.IndirectHandlers).ToLazyReadOnlyCollection();

        PostHandlers         = ResolvePostHandlers(descriptor.PostHandlers).ToLazyReadOnlyCollection();
        IndirectPostHandlers = ResolvePostHandlers(descriptor.IndirectPostHandlers).ToLazyReadOnlyCollection();

        PreHandlers         = ResolvePreHandlers(descriptor.PreHandlers).ToLazyReadOnlyCollection();
        IndirectPreHandlers = ResolvePreHandlers(descriptor.IndirectPreHandlers).ToLazyReadOnlyCollection();

        ErrorHandlers         = ResolveErrorHandlers(descriptor.ErrorHandlers).ToLazyReadOnlyCollection();
        IndirectErrorHandlers = ResolveErrorHandlers(descriptor.IndirectErrorHandlers).ToLazyReadOnlyCollection();
    }
Exemplo n.º 12
0
        /// <summary>
        /// Subscribe on the message broadcasting.
        /// </summary>
        /// <param name="descriptor">Message instance. Same instance must be used for the broadcasting (through @ref Broadcast)</param>
        /// <param name="handler">Handler that should be invoked when <see cref="Broadcast"/> will be called.</param>
        /// <param name="owner">Used only for development/debug prurposes. String representation of this parameter (if specified) will be displayed withing MessageViewer</param>
        /// <returns></returns>
        public ISubscription AddSubscription(IMessageDescriptor descriptor, Action <object[]> handler, object owner)
        {
            var messageType = descriptor.GetType();

            MessageDelegate messageDelegate = null;

            lock (m_messageDelegates)
            {
                messageDelegate = m_messageDelegates.Find(m => m.MessageType == messageType);

                if (messageDelegate == null)
                {
                    messageDelegate = new MessageDelegate(messageType);

                    m_messageDelegates.Add(messageDelegate);
                }
            }

            return(messageDelegate.AddSubscription(handler, owner));
        }
Exemplo n.º 13
0
        public IMessage Deserialize(IMessageDescriptor descriptor, byte[] message)
        {
            if (descriptor == null)
            {
                return(null);
            }
            if (string.IsNullOrWhiteSpace(descriptor.MessageTopic))
            {
                return(null);
            }
            if (message == null || message.Length == 0)
            {
                return(null);
            }
            var allMessageTypes = _messageHandlerFactoryStore.GetAllHandledMessageTypes();
            var type            = _messageTopicResolver.Resolve(descriptor, allMessageTypes);

            if (type == null)
            {
                return(null);
            }
            if (!typeof(IMessage).IsAssignableFrom(type))
            {
                return(null);
            }
            var stringMessage = Encoding.UTF8.GetString(message);

            IMessage typedMessageObject = null;

            try
            {
                // typedMessageObject = JsonConvert.DeserializeObject(stringMessage, type) as IMessage;
                typedMessageObject = JsonSerializer.Deserialize(stringMessage, type) as IMessage;
            }
            catch (System.Exception e)
            {
                _logger.LogError(e, "反序列化消息失败");
            }

            return(typedMessageObject);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Broadcast message: invoke corresponding handlers with passed (possible partially) parameters.
        /// </summary>
        /// <param name="instance">Message instance. Same instance must be used for subscription (through @ref AddSubscription).</param>
        /// <param name="parameters">Pass directly</param>
        public void Broadcast(IMessageDescriptor instance, params object[] parameters)
        {
            var messageType = instance.GetType();

            var messageDelegate = m_messageDelegates.Find(d => d.MessageType == messageType);

            if (
                messageDelegate != null &&
                messageDelegate.Invoke(parameters))
            {
                return;
            }

            var descAttrib = ReflectionUtils.GetCustomAttribute <MessageDescriptionAttribute>(messageType);

            var handlerRequirement = descAttrib == null ? HandlerRequirement.Default : descAttrib.HandlerRequirement;

            switch (handlerRequirement)
            {
            case HandlerRequirement.Default:
            {    //#todo add ConsoleOutput Utility
#if UNITY_EDITOR
                UnityEngine.Debug.LogWarningFormat("There is no registered handlers for [{0}]", messageType);
#endif
                break;
            }

            case HandlerRequirement.NotRequired:
            {
                break;
            }

            case HandlerRequirement.Required:
            {
                throw new Exception(string.Format("Message '{0}' must be handled by its requirement ! ", messageType));
            }
            }
        }
Exemplo n.º 15
0
        public async ValueTask <string> HashAsync(
            IMessageDescriptor descriptor,
            IMessage message,
            HashAlgorithmName algorism          = default,
            CancellationToken cancellationToken = default)
        {
            algorism = (algorism == default) ? HashAlgorithmName.SHA1 : algorism;

            byte[] raw = null;

            if (descriptor is IRichMessageDescriptor rich)
            {
                if (rich.Raw != null && rich.Raw.Length != 0)
                {
                    raw = rich.Raw;
                }
                else if (!string.IsNullOrWhiteSpace(rich.MessageId))
                {
                    raw = Encoding.UTF8.GetBytes(rich.MessageId);
                }
            }
            if (raw == null)
            {
                try
                {
                    raw = _messageConverter.Serialize(message);
                }
                catch (Exception)
                {
                }
            }
            if (raw == null)
            {
                return("SRC-ERROR");
            }
            return(await Task.Run(async() => await HashBodyAsync(descriptor, raw, algorism, cancellationToken)));
        }
Exemplo n.º 16
0
 public async ValueTask <string> HashBodyAsync(
     IMessageDescriptor descriptor,
     byte[] messageBody,
     HashAlgorithmName algorism          = default,
     CancellationToken cancellationToken = default)
 {
     algorism = (algorism == default) ? HashAlgorithmName.SHA1 : algorism;
     return(await Task.Run(() =>
     {
         try
         {
             using (var hasher = HashAlgorithm.Create(algorism.Name))
             {
                 var hash = hasher.ComputeHash(messageBody);
                 var hashString = string.Join("", hash.Select(b => b.ToString("x2")));
                 return hashString;
             }
         }
         catch (Exception e)
         {
             return $"HASH-ERROR: {e.Message}";
         }
     }));
 }
Exemplo n.º 17
0
        private IModel CreateConsumerChannel(IMessageDescriptor descriptor)
        {
            const string MODE = "topic";

            if (_channels.TryGetValue(descriptor, out var exists))
            {
                Logger.LogWarning($"CreateConsumerChannel: Channel is already created");
                return(exists);
            }

            var channel = _persistentConnection.CreateModel();

            void onModelShutdown(object sender, ShutdownEventArgs eventArgs)
            {
                var model = sender as IModel;

                switch (eventArgs.Initiator)
                {
                case ShutdownInitiator.Application:
                    if (eventArgs.ReplyCode == 200)
                    {
                        model.ModelShutdown -= onModelShutdown;
                        Logger.LogInformation($"CreateConsumerChannel: channel { model.ChannelNumber} shutdown by app.");
                        _channels.TryRemove(descriptor, out var _);
                        return;
                    }
                    break;

                case ShutdownInitiator.Library:
                    if (eventArgs.ReplyCode == 541)     //Unhandled Exception
                    {
                        var shutdownReason = (eventArgs.Cause as Exception).Message;
                        Logger.LogWarning($"CreateConsumerChannel: channel { model.ChannelNumber} shutdown, Initiator: {eventArgs.Initiator}, caused by :{(eventArgs.Cause as Exception).Message}");
                    }
                    break;

                case ShutdownInitiator.Peer:
                    break;

                default:
                    break;
                }
            }

            channel.ModelShutdown += onModelShutdown;

            channel.ExchangeDeclare(exchange: descriptor.MessageGroup,
                                    durable: true,
                                    type: MODE);

            var queueName = _messageBusOptions.QueuePerConsumer != false
                            ? string.Concat(_messageBusOptions.QueueName, "-", descriptor.MessageTopic)
                            : _messageBusOptions.QueueName;

            channel.QueueDeclare(queue: queueName,
                                 durable: true,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);

            channel.QueueBind(queue: queueName,
                              exchange: descriptor.MessageGroup,
                              routingKey: descriptor.MessageTopic);


            var consumer = new AsyncEventingBasicConsumer(channel);

            consumer.Shutdown += ConsumerShutdown;

            consumer.Received += ConsumerMessageReceived;

            var consumerTag = channel.BasicConsume(queue: queueName,
                                                   autoAck: false,
                                                   consumer: consumer);

            Logger.LogInformation($"CreateConsumerChannel: Exchange: {descriptor.MessageGroup}, RoutingKey: {descriptor.MessageTopic}, Mode:{MODE}, Queue: {queueName}, ConsumerTag: {consumerTag}");
            _channels.TryAdd(descriptor, channel);
            return(channel);
        }
Exemplo n.º 18
0
 public ValueTask PublishAsync(IMessageDescriptor descriptor, byte[] message)
 {
     return(new ValueTask(Task.Run(() => Publish(descriptor, message))));
 }
Exemplo n.º 19
0
 /// <summary>
 /// Default ctor.
 /// </summary>
 /// <param name="topic">话题</param>
 /// <param name="message">消息</param>
 public MessageWrapper(IMessageDescriptor descriptor, IMessage message)
 {
     this.Descriptor = descriptor;
     this.Message    = message;
 }
Exemplo n.º 20
0
 public void Subscribe(IMessageDescriptor descriptor, Action <IMessage, IRichMessageDescriptor> handler) => Subscribe(descriptor, (message, _descriptor) =>
 {
     handler?.Invoke(message, _descriptor);
     return(new ValueTask());
 });
Exemplo n.º 21
0
 public void UnSubscribe(IMessageDescriptor descriptor)
 {
     _subscribers.TryRemove(descriptor, out var value);
 }
Exemplo n.º 22
0
 public void Subscribe(IMessageDescriptor descriptor, Func <IMessage, IRichMessageDescriptor, ValueTask> asyncHandler)
 {
     Logger.LogInformation($"Subscribing: Exchange: {descriptor.MessageGroup}, Topic: {descriptor.MessageTopic}");
     _subscribers.AddOrUpdate(descriptor, asyncHandler, (desc, oldValue) => asyncHandler);
     CreateConsumerChannel(descriptor);
 }
Exemplo n.º 23
0
 public void Subscribe(IMessageDescriptor descriptor, Func <IMessage, ValueTask> asyncHandler) => Subscribe(descriptor, async(msg, desc) => await asyncHandler(msg));