Files
UnrealEngine/Engine/Source/Runtime/Messaging/Public/IMessageBus.h
2025-05-18 13:04:45 +08:00

317 lines
16 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/Array.h"
#include "Delegates/Delegate.h"
#include "Math/Range.h"
#include "Templates/SharedPointer.h"
#include "UObject/TopLevelAssetPath.h"
class FName;
class IMessageAttachment;
class IMessageContext;
class IMessageInterceptor;
class IMessageReceiver;
class IMessageSender;
class IMessageSubscription;
class IMessageTracer;
class IBusListener;
class UScriptStruct;
enum class EMessageBusNotification : uint8;
enum class EMessageScope : uint8;
enum class EMessageFlags : uint32;
struct FDateTime;
struct FMessageAddress;
struct FTimespan;
/** Delegate type for message bus shutdowns. */
DECLARE_MULTICAST_DELEGATE(FOnMessageBusShutdown);
/**
* Interface for message buses.
*
* A message bus is the main logical component to facilitate communication between (possibly distributed) parts of an application
* using Message Passing as its underlying architectural pattern. It allows registered sender and recipient objects, subsequently
* referred to as Message Endpoints, to exchange structured data in the form of user defined messages[1].
*
* Depending on their usage, messages are classified into a number of types, such as commands, events and documents. In Unreal Engine,
* all these messages are modeled with regular built-in or user defined UStructs that may either be empty or contain data in the
* form of FProperty fields[2]. Before being dispatched, messages are internally wrapped into so called Message Context objects
* (IMessageContext) that contain additional information about a message, such as when it was sent and the sender and recipients.
*
* The sending and receiving of messages is not limited to message endpoints within the same thread or process, but may be extended
* to other applications running on the same computer or on other computers connected to a network with so called Message Transport
* Plug-ins, such as the UdpMessaging plug-in that ships with Unreal Engine. The main goal of a message bus is to hide the technical
* details of the underlying transport mechanisms, so that users can focus on implementing their distributed applications rather than
* worrying about how data gets from one endpoint to another. A message bus makes it look as if all senders and recipients are located
* within the same process, regardless of whether that is actually the case or not. It is possible to restrict the reach of messages
* using so called Message Scopes (EMessageScope).
*
* All message recipients (objects implementing the see IMessageReceiver interface) must be registered with the message bus through the
* see IMessageBus.Register method. Before a recipient is destroyed it should unregister itself using the see IMessageBus.Unregister
* method. Message senders (objects implementing the see IMessageSender interface) do not register with the bus, but instead pass a
* reference to themselves each time they send a message. The IMessageReceiver and IMessageSender both are very low-level interfaces
* into the messaging system. Most users will prefer to use instances of the see FMessageEndpoint class instead, which provides a much
* more convenient way of sending and receiving messages.
*
* Message buses in Unreal Engine support the following two common messaging patterns: Request-Reply and Publish-Subscribe. Please note
* that higher level concepts, such as Remote Procedure Call (RPC) are not part of the messaging system, but we may provide them as
* separate features in the future.
*
* In the Request-Reply pattern a message is sent to one or more particular message recipients using the IMessageBus.Send method.
* Message recipients implement the see IMessageRecipient interface and are uniquely identified by their addresses (FMessageAddress).
* After a message is received, the recipients may then reply with another message using the same IMessageBus.Send method. Alternatively,
* a previously received message may be forwarded to another recipient using the see IMessageBus.Forward method. This pattern is useful
* when message recipients already know about each other and wish to communicate directly, i.e. to exchange commands or events.
*
* In the Publish-Subscribe pattern a message is sent to all message recipients on the bus using the see IMessageBus.Publish method.
* Only recipients that previously subscribed to the type of the sent message using the IMessageBus.Subscribe method will actually receive
* the message. All other recipients will not receive the message. After a published message is received, the recipients may respond with
* another message, either directly to the message sender using IMessageBus.Send method, or by publishing another message using the
* the IMessageBus.Publish method. This pattern is useful for discovering recipients on the bus and to message recipients that are unknown.
*
* Most applications will often use a combination of both Request-Reply and Publish-Subscribe. A typical implementation of distributed
* applications involves service providers and service consumers (a service can be any useful functionality provided by a system). The
* service consumers will often publish a special message in order to discover service providers. Service providers are subscribed to these
* special messages and will respond with another message that contains information about the provider and that is sent back directly to the
* consumer. The consumer is now aware of the service provider's existence and its message address, and it can then request services by
* directly sending all subsequent messages directly to it.
*
* The dispatching of sent and published messages to the correct recipients is accomplished by the Message Router, which is an internal
* component of the message bus. The message router maintains an address book of known message endpoints that allows it to determine
* the destination of messages. If a message cannot be delivered, it is forwarded to a so called Dead Letter Channel, which is a queue
* of messages that can be inspected for debugging purposes[3].
*
* It is possible to intercept messages before they are being routed to recipients by registering so called Message Interceptors (objects
* implementing the IMessageInterceptor interface) with the message bus. This feature enables advanced use cases that require inspection or
* manipulation of messages contents, such as message filtering and enriching, splitting and aggregating, re-sequencing or authentication[4].
*
* The messaging system also provides a facility for debugging the system itself through the so called Message Tracer (an internal object
* implementing the see IMessageTracer interface) that can be accessed with the IMessageBus.GetTracer() method. The message tracer is
* currently used in the Messaging Debugger - a visual debugging tool for the Messaging System in Unreal Frontend and the Unreal Editor.
*
* Notes:
*
* [1] The messaging implementation in Unreal Engine is more or less closely following the terminology in the Enterprise Integration
* Patterns book at http://www.eaipatterns.com/eaipatterns.html. A good introduction to messaging concepts can also be found on MSDN
* at http://msdn.microsoft.com/en-us/library/ff647328.aspx
*
* [2] It is currently also required for such structures to implement a specific TStructOpsTypeTraits type trait or otherwise they
* will not be recognized as legal message types. Search for 'WithMessagingHandling' in the code base to find existing examples. We
* hope to remove the need for these type traits soon.
*
* [3] Dead letter channels are not implemented yet.
*
* [4] There are currently no built-in mechanisms for authentication and authorization, but they are on the to-do list.
*
* @see FMessageAddress, FMessageEndpoint, IMessageReceiver, IMessageSender
*/
class IMessageBus
{
public:
/**
* Forwards a previously received message.
*
* Messages can only be forwarded to endpoints within the same process.
*
* @param Context The context of the message to forward.
* @param Recipients The list of message recipients to forward the message to.
* @param Delay The deferral time.
* @param Forwarder The sender that forwards the message.
* @see Publish, Send
*/
virtual void Forward(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay, const TSharedRef<IMessageSender, ESPMode::ThreadSafe>& Forwarder) = 0;
/**
* Gets the message bus tracer.
*
* @return Weak pointer to the tracer object.
*/
virtual TSharedRef<IMessageTracer, ESPMode::ThreadSafe> GetTracer() = 0;
/**
* Adds an interceptor for messages of the specified type.
*
* @param Interceptor The interceptor.
* @param MessageType The type of messages to intercept.
* @see Unintercept
*/
UE_DEPRECATED(5.1, "Types names are now represented by path names. Please use a version of this function that takes an FTopLevelAssetPath as MessageType.")
MESSAGING_API virtual void Intercept(const TSharedRef<IMessageInterceptor, ESPMode::ThreadSafe>& Interceptor, const FName& MessageType);
/**
* Adds an interceptor for messages of the specified type.
*
* @param Interceptor The interceptor.
* @param MessageType The type of messages to intercept.
* @see Unintercept
*/
virtual void Intercept(const TSharedRef<IMessageInterceptor, ESPMode::ThreadSafe>& Interceptor, const FTopLevelAssetPath& MessageType) = 0;
/**
* Sends a message to subscribed recipients.
*
* The bus takes over ownership of the message's memory.
* It must NOT be freed by the caller.
*
* @param Message The message to publish.
* @param TypeInfo The message's type information.
* @param Scope The message scope.
* @param Annotations An optional message annotations header.
* @param Delay The delay after which to send the message.
* @param Expiration The time at which the message expires.
* @param Publisher The message publisher.
* @see Forward, Send
*/
virtual void Publish(void* Message, UScriptStruct* TypeInfo, EMessageScope Scope, const TMap<FName, FString>& Annotations, const FTimespan& Delay, const FDateTime& Expiration, const TSharedRef<IMessageSender, ESPMode::ThreadSafe>& Publisher) = 0;
/**
* Registers a message recipient with the message bus.
*
* @param Address The address of the recipient to register.
* @param Recipient The message recipient.
* @see Unregister
*/
virtual void Register(const FMessageAddress& Address, const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Recipient) = 0;
/**
* Sends a message to multiple recipients.
*
* The bus takes over ownership of the message's memory.
* It must NOT be freed by the caller.
*
* @param Message The message to send.
* @param TypeInfo The message's type information.
* @param Flags The message flags.
* @param Annotations An optional message annotations header.
* @param Attachment The binary data to attach to the message.
* @param Recipients The list of message recipients.
* @param Delay The delay after which to send the message.
* @param Expiration The time at which the message expires.
* @param Sender The message sender.
* @see Forward, Publish
*/
virtual void Send(void* Message, UScriptStruct* TypeInfo, EMessageFlags Flags, const TMap<FName, FString>& Annotations, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay, const FDateTime& Expiration, const TSharedRef<IMessageSender, ESPMode::ThreadSafe>& Sender) = 0;
/**
* Shuts down the message bus.
*
* @see OnShutdown
*/
virtual void Shutdown() = 0;
/**
* Adds a subscription for published messages of the specified type.
*
* Subscriptions allow message consumers to receive published messages from the message bus.
* The returned interface can be used to query the subscription's details and its enabled state.
*
* @param Subscriber The subscriber wishing to receive the messages.
* @param MessageType The type of messages to subscribe to (NAME_All = subscribe to all message types).
* @param ScopeRange The range of message scopes to include in the subscription.
* @return The added subscription, or nullptr if the subscription failed.
* @see Unsubscribe
*/
UE_DEPRECATED(5.1, "Types names are now represented by path names. Please use a version of this function that takes an FTopLevelAssetPath as MessageType.")
MESSAGING_API virtual TSharedPtr<IMessageSubscription, ESPMode::ThreadSafe> Subscribe(const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Subscriber, const FName& MessageType, const TRange<EMessageScope>& ScopeRange);
/**
* Adds a subscription for published messages of the specified type.
*
* Subscriptions allow message consumers to receive published messages from the message bus.
* The returned interface can be used to query the subscription's details and its enabled state.
*
* @param Subscriber The subscriber wishing to receive the messages.
* @param MessageType The type of messages to subscribe to (IMessageBus::PATHNAME_All = subscribe to all message types).
* @param ScopeRange The range of message scopes to include in the subscription.
* @return The added subscription, or nullptr if the subscription failed.
* @see Unsubscribe
*/
virtual TSharedPtr<IMessageSubscription, ESPMode::ThreadSafe> Subscribe(const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Subscriber, const FTopLevelAssetPath& MessageType, const TRange<EMessageScope>& ScopeRange) = 0;
/**
* Removes an interceptor for messages of the specified type.
*
* @param Interceptor The interceptor to remove.
* @param MessageType The type of messages to stop intercepting.
* @see Intercept
*/
UE_DEPRECATED(5.1, "Types names are now represented by path names. Please use a version of this function that takes an FTopLevelAssetPath as MessageType.")
MESSAGING_API virtual void Unintercept(const TSharedRef<IMessageInterceptor, ESPMode::ThreadSafe>& Interceptor, const FName& MessageType);
/**
* Removes an interceptor for messages of the specified type.
*
* @param Interceptor The interceptor to remove.
* @param MessageType The type of messages to stop intercepting.
* @see Intercept
*/
virtual void Unintercept(const TSharedRef<IMessageInterceptor, ESPMode::ThreadSafe>& Interceptor, const FTopLevelAssetPath& MessageType) = 0;
/**
* Unregisters a message recipient from the message bus.
*
* @param Address The address of the recipient to unregister.
* @see Register
*/
virtual void Unregister(const FMessageAddress& Address) = 0;
/**
* Cancels the specified message subscription.
*
* @param Subscriber The subscriber wishing to stop receiving the messages.
* @param MessageType The type of messages to unsubscribe from (NAME_All = all types).
* @see Subscribe
*/
UE_DEPRECATED(5.1, "Types names are now represented by path names. Please use a version of this function that takes an FTopLevelAssetPath as MessageType.")
MESSAGING_API virtual void Unsubscribe(const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Subscriber, const FName& MessageType);
/**
* Cancels the specified message subscription.
*
* @param Subscriber The subscriber wishing to stop receiving the messages.
* @param MessageType The type of messages to unsubscribe from (IMessageBus::PATHNAME_All = all types).
* @see Subscribe
*/
virtual void Unsubscribe(const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Subscriber, const FTopLevelAssetPath& MessageType) = 0;
/**
* Add a listener to the bus notifications
* @param Listener The listener to as to the registration notifications
*/
virtual void AddNotificationListener(const TSharedRef<IBusListener, ESPMode::ThreadSafe>& Listener) = 0;
/**
* Remove a listener to the bus notifications
* @param Listener The listener to remove from the registration notifications
*/
virtual void RemoveNotificationListener(const TSharedRef<IBusListener, ESPMode::ThreadSafe>& Listener) = 0;
/**
* @return The name of this message bus.
*/
virtual const FString& GetName() const = 0;
public:
/**
* Returns a delegate that is executed when the message bus is shutting down.
*
* @return The delegate.
* @see Shutdown
*/
virtual FOnMessageBusShutdown& OnShutdown() = 0;
MESSAGING_API static const FTopLevelAssetPath PATHNAME_All;
public:
/** Virtual destructor. */
virtual ~IMessageBus() { }
};