// Copyright Epic Games, Inc. All Rights Reserved. #include "Bus/MessageBus.h" #include "IMessagingModule.h" #include "HAL/RunnableThread.h" #include "Bus/MessageRouter.h" #include "Bus/MessageContext.h" #include "Bus/MessageSubscription.h" #include "IMessageSender.h" #include "IMessageReceiver.h" #include "HAL/ThreadSingleton.h" const FTopLevelAssetPath IMessageBus::PATHNAME_All(TEXT("/Unknown"), NAME_All); /* FMessageBus structors *****************************************************************************/ FMessageBus::FMessageBus(FString InName, const TSharedPtr& InRecipientAuthorizer) : Name(MoveTemp(InName)) , RecipientAuthorizer(InRecipientAuthorizer) { Router = new FMessageRouter(); RouterThread = FRunnableThread::Create(Router, *FString::Printf(TEXT("FMessageBus.%s.Router"), *Name), 128 * 1024, TPri_Normal, FPlatformAffinity::GetPoolThreadMask()); check(Router != nullptr); } FMessageBus::~FMessageBus() { Shutdown(); delete Router; } /* IMessageBus interface *****************************************************************************/ void FMessageBus::Forward( const TSharedRef& Context, const TArray& Recipients, const FTimespan& Delay, const TSharedRef& Forwarder ) { if (UE_GET_LOG_VERBOSITY(LogMessaging) >= ELogVerbosity::Verbose) { FString RecipientStr = FString::JoinBy(Context->GetRecipients(), TEXT("+"), &FMessageAddress::ToString); UE_LOG(LogMessaging, Verbose, TEXT("Forwarding %s from %s to %s"), *Context->GetMessageTypePathName().ToString(), *Context->GetSender().ToString(), *RecipientStr); } Router->RouteMessage(MakeShareable(new FMessageContext( Context, Forwarder->GetSenderAddress(), Recipients, EMessageScope::Process, FDateTime::UtcNow() + Delay, FTaskGraphInterface::Get().GetCurrentThreadIfKnown() ))); } TSharedRef FMessageBus::GetTracer() { return Router->GetTracer(); } void FMessageBus::Intercept(const TSharedRef& Interceptor, const FTopLevelAssetPath& MessageType) { if (MessageType.IsNull()) { return; } if (!RecipientAuthorizer.IsValid() || RecipientAuthorizer->AuthorizeInterceptor(Interceptor, MessageType)) { UE_LOG(LogMessaging, Verbose, TEXT("Adding invterceptor %s"), *Interceptor->GetDebugName().ToString()); Router->AddInterceptor(Interceptor, MessageType); } } FOnMessageBusShutdown& FMessageBus::OnShutdown() { return ShutdownDelegate; } void FMessageBus::Publish( void* Message, UScriptStruct* TypeInfo, EMessageScope Scope, const TMap& Annotations, const FTimespan& Delay, const FDateTime& Expiration, const TSharedRef& Publisher ) { UE_LOG(LogMessaging, Verbose, TEXT("Publishing %s from sender %s"), *TypeInfo->GetName(), *Publisher->GetSenderAddress().ToString()); Router->RouteMessage(MakeShared( Message, TypeInfo, Annotations, nullptr, Publisher->GetSenderAddress(), TArray(), Scope, EMessageFlags::None, FDateTime::UtcNow() + Delay, Expiration, FTaskGraphInterface::Get().GetCurrentThreadIfKnown() )); } void FMessageBus::Register(const FMessageAddress& Address, const TSharedRef& Recipient) { UE_LOG(LogMessaging, Verbose, TEXT("Registering %s"), *Address.ToString()); Router->AddRecipient(Address, Recipient); } void FMessageBus::Send( void* Message, UScriptStruct* TypeInfo, EMessageFlags Flags, const TMap& Annotations, const TSharedPtr& Attachment, const TArray& Recipients, const FTimespan& Delay, const FDateTime& Expiration, const TSharedRef& Sender ) { UE_LOG(LogMessaging, Verbose, TEXT("Sending %s to %d recipients"), *TypeInfo->GetName(), Recipients.Num()); Router->RouteMessage(MakeShared( Message, TypeInfo, Annotations, Attachment, Sender->GetSenderAddress(), Recipients, EMessageScope::Network, Flags, FDateTime::UtcNow() + Delay, Expiration, FTaskGraphInterface::Get().GetCurrentThreadIfKnown() )); } void FMessageBus::Shutdown() { if (RouterThread != nullptr) { ShutdownDelegate.Broadcast(); RouterThread->Kill(true); delete RouterThread; RouterThread = nullptr; } } TSharedPtr FMessageBus::Subscribe( const TSharedRef& Subscriber, const FTopLevelAssetPath& MessageType, const FMessageScopeRange& ScopeRange ) { if (!MessageType.IsNull()) { if (!RecipientAuthorizer.IsValid() || RecipientAuthorizer->AuthorizeSubscription(Subscriber, MessageType)) { UE_LOG(LogMessaging, Verbose, TEXT("Subscribing %s"), *Subscriber->GetDebugName().ToString()); TSharedRef Subscription = MakeShareable(new FMessageSubscription(Subscriber, MessageType, ScopeRange)); Router->AddSubscription(Subscription); return Subscription; } } return nullptr; } void FMessageBus::Unintercept(const TSharedRef& Interceptor, const FTopLevelAssetPath& MessageType) { if (!MessageType.IsNull()) { UE_LOG(LogMessaging, Verbose, TEXT("Unintercepting %s"), *Interceptor->GetDebugName().ToString()); Router->RemoveInterceptor(Interceptor, MessageType); } } void FMessageBus::Unregister(const FMessageAddress& Address) { UE_LOG(LogMessaging, Verbose, TEXT("Attempting to unregister %s"), *Address.ToString()); if (!RecipientAuthorizer.IsValid() || RecipientAuthorizer->AuthorizeUnregistration(Address)) { UE_LOG(LogMessaging, Verbose, TEXT("Unregistered %s"), *Address.ToString()); Router->RemoveRecipient(Address); } } void FMessageBus::Unsubscribe(const TSharedRef& Subscriber, const FTopLevelAssetPath& MessageType) { if (!MessageType.IsNull()) { if (!RecipientAuthorizer.IsValid() || RecipientAuthorizer->AuthorizeUnsubscription(Subscriber, MessageType)) { UE_LOG(LogMessaging, Verbose, TEXT("Unsubscribing %s"), *Subscriber->GetDebugName().ToString()); Router->RemoveSubscription(Subscriber, MessageType); } } } void FMessageBus::AddNotificationListener(const TSharedRef& Listener) { Router->AddNotificationListener(Listener); } void FMessageBus::RemoveNotificationListener(const TSharedRef& Listener) { Router->RemoveNotificationListener(Listener); } const FString& FMessageBus::GetName() const { return Name; } // IMessageBus deprecated functions void IMessageBus::Intercept(const TSharedRef& Interceptor, const FName& MessageType) { Intercept(Interceptor, UClass::TryConvertShortTypeNameToPathName(MessageType.ToString())); } TSharedPtr IMessageBus::Subscribe(const TSharedRef& Subscriber, const FName& MessageType, const TRange& ScopeRange) { return Subscribe(Subscriber, UClass::TryConvertShortTypeNameToPathName(MessageType.ToString()), ScopeRange); } void IMessageBus::Unintercept(const TSharedRef& Interceptor, const FName& MessageType) { Unintercept(Interceptor, UClass::TryConvertShortTypeNameToPathName(MessageType.ToString())); } void IMessageBus::Unsubscribe(const TSharedRef& Subscriber, const FName& MessageType) { Unsubscribe(Subscriber, UClass::TryConvertShortTypeNameToPathName(MessageType.ToString())); }