/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: IProtocolStack.hpp Date: 2022-8-24 Author: Reece ***/ #pragma once namespace Aurora::IO::Protocol { AUE_DEFINE_VA(EProtocolWhere, eAppend, ePrepend); struct IProtocolStack : IProtocolBaseReader, IProtocolBaseWriter { /** * @brief * Warning: AddInterceptorEx is preferred * @param pInterceptor * @param uOutputBufferSize When 0, a hopefully not stupid default is used. * (Configurable at runtime init via RuntimeConfig.ioConfig.uProtocolStackDefaultBufferSize) * @return */ virtual AuSPtr AddInterceptor(EProtocolWhere eWhere, const AuSPtr &pInterceptor, AuUInt uOutputBufferSize) = 0; /** * @brief Registers a protocol stack interceptor to be called once per tick of the protocol stack. * Be careful to not use stupid uOutputBufferSize sizes otherwise you'll quickly find yourself running out of memory. * You can mitigate excessive resource consumption by using smaller IO frames and repeated callbacks via ::AddSingleFrameProcessor; * or by using ::AddInterceptorDynamicBuffer with a defined base size and upper limit. * @param pInterceptorEx * @param uOutputBufferSize When 0, a hopefully not stupid default is used. * (Configurable at runtime init via RuntimeConfig.ioConfig.uProtocolStackDefaultBufferSize) * @return */ virtual AuSPtr AddInterceptorEx(EProtocolWhere eWhere, const AuSPtr &pInterceptorEx, AuUInt uOutputBufferSize) = 0; /** * @brief defer to AddInterceptorEx * @param pInterceptorEx * @param uOutputBufferSize * @return */ virtual AuSPtr AddInterceptorDynamicBuffer(EProtocolWhere eWhere, const AuSPtr &pInterceptorEx, AuUInt uOutputBufferDefaultSize, AuUInt uOutputBufferMaximumSize) = 0; /** * @brief Same as AddInterceptor, except that DoTick will repeat until the input is fully consumed. * * This allows us to tick processors under our frame, followed by a retick if there is more data available to us. * Such paradigm contrasts the default unframed/raw stream behaviour where the processor is responsible for consuming all * available data. * With such limitations, it's impossible to build a protocol where a piece in the middle * 1) can/should only flush 1 frame to the following interceptor * (this is a problem when the frame does not contain a length prefix and the next interceptor is a frame processor) * 2) only reads a portion of pReadInByteBuffer * (the current interceptor can only process a frame of data per tick) * * This function sets an internal flag that indicates re-ticks from the root single frame processor are to be expected * in order to complete a single ::DoTick tick. With this flag enabled, multiple tick may occur as opposed to a single * callback per ::DoTick(). * @param pInterceptorEx * @return */ virtual AuSPtr AddSingleFrameProcessor(EProtocolWhere eWhere, const AuSPtr &pInterceptorEx) = 0; /** * @brief Defer to AppendSingleFrameProcessor * @param pInterceptorEx * @param uOutputBufferSize * @param uOutputBufferSizeMax * @return */ virtual AuSPtr AddSingleFrameProcessorDynamicBuffer(EProtocolWhere eWhere, const AuSPtr &pInterceptorEx, AuUInt uOutputBufferDefaultSize, AuUInt uOutputBufferMaximumSize) = 0; /** * @brief See: AppendSingleFrameProcessor * @param pInterceptorEx * @return */ virtual AuSPtr AddSingleFrameProcessorEx(EProtocolWhere eWhere, const AuSPtr &pInterceptorEx, AuUInt uOutputBufferSize) = 0; /** * @brief * @param pInterceptor * @return */ virtual AuSPtr AddEndInterceptor(const AuSPtr &pInterceptor) = 0; /** * @brief Sends one tick down the protocol stack, regardless of how much data is written into the * next piece/interceptor, and regardless of if another read tick is required. * @return The error state of the top-most interceptor */ virtual bool DoTick() = 0; /** * @brief */ virtual void Destroy() = 0; /** * @brief * @return */ virtual AuList> GetArrayOfInterceptors() = 0; /** * @brief * @param uIndex * @return */ virtual AuSPtr GetInterceptorAtIndex(AuUInt32 uIndex) = 0; /** * @brief * @return */ virtual bool IsValid() = 0; AURT_ADD_USR_DATA; }; /** * @brief Allocates a new protocol stack with a buffered input stream of uLength bytes * @param uLength * @return */ AUKN_SYM AuSPtr NewBufferedProtocolStack(AuUInt uLength); /** * @brief Creates a protocol stack backed by the memory of a pipe. * @param pWork * @return */ AUKN_SYM AuSPtr NewProtocolStackFromPipe(const AuSPtr &pWork, bool bAutoTick = true, bool bKillPipeOnFirstRootLevelFalse = true); }