Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

250 lines
4.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "MessageEndpoint.h"
#include "Misc/Guid.h"
#include "IMessageContext.h"
#include "IMessageRpcCall.h"
#include "Async/IAsyncProgress.h"
#include "Async/IAsyncTask.h"
#include "Async/Future.h"
#include "Async/AsyncResult.h"
/**
* Interface for RPC clients.
*/
class IMessageRpcClient
{
/** Abstract base class for RPC calls. */
class FCall
: public IAsyncProgress
, public IAsyncTask
, public IMessageRpcCall
{
public:
FCall()
: State(EAsyncTaskState::Running)
, TimeCreated(FDateTime::UtcNow())
{ }
public:
FSimpleDelegate& OnCancelled()
{
return CanceledDelegate;
}
public:
virtual TOptional<float> GetCompletion() override
{
return Completion;
}
virtual FText GetStatusText() override
{
return StatusText;
}
virtual FSimpleDelegate& OnProgressChanged() override
{
return ProgressChangedDelegate;
}
public:
virtual void Cancel() override
{
State = EAsyncTaskState::Cancelled;
CanceledDelegate.ExecuteIfBound();
}
virtual EAsyncTaskState GetTaskState() override
{
return State;
}
public:
virtual FDateTime GetLastUpdated() const override
{
return LastUpdated;
}
virtual FDateTime GetTimeCreated() const override
{
return TimeCreated;
}
virtual void UpdateProgress(float InCompletion, const FText& InStatusText) override
{
Completion = InCompletion;
StatusText = InStatusText;
LastUpdated = FDateTime::UtcNow();
ProgressChangedDelegate.ExecuteIfBound();
}
protected:
float Completion;
FDateTime LastUpdated;
EAsyncTaskState State;
FText StatusText;
FDateTime TimeCreated;
private:
FSimpleDelegate CanceledDelegate;
FSimpleDelegate ProgressChangedDelegate;
};
/** Template for RPC requests. */
template<typename RpcType, typename... P>
class TCall
: public FCall
{
public:
TCall(const FGuid& CallId, P... Params)
: MessageTemplate(new typename RpcType::FRequest(Params...))
{
MessageTemplate->CallId = CallId;
}
virtual ~TCall()
{
delete MessageTemplate;
}
virtual void Complete(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& ResponseContext) override
{
if (ResponseContext->GetMessageTypeInfo() == RpcType::FResponse::StaticStruct())
{
State = EAsyncTaskState::Completed;
Promise.SetValue(static_cast<const typename RpcType::FResponse*>(ResponseContext->GetMessage())->Result);
}
else
{
State = EAsyncTaskState::Failed;
Promise.SetValue(typename RpcType::FResult());
}
}
virtual void* ConstructMessage() const override
{
return FMessageEndpoint::MakeMessage<typename RpcType::FRequest>(*MessageTemplate);
}
TFuture<typename RpcType::FResult> GetFuture()
{
return Promise.GetFuture();
}
virtual const FGuid& GetId() const override
{
return MessageTemplate->CallId;
}
virtual void* GetMessageTemplate() const override
{
return MessageTemplate;
}
virtual UScriptStruct* GetMessageType() const override
{
return RpcType::FRequest::StaticStruct();
}
virtual void TimeOut() override
{
State = EAsyncTaskState::Failed;
Promise.SetValue(typename RpcType::FResult());
}
private:
TPromise<typename RpcType::FResult> Promise;
typename RpcType::FRequest* MessageTemplate;
};
public:
/**
* Connect this client to an RPC server.
*
* @param InServerAddress The RPC server's message address.
* @see Disconnect
*/
virtual void Connect(const FMessageAddress& InServerAddress) = 0;
/**
* Disconnect this client from the RPC server.
*
* @see Connect
*/
virtual void Disconnect() = 0;
/**
* Whether the MessageRpcClient is currently connected to an RPC server.
*
* @return true if the client is connected, false otherwise.
*/
virtual bool IsConnected() const = 0;
public:
/**
* Call a remote procedure.
*
* @param RpcType The RPC type definition.
* @param P The call parameter types.
* @param Params The call parameter list.
*/
template<typename RpcType, typename... P>
TAsyncResult<typename RpcType::FResult> Call(P... Params)
{
typedef TCall<RpcType, P...> CallType;
FGuid CallId = FGuid::NewGuid();
TSharedRef<CallType> Call = MakeShareable(new CallType(CallId, Params...));
{
AddCall(Call);
Call->OnCancelled().BindLambda([this, CallId]() {
CancelCall(CallId);
});
}
return TAsyncResult<typename RpcType::FResult>(Call->GetFuture(), Call, Call);
}
protected:
/**
* Add an RPC request.
*
* @param Request The call to add.
*/
virtual void AddCall(const TSharedRef<IMessageRpcCall>& Call) = 0;
/**
* Cancel the specified RPC call.
*
* @param CallId The unique identifier of the call to cancel.
*/
virtual void CancelCall(const FGuid& CallId) = 0;
public:
/** Virtual destructor. */
virtual ~IMessageRpcClient() { }
};
Expose_TNameOf(IMessageRpcClient)