Files
UnrealEngine/Engine/Source/Runtime/Online/BuildPatchServices/Private/Installer/MessagePump.cpp
2025-05-18 13:04:45 +08:00

149 lines
4.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Installer/MessagePump.h"
#include "Containers/Union.h"
#include "Containers/Queue.h"
#include <atomic>
namespace BuildPatchServices
{
// Union of all possible message types.
typedef TUnion<FChunkSourceEvent, FInstallationFileAction, FGenericMessage> FMessageUnion;
// Queue type for messages.
typedef TQueue<FMessageUnion, EQueueMode::Mpsc> FMessageQueue;
// Tuple of the request and response for finding a chunk uri location
typedef TTuple<FChunkUriRequest, TFunction<void(FChunkUriResponse)>> FChunkUriRequestResponse;
// Queue of request responses of chunk we are looking for
typedef TQueue<FChunkUriRequestResponse, EQueueMode::Mpsc> FChunkUriQueue;
}
namespace MessagePumpHelpers
{
template<typename Type>
bool TryPump(const TArray<BuildPatchServices::FMessageHandler*>& Handlers, const BuildPatchServices::FMessageUnion& MessageUnion)
{
if (MessageUnion.HasSubtype<Type>())
{
for (BuildPatchServices::FMessageHandler* Handler : Handlers)
{
Handler->HandleMessage(MessageUnion.GetSubtype<Type>());
}
return true;
}
return false;
}
}
namespace BuildPatchServices
{
class FMessagePump
: public IMessagePump
{
public:
// IMessagePump interface begin.
virtual void SendMessage(FChunkSourceEvent Message) override;
virtual void SendMessage(FInstallationFileAction Message) override;
virtual void SendMessage(FGenericMessage Message) override;
virtual bool SendRequest(FChunkUriRequest Request, TFunction<void(FChunkUriResponse)> OnResponse) override;
virtual void PumpMessages() override;
virtual void RegisterMessageHandler(FMessageHandler* MessageHandler) override;
virtual void UnregisterMessageHandler(FMessageHandler* MessageHandler) override;
// IMessagePump interface end.
private:
FMessageQueue MessageQueue;
FChunkUriQueue ChunkUriRequestQueue;
FDefaultMessageHandler DefaultMessageHandler;
TArray<FMessageHandler*> Handlers;
// std::atomic will not expose integral operations with enum types.
std::atomic<uint32> MessageRequests{0};
};
void FMessagePump::SendMessage(FGenericMessage Message)
{
MessageQueue.Enqueue(FMessageUnion(MoveTemp(Message)));
}
void FMessagePump::SendMessage(FChunkSourceEvent Message)
{
MessageQueue.Enqueue(FMessageUnion(MoveTemp(Message)));
}
void FMessagePump::SendMessage(FInstallationFileAction Message)
{
MessageQueue.Enqueue(FMessageUnion(MoveTemp(Message)));
}
bool FMessagePump::SendRequest(FChunkUriRequest Request, TFunction<void(FChunkUriResponse)> OnResponse)
{
if (EnumHasAllFlags(static_cast<EMessageRequests>(MessageRequests.load()), EMessageRequests::ChunkUriRequest))
{
ChunkUriRequestQueue.Enqueue(FChunkUriRequestResponse(MoveTemp(Request), MoveTemp(OnResponse)));
return true;
}
return false;
}
void FMessagePump::PumpMessages()
{
FMessageUnion MessageUnion;
while (MessageQueue.Dequeue(MessageUnion))
{
if (MessagePumpHelpers::TryPump<FChunkSourceEvent>(Handlers, MessageUnion))
{
continue;
}
else if (MessagePumpHelpers::TryPump<FInstallationFileAction>(Handlers, MessageUnion))
{
continue;
}
else if (MessagePumpHelpers::TryPump<FGenericMessage>(Handlers, MessageUnion))
{
continue;
}
}
FChunkUriRequestResponse ChunkUriRequestResponse;
while (ChunkUriRequestQueue.Dequeue(ChunkUriRequestResponse))
{
bool bHandled = false;
for (BuildPatchServices::FMessageHandler* Handler : Handlers)
{
if (Handler->HandleRequest(ChunkUriRequestResponse.Get<0>(), ChunkUriRequestResponse.Get<1>()))
{
bHandled = true;
break;
}
}
if (!bHandled)
{
DefaultMessageHandler.HandleRequest(ChunkUriRequestResponse.Get<0>(), ChunkUriRequestResponse.Get<1>());
}
}
}
void FMessagePump::RegisterMessageHandler(FMessageHandler* InHandler)
{
MessageRequests |= static_cast<uint32>(InHandler->GetMessageRequests());
Handlers.Add(InHandler);
}
void FMessagePump::UnregisterMessageHandler(FMessageHandler* InHandler)
{
MessageRequests = 0;
Handlers.Remove(InHandler);
for (FMessageHandler* Handler : Handlers)
{
MessageRequests |= static_cast<uint32>(Handler->GetMessageRequests());
}
}
IMessagePump* FMessagePumpFactory::Create()
{
return new FMessagePump();
}
}