Files
UnrealEngine/Engine/Source/Runtime/Messaging/Private/Bridge/MessageBridge.cpp
2025-05-18 13:04:45 +08:00

262 lines
5.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Bridge/MessageBridge.h"
#include "IMessagingModule.h"
#include "IMessageBus.h"
#include "IMessageSubscription.h"
#include "IMessageTransport.h"
/* FMessageBridge structors
*****************************************************************************/
FMessageBridge::FMessageBridge(
const FMessageAddress InAddress,
const TSharedRef<IMessageBus, ESPMode::ThreadSafe>& InBus,
const TSharedRef<IMessageTransport, ESPMode::ThreadSafe>& InTransport
)
: Address(InAddress)
, Bus(InBus)
, Enabled(false)
, Id(FGuid::NewGuid())
, Transport(InTransport)
{
Bus->OnShutdown().AddRaw(this, &FMessageBridge::HandleMessageBusShutdown);
}
FMessageBridge::~FMessageBridge()
{
Disable();
if (Bus.IsValid())
{
Bus->OnShutdown().RemoveAll(this);
Bus->Unregister(Address);
TArray<FMessageAddress> RemovedAddresses;
AddressBook.RemoveAll(RemovedAddresses);
for (const auto& RemovedAddress : RemovedAddresses)
{
Bus->Unregister(RemovedAddress);
}
}
}
/* IMessageBridge interface
*****************************************************************************/
void FMessageBridge::Disable()
{
if (!Enabled)
{
return;
}
// disable subscription & transport
if (MessageSubscription.IsValid())
{
MessageSubscription->Disable();
}
if (Transport.IsValid())
{
Transport->StopTransport();
}
Enabled = false;
}
void FMessageBridge::Enable()
{
if (Enabled || !Bus.IsValid() || !Transport.IsValid())
{
return;
}
// enable subscription & transport
if (!Transport->StartTransport(*this))
{
return;
}
Bus->Register(Address, AsShared());
if (MessageSubscription.IsValid())
{
MessageSubscription->Enable();
}
else
{
MessageSubscription = Bus->Subscribe(AsShared(), IMessageBus::PATHNAME_All, FMessageScopeRange::AtLeast(EMessageScope::Network));
}
Enabled = true;
}
bool FMessageBridge::IsEnabled() const
{
return Enabled;
}
FGuid FMessageBridge::LookupAddress(const FMessageAddress &InAddress)
{
if (InAddress.IsValid())
{
TArray<FGuid> RemoteNodes = AddressBook.GetNodesFor({InAddress});
ensure(RemoteNodes.Num() <= 1);
if (RemoteNodes.Num()>0 && RemoteNodes[0].IsValid())
{
return RemoteNodes[0];
}
}
return {};
}
/* IMessageReceiver interface
*****************************************************************************/
FName FMessageBridge::GetDebugName() const
{
return *FString::Printf(TEXT("FMessageBridge (%s)"), *Transport->GetDebugName().ToString());
}
const FGuid& FMessageBridge::GetRecipientId() const
{
return Id;
}
ENamedThreads::Type FMessageBridge::GetRecipientThread() const
{
return ENamedThreads::AnyThread;
}
bool FMessageBridge::IsLocal() const
{
return false;
}
void FMessageBridge::ReceiveMessage(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context)
{
UE_LOG(LogMessaging, Verbose, TEXT("Received %s message from %s"), *Context->GetMessageTypePathName().ToString(), *Context->GetSender().ToString());
if (!Enabled)
{
return;
}
// get remote nodes
TArray<FGuid> RemoteNodes;
if (Context->GetRecipients().Num() > 0)
{
RemoteNodes = AddressBook.GetNodesFor(Context->GetRecipients());
if (RemoteNodes.Num() == 0)
{
return;
}
}
// forward message to remote nodes
Transport->TransportMessage(Context, RemoteNodes);
}
/* IMessageSender interface
*****************************************************************************/
FMessageAddress FMessageBridge::GetSenderAddress()
{
return Address;
}
void FMessageBridge::NotifyMessageError(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const FString& Error)
{
// deprecated
}
/* IMessageTransportHandler interface
*****************************************************************************/
void FMessageBridge::DiscoverTransportNode(const FGuid& NodeId)
{
// do nothing (address book is updated in ReceiveTransportMessage)
}
void FMessageBridge::ForgetTransportNode(const FGuid& NodeId)
{
TArray<FMessageAddress> RemovedAddresses;
// update address book
AddressBook.RemoveNode(NodeId, RemovedAddresses);
// unregister endpoints
if (Bus.IsValid())
{
for (const auto& RemovedAddress : RemovedAddresses)
{
Bus->Unregister(RemovedAddress);
}
}
}
void FMessageBridge::ReceiveTransportMessage(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const FGuid& NodeId)
{
if (UE_GET_LOG_VERBOSITY(LogMessaging) >= ELogVerbosity::Verbose)
{
FString RecipientStr = FString::JoinBy(Context->GetRecipients(), TEXT("+"), &FMessageAddress::ToString);
UE_LOG(LogMessaging, Verbose, TEXT("FMessageBridge::ReceiveTransportMessage: Received %s from %s for %s"),
*Context->GetMessageTypePathName().ToString(),
*Context->GetSender().ToString(),
*RecipientStr);
}
if (!Enabled || !Bus.IsValid())
{
return;
}
// discard expired messages
if (Context->GetExpiration() < FDateTime::UtcNow())
{
UE_LOG(LogMessaging, Verbose, TEXT("FMessageBridge::ReceiveTransportMessage: Message expired. Discarding"));
return;
}
// register newly discovered endpoints
if (!AddressBook.Contains(Context->GetSender()))
{
UE_LOG(LogMessaging, Verbose, TEXT("FMessageBridge::ReceiveTransportMessage: Registering new sender %s"), *Context->GetMessageTypePathName().ToString());
AddressBook.Add(Context->GetSender(), NodeId);
Bus->Register(Context->GetSender(), AsShared());
}
// forward message to local bus
Bus->Forward(Context, Context->GetRecipients(), FTimespan::Zero(), AsShared());
}
/* FMessageBridge callbacks
*****************************************************************************/
void FMessageBridge::HandleMessageBusShutdown()
{
Disable();
Bus.Reset();
}