AuroraRPC/Source/AuRPCPipe.cpp

305 lines
7.0 KiB
C++
Raw Normal View History

2022-07-02 22:08:52 +00:00
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuRPCPipe.cpp
Date: 2022-6-29
Author: Reece
***/
#include <AuroraRuntime.hpp>
#include "AuRPC.hpp"
#include "AuRPCPipe.hpp"
#include "AuRPCPipePacket.hpp"
#include "AuRPCRequest.hpp"
#include "AuRPCChannel.hpp"
#include "AuRPCClientChannel.hpp"
struct RPCTransaction :
AuIO::IAsyncFinishedSubscriber,
AuEnableSharedFromThis<RPCTransaction>
2022-07-02 22:08:52 +00:00
{
AuSPtr<AuIO::IAsyncTransaction> transaction;
AuMemoryViewRead view;
AuRPCPipePacket packet;
2022-07-02 22:08:52 +00:00
void OnAsyncFileOpFinished(AuUInt64 offset, AuUInt32 length) override
2022-07-02 22:08:52 +00:00
{
transaction->SetCallback({});
if (length != view.length)
2022-07-02 22:08:52 +00:00
{
this->Fail();
if (this->packet.clientChannel)
2022-07-02 22:08:52 +00:00
{
this->packet.clientChannel->FatalIOError();
2022-07-02 22:08:52 +00:00
}
}
else
2022-07-02 22:08:52 +00:00
{
this->Sent();
}
}
2022-07-02 22:08:52 +00:00
bool SendClient()
{
if (packet.protPacket)
{
return true;
}
2022-07-02 22:08:52 +00:00
if (!packet.clientRequest)
{
return false;
}
2022-07-02 22:08:52 +00:00
packet.clientRequest->state = ERPCRequestState::eSubmitting;
2022-07-02 22:08:52 +00:00
if (!AuTryInsert(packet.clientChannel->outstandingRequests, packet.clientRequest))
{
return false;
2022-07-02 22:08:52 +00:00
}
return true;
}
2022-07-02 22:08:52 +00:00
void Fail()
{
if (packet.clientChannel)
{
packet.clientRequest->callback->OnResponse(AuRPCResponse(ERPCError::eIOError));
packet.clientRequest->state = ERPCRequestState::eFailed;
2022-07-02 22:08:52 +00:00
}
this->Remove();
}
void Remove()
{
if (packet.clientChannel)
2022-07-02 22:08:52 +00:00
{
AuTryRemove(packet.clientChannel->outstandingRequests, packet.clientRequest);
2022-07-02 22:08:52 +00:00
}
}
2022-07-02 22:08:52 +00:00
void Sent()
{
if (packet.clientRequest)
2022-07-02 22:08:52 +00:00
{
packet.clientRequest->state = ERPCRequestState::eSent;
2022-07-02 22:08:52 +00:00
}
}
};
2022-07-02 22:08:52 +00:00
bool AuRPCPipe::SendPacket(const AuRPCPipePacket &packet)
{
2022-07-02 22:08:52 +00:00
auto ioTransaction = this->pipe->NewAsyncTransaction();
if (!ioTransaction)
{
return false;
}
auto transactionObject = AuMakeShared<RPCTransaction>();
if (!transactionObject)
{
return false;
}
transactionObject->packet = packet;
transactionObject->view = packet.clientRequest ? packet.clientRequest->GetData() : *packet.serverResponse->message;
transactionObject->transaction = ioTransaction;
transactionObject->transaction->SetCallback(transactionObject);
AuWorkerPId_t pid;
if (packet.clientChannel)
{
pid = this->channel->ToContext()->pinnedClientThread;
}
else
{
pid = this->channel->ToContext()->server.worker;
}
2022-07-02 22:08:52 +00:00
if (pid != AuAsync::GetCurrentWorkerPId())
2022-07-02 22:08:52 +00:00
{
AuAsync::NewWorkFunction(pid, [=]()
{
transactionObject->SendClient();
if (!transactionObject->transaction->StartWrite(0, AuSPtr<AuMemoryViewRead>(transactionObject->SharedFromThis(), &transactionObject->view)))
{
transactionObject->Fail();
}
})->Dispatch();
}
else
{
transactionObject->SendClient();
if (!transactionObject->transaction->StartWrite(0, AuSPtr<AuMemoryViewRead>(transactionObject->SharedFromThis(), &transactionObject->view)))
{
transactionObject->Fail();
}
2022-07-02 22:08:52 +00:00
}
return true;
}
AuRPCPipe::~AuRPCPipe()
{
Deinit();
}
AuRPCPipe::AuRPCPipe(AuRPCChannel* channel) : channel(channel)
{
}
// IIOEventListenerFunctional
void AuRPCPipe::OnIOTick()
{
this->OnConnect();
}
void AuRPCPipe::OnIOFailure()
{
SysPushErrorIO("IO Connect Failure");
OnFatalError();
}
void AuRPCPipe::OnIOComplete()
{
//looking for who the fuck asked
//AuLogDbg("Connection watch operation completed successfully");
}
// Pipe callbacks
void AuRPCPipe::OnPipePartialEvent(AuUInt trasnferred)
{
RpcLogDebug("Consumed bytes");
}
void AuRPCPipe::OnPipeSuccessEvent()
{
2022-07-05 20:16:22 +00:00
if (this->isClient_)
{
2022-07-08 03:30:03 +00:00
OnError(false);
2022-07-05 20:16:22 +00:00
return;
}
2022-07-08 03:30:03 +00:00
2022-07-02 22:08:52 +00:00
RpcLogDebug("Waiting for next socket");
this->isOpenWork = GetRPCProcessor()->StartSimpleLSWatch(this->pipe->AsReadChannelIsOpen(),
AuSPtr<AuIO::IIOSimpleEventListener>(this->channel->ToContext(), this));
}
void AuRPCPipe::OnPipeFailureEvent()
{
RpcLogDebug("Couldn't listen...");
this->OnFatalError();
}
2023-10-16 00:54:34 +00:00
void AuRPCPipe::OnPipeReallocEvent(bool bSuccess)
{
}
2022-07-02 22:08:52 +00:00
// IIOBufferedStreamAvailable
bool AuRPCPipe::OnDataAvailable(AuByteBuffer& view)
{
return this->channel->OnDataAvailable(view);
}
void AuRPCPipe::OnFatalError()
{
if (AuExchange(this->errored_, true))
{
return;
}
OnError(true);
}
void AuRPCPipe::OnError(bool fatal)
{
this->channel->OnDisconnect(true);
}
void AuRPCPipe::OnConnect()
{
RpcLogDebug("RPC Pipe connection initiated. Beginning read...");
AuIO::IOPipeRequestAIO req;
2022-12-28 12:09:07 +00:00
req.pAsyncTransaction = this->pipe->NewAsyncTransaction();
req.bIsStream = true;
2022-07-02 22:08:52 +00:00
req.output.type = AuIO::EPipeCallbackType::eTryHandleBufferedPart;
2022-12-28 12:09:07 +00:00
req.output.handleBufferedStream.pOnData = AuSPtr<AuIO::IIOBufferedStreamAvailable>(this->channel->ToContext(), this);
req.pListener = AuSPtr<AuIO::IIOPipeEventListener>(this->channel->ToContext(), this);
2022-07-02 22:08:52 +00:00
// Create a pipe to process an asynchronous repeating stream read transaction of no particular read/EoS limit
this->work = GetRPCProcessor()->ToPipeProcessor()->NewAIOPipe(req);
if (!this->work)
{
SysPushErrorIO("Couldn't create an IO pipe for a new session connection");
this->OnFatalError();
return;
}
// Fire ye pipe consumption
if (!this->work->Start())
{
SysPushErrorIO("Couldn't start reading the IO pipe");
this->OnFatalError();
return;
}
if (!this->channel->OnConnect())
{
SysPushErrorIO("Couldn't start the channel");
this->OnFatalError();
return;
}
}
bool AuRPCPipe::Init(const AuString& str)
{
this->pipe = AuIPC::ImportPipe(str);
if (!this->pipe)
{
SysPushErrorIO("Couldn't open an IPC pipe given handle: {}", str);
return {};
}
this->OnConnect();
this->isClient_ = true;
return true;// WaitForOtherEnd();
}
bool AuRPCPipe::Init(AuOptional<AuUInt32> optLength)
2022-07-02 22:08:52 +00:00
{
this->pipe = optLength ?
AuIPC::NewPipeEx(optLength.value()) :
AuIPC::NewPipe();
2022-07-02 22:08:52 +00:00
if (!this->pipe)
{
SysPushErrorIO("Couldn't spare the resources required for an IPC pipe");
return {};
}
return WaitForOtherEnd();
}
bool AuRPCPipe::WaitForOtherEnd()
{
this->isOpenWork = GetRPCProcessor()->StartSimpleLSWatchEx(this->pipe->AsReadChannelIsOpen(),
AuSPtr<AuIO::IIOSimpleEventListener>(this->channel->ToContext(), this),
true);
return bool(this->isOpenWork);
}
void AuRPCPipe::Deinit()
{
if (this->work)
{
work->End();
work.reset();
}
}