diff --git a/Include/Aurora/Utility/RateLimiter.hpp b/Include/Aurora/Utility/RateLimiter.hpp index 27166cb6..77236255 100644 --- a/Include/Aurora/Utility/RateLimiter.hpp +++ b/Include/Aurora/Utility/RateLimiter.hpp @@ -11,9 +11,26 @@ namespace Aurora::Utility { struct RateLimiter { - AuUInt64 nextTriggerTime; - AuUInt64 nsTimeStep; - + AuUInt64 nextTriggerTime {}; + AuUInt64 nsTimeStep {}; + bool noCatchUp {}; + + inline RateLimiter() + { + + } + + inline RateLimiter(AuUInt64 nsTimeStep) + { + SetNextStep(nsTimeStep); + } + + inline auline void SetTargetTime(AuUInt64 timeAbsNs) + { + this->nsTimeStep = 0; + this->nextTriggerTime = timeAbsNs; + } + inline auline void SetNextStep(AuUInt64 nsTimeStep) { this->nsTimeStep = nsTimeStep; @@ -71,7 +88,14 @@ namespace Aurora::Utility inline auline AuUInt64 GetLatch() { - return this->nextTriggerTime + this->nsTimeStep; + if (this->noCatchUp) + { + return this->nsTimeStep + Aurora::Time::CurrentInternalClockNS(); + } + else + { + return this->nextTriggerTime + this->nsTimeStep; + } } }; }; \ No newline at end of file diff --git a/Source/Console/ConsoleTTY/ConsoleTTY.cpp b/Source/Console/ConsoleTTY/ConsoleTTY.cpp index 34914a7b..03bca1a1 100644 --- a/Source/Console/ConsoleTTY/ConsoleTTY.cpp +++ b/Source/Console/ConsoleTTY/ConsoleTTY.cpp @@ -30,11 +30,14 @@ namespace Aurora::Console::ConsoleTTY void TTYConsole::Init() { + this->historyLock = AuThreadPrimitives::RWLockUnique(); + this->HistorySetFile(); + this->HistoryLoad(); } void TTYConsole::Deinit() { - + this->HistoryAppendChanges(); } bool TTYConsole::Start() @@ -316,6 +319,8 @@ namespace Aurora::Console::ConsoleTTY void TTYConsole::NoncanonicalOnEnter() { + AU_LOCK_GUARD(this->historyLock->AsWritable()); + if (this->inputField.size()) { @@ -435,6 +440,8 @@ namespace Aurora::Console::ConsoleTTY void TTYConsole::NoncanonicalOnHistoryDown() { + AU_LOCK_GUARD(this->historyLock->AsReadable()); + bool locked {}; if (this->history.empty()) @@ -483,6 +490,84 @@ namespace Aurora::Console::ConsoleTTY NoncanonicalSetCursor(); } + void TTYConsole::HistorySetFile() + { + AuString path; + AuProcess::GetProcFullPath(path); + auto hash = AuFnv1a64Runtime(path.data(), path.size()); + AuIOFS::NormalizePath(this->historyFileName, fmt::format("~/TTYHistory/{}.txt", hash)); + } + + AuString TTYConsole::HistoryGetFile() + { + return this->historyFileName; + } + + void TTYConsole::HistoryAppendChanges() + { + if (!this->historyLock) + { + return; + } + + AU_LOCK_GUARD(this->historyLock->AsWritable()); + + if (this->history.size() <= this->iHistoryWritePos) + { + return; + } + + auto file = AuIOFS::OpenUnique(this->historyFileName, AuIOFS::EFileOpenMode::eReadWrite); + if (!file) + { + SysPushErrorIO(this->historyFileName); + return; + } + + file->SetOffset(file->GetLength()); + + AuString buffer; + auto line = AuLocale::NewLine(); + line.reserve(4096); + + for (int i = this->iHistoryWritePos; i < this->history.size(); i++) + { + buffer += (i == 0 ? "" : line); + buffer += this->history[i]; + } + + AuUInt bytesWritten; + file->Write(AuMemoryViewStreamRead(AuMemory::MemoryViewRead(buffer), bytesWritten)); + + this->iHistoryWritePos = this->history.size(); + } + + void TTYConsole::HistoryLoad() + { + AU_LOCK_GUARD(this->historyLock->AsWritable()); + + if (this->historyFileName.empty()) + { + return; + } + + if (!AuIOFS::FileExists(this->historyFileName)) + { + return; + } + + AuString buffer; + if (!AuIOFS::ReadString(this->historyFileName, buffer)) + { + return; + } + + AuParse::SplitNewlines(buffer, [&](const AuString &in) + { + this->history.push_back(in); + }); + } + void TTYConsole::NoncanonicalOnPageUp() { this->Scroll(this->GetLogBoxLines()); @@ -523,6 +608,24 @@ namespace Aurora::Console::ConsoleTTY this->bTriggerRedraw = true; } + void TTYConsole::PumpHistory() + { + static Aurora::Utility::RateLimiter limiter; + + if (!limiter.nextTriggerTime) + { + limiter.noCatchUp = true; + limiter.SetNextStep(AuMSToNS(10'000)); + } + + if (!limiter.CheckExchangePass()) + { + return; + } + + HistoryAppendChanges(); + } + void TTYConsole::Pump() { if (!gTTYConsoleEnabled) @@ -536,6 +639,8 @@ namespace Aurora::Console::ConsoleTTY } Flush(); + + PumpHistory(); } void TTYConsole::OnEnter() @@ -762,6 +867,8 @@ namespace Aurora::Console::ConsoleTTY bTryAgain = true; continue; } + + bool redrawEntireBox {}; if (bChangedSize || bRedrawWindowRequired || bHasMesasgesPending) { @@ -781,11 +888,11 @@ namespace Aurora::Console::ConsoleTTY TTYStorePos(); } - if (bChangedSize || this->bTriggerRedraw) { TTYClearScreen(); - // bRefresh = true; + bRefresh = true; + redrawEntireBox = true; } } @@ -797,11 +904,18 @@ namespace Aurora::Console::ConsoleTTY if (RegenerateBuffer(bChangedSize, redrawBox) || this->bTriggerRedraw) { bRefresh = true; + redrawEntireBox = true; RedrawLogBox(); } + bRefresh |= redrawBox; } + if (redrawEntireBox) + { + RedrawLogBox(); + } + if (bRefresh) { RedrawBanner(); diff --git a/Source/Console/ConsoleTTY/ConsoleTTY.hpp b/Source/Console/ConsoleTTY/ConsoleTTY.hpp index a252be0e..31b30ee2 100644 --- a/Source/Console/ConsoleTTY/ConsoleTTY.hpp +++ b/Source/Console/ConsoleTTY/ConsoleTTY.hpp @@ -15,6 +15,7 @@ namespace Aurora::Console::ConsoleTTY { void BufferMessage(const AuConsole::ConsoleMessage &msg); void Pump(); + void PumpHistory(); bool RedrawWindow(); void OnEnter(); @@ -67,8 +68,14 @@ namespace Aurora::Console::ConsoleTTY void NoncanonicalOnHistoryUp(); void NoncanonicalOnHistoryDown(); + void HistorySetFile(); + AuString HistoryGetFile(); + void HistoryAppendChanges(); + void HistoryLoad(); void HistoryUpdateCursor(); + AuString historyFileName; + int noncanonicalCursorPos {}; int noncanonicalCursorPosInBytes {}; @@ -163,8 +170,12 @@ namespace Aurora::Console::ConsoleTTY int iHistoryPos {-1}; + int iHistoryWritePos {0}; AuList history; + AuThreadPrimitives::RWLockUnique_t historyLock; + + AuThreadPrimitives::SpinLock messageLock; AuList messagesPending; diff --git a/Source/IPC/IPCMemory.NT.cpp b/Source/IPC/IPCMemory.NT.cpp index 1bf1d019..b6ef5eb8 100644 --- a/Source/IPC/IPCMemory.NT.cpp +++ b/Source/IPC/IPCMemory.NT.cpp @@ -92,11 +92,11 @@ namespace Aurora::IPC return {}; } - auto map = MapViewOfFile(file, - FILE_MAP_ALL_ACCESS, - 0, - 0, - length); + auto map = ::MapViewOfFile(file, + FILE_MAP_ALL_ACCESS, + 0, + 0, + length); if (!map) { SysPushErrorIO(); @@ -128,9 +128,9 @@ namespace Aurora::IPC auto length = handle.word; auto path = handle.ToNTPath(); - auto file = OpenFileMappingA(FILE_MAP_ALL_ACCESS, - FALSE, - path.c_str()); + auto file = ::OpenFileMappingA(FILE_MAP_ALL_ACCESS, + FALSE, + path.c_str()); if ((file == INVALID_HANDLE_VALUE) || (!file)) @@ -138,11 +138,11 @@ namespace Aurora::IPC return {}; } - auto map = MapViewOfFile(file, - FILE_MAP_ALL_ACCESS, - 0, - 0, - length); + auto map = ::MapViewOfFile(file, + FILE_MAP_ALL_ACCESS, + 0, + 0, + length); if (!map) { SysPushErrorIO();