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"
|
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
struct RPCTransaction :
|
|
|
|
AuIO::IAsyncFinishedSubscriber,
|
|
|
|
AuEnableSharedFromThis<RPCTransaction>
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +00:00
|
|
|
AuSPtr<AuIO::IAsyncTransaction> transaction;
|
|
|
|
AuMemoryViewRead view;
|
|
|
|
AuRPCPipePacket packet;
|
2022-07-02 22:08:52 +00:00
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
void OnAsyncFileOpFinished(AuUInt64 offset, AuUInt32 length) override
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +00:00
|
|
|
transaction->SetCallback({});
|
|
|
|
if (length != view.length)
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +00:00
|
|
|
this->Fail();
|
|
|
|
if (this->packet.clientChannel)
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +00:00
|
|
|
this->packet.clientChannel->FatalIOError();
|
2022-07-02 22:08:52 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-16 18:16:32 +00:00
|
|
|
else
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +00:00
|
|
|
this->Sent();
|
|
|
|
}
|
|
|
|
}
|
2022-07-02 22:08:52 +00:00
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
bool SendClient()
|
|
|
|
{
|
|
|
|
if (packet.protPacket)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2022-07-02 22:08:52 +00:00
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
if (!packet.clientRequest)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2022-07-02 22:08:52 +00:00
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
packet.clientRequest->state = ERPCRequestState::eSubmitting;
|
2022-07-02 22:08:52 +00:00
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
if (!AuTryInsert(packet.clientChannel->outstandingRequests, packet.clientRequest))
|
|
|
|
{
|
|
|
|
return false;
|
2022-07-02 22:08:52 +00:00
|
|
|
}
|
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
2022-07-02 22:08:52 +00:00
|
|
|
|
2023-12-16 18:16:32 +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
|
|
|
}
|
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
this->Remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Remove()
|
|
|
|
{
|
|
|
|
if (packet.clientChannel)
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +00:00
|
|
|
AuTryRemove(packet.clientChannel->outstandingRequests, packet.clientRequest);
|
2022-07-02 22:08:52 +00:00
|
|
|
}
|
2023-12-16 18:16:32 +00:00
|
|
|
}
|
2022-07-02 22:08:52 +00:00
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
void Sent()
|
|
|
|
{
|
|
|
|
if (packet.clientRequest)
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +00:00
|
|
|
packet.clientRequest->state = ERPCRequestState::eSent;
|
2022-07-02 22:08:52 +00:00
|
|
|
}
|
2023-12-16 18:16:32 +00:00
|
|
|
}
|
|
|
|
};
|
2022-07-02 22:08:52 +00:00
|
|
|
|
2023-12-16 18:16:32 +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);
|
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
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
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
if (pid != AuAsync::GetCurrentWorkerPId())
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +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();
|
|
|
|
}
|
|
|
|
|
2023-12-16 18:16:32 +00:00
|
|
|
bool AuRPCPipe::Init(AuOptional<AuUInt32> optLength)
|
2022-07-02 22:08:52 +00:00
|
|
|
{
|
2023-12-16 18:16:32 +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();
|
|
|
|
}
|
|
|
|
}
|