[+] Aurora::IO::Net::NetSocketConnectByHost

[+] Aurora::IO::FS::DirDeleterEx
[+] Aurora::IO::Compress
[+] Aurora::IO::Decompress
[*] Aurora::Memory::ByteBuffer zero-alloc fixes
[*] Aurora::Memory::ByteBuffer linear read of begin/end should return (`const AuUInt8 *`)'s
[*] Changed NT file CREATE flags
[*] Fix linux regression
[*] Update logger sink DirLogArchive
... [+] DirectoryLogger::uMaxLogsOrZeroBeforeDelete
... [+] DirectoryLogger::uMaxCumulativeFileSizeInMiBOrZeroBeforeDelete
... [+] DirectoryLogger::uMaxCumulativeFileSizeInMiBOrZeroBeforeCompress
... [+] DirectoryLogger::uMaxFileTimeInDeltaMSOrZeroBeforeCompress
... [+] DirectoryLogger::uMaxFileTimeInDeltaMSOrZeroBeforeDelete
[*] FIX: BufferedLineReader was taking the wrong end head
(prep) LZMACompressor
[*] Updated build-script for LZMA (when i can be bothered to impl it)
(prep) FSOverlappedUtilities
(prep) FSDefaultOverlappedWorkerThread | default worker pool / apc dispatcher / auasync dispatcher concept for higher level overlapped ops
(stub) [+] Aurora::IO::FS::OverlappedForceDelegatedIO
(stub) [+] Aurora::IO::FS::OverlappedCompress
(stub) [+] Aurora::IO::FS::OverlappedDecompress
(stub) [+] Aurora::IO::FS::OverlappedWrite
(stub) [+] Aurora::IO::FS::OverlappedRead
(stub) [+] Aurora::IO::FS::OverlappedStat
(stub) [+] Aurora::IO::FS::OverlappedCopy
(stub) [+] Aurora::IO::FS::OverlappedRelink
(stub) [+] Aurora::IO::FS::OverlappedTrustFile
(stub) [+] Aurora::IO::FS::OverlappedBlockFile
(stub) [+] Aurora::IO::FS::OverlappedUnblockFile
(stub) [+] Aurora::IO::FS::OverlappedDelete
This commit is contained in:
Reece Wilson 2023-01-26 21:43:19 +00:00
parent bf8c1eb8c7
commit 04aca5fcf2
33 changed files with 1011 additions and 130 deletions

View File

@ -20,6 +20,7 @@
"wxwidgets", "wxwidgets",
"glm", "glm",
"bzip2", "bzip2",
"liblzma",
"lz4" "lz4"
], ],
"depends": [ "depends": [

View File

@ -44,6 +44,14 @@ namespace Aurora::IO::FS
*/ */
AUKN_SYM bool DirDeleter(const AuString &string); AUKN_SYM bool DirDeleter(const AuString &string);
/**
* @brief
* @param string
* @param failingPaths
* @return
*/
AUKN_SYM bool DirDeleterEx(const AuString &string, AuList<AuString> &failingPaths);
/** /**
* @brief Writes a blob into a file chunk-by-chunk. * @brief Writes a blob into a file chunk-by-chunk.
* The directory structure may or may not exist for the write operation to succeed. * The directory structure may or may not exist for the write operation to succeed.
@ -143,19 +151,34 @@ namespace Aurora::IO::FS
AUKN_SYM bool BlockFile(const AuString &path); AUKN_SYM bool BlockFile(const AuString &path);
/** /**
* @brief Specifies generic level of trust * @brief Specifies generic local-system/trusted level of trust
* @param path * @param path
* @return * @return
*/ */
AUKN_SYM bool UnblockFile(const AuString &path); AUKN_SYM bool UnblockFile(const AuString &path);
/** /**
* @brief Specifies user/internal level trust of a file * @brief Specifies user/executable level trust of a file
* @warning This routine is intended to enable execution of files
* on both UNIX and NT based systems. UnblockFile
* will be enough for resources and some powershell scripts;
* however, this is required for unblocking / `mode |= 0111`ing
* executable files.
* @param path * @param path
* @return * @return
*/ */
AUKN_SYM bool TrustFile(const AuString &path); AUKN_SYM bool TrustFile(const AuString &path);
/**
* @brief Transfers the contents of the specified filepath through a
* zstandard compression pipe to an ending path + ".zst" file.
* @warning This file API does not relate to file-system level compression
* @param path = ur mother
*/
AUKN_SYM bool Compress(const AuString &path, AuInt8 level = 17);
AUKN_SYM bool Decompress(const AuString &path);
/** /**
* @brief Normalizes an arbitrary string of in * @brief Normalizes an arbitrary string of in
* @param out * @param out
@ -198,3 +221,4 @@ namespace Aurora::IO::FS
#include "Async.hpp" #include "Async.hpp"
#include "Watcher.hpp" #include "Watcher.hpp"
#include "IReadDir.hpp" #include "IReadDir.hpp"
#include "Overlapped.hpp"

View File

@ -0,0 +1,69 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Overlapped.hpp
Date: 2023-1-26
Author: Reece
Note: Defer to Async.hpp for creation of overlapped stream objects
This header defines FS.hpp-like APIs that run overlapped or on a
worker thread or two.
***/
#pragma once
namespace Aurora::IO::Loop
{
struct ILoopSource;
}
namespace Aurora::IO::FS
{
struct IOverlappedOperationBase;
AUKN_INTERFACE(IOverlappedCallback,
AUI_METHOD(void, OnSuccess, (AuSPtr<IOverlappedOperationBase>, pOriginator)),
AUI_METHOD(void, OnFailure, (AuSPtr<IOverlappedOperationBase>, pOriginator))
);
struct IOverlappedOperationBase
{
virtual AuSPtr<Loop::ILoopSource> ToWaitable() = 0;
virtual AuSPtr<IOverlappedCallback> SetCallback(AuSPtr<IOverlappedOperationBase> pCallback) = 0;
virtual bool IsOperationComplete() = 0;
virtual bool IsOperationSuccessful() = 0;
};
struct IOverlappedStatOperation : IOverlappedOperationBase
{
virtual AuSPtr<Stat> GetStats() = 0;
};
struct IOverlappedReadOperation : IOverlappedOperationBase
{
virtual AuSPtr<Aurora::Memory::ByteBuffer> GetByteBuffer() = 0;
virtual AuSPtr<Aurora::Memory::MemoryViewWrite> GetReadView() = 0;
};
/**
* @brief If running under AuAsync runner, we use the local thread for the entire IO operation.
* In the future, whence I can be bothered to finish the APC api, *all* overlapped operations
* will be processed on the local thread.
* Specifying true forces all IO to occour on a preallocated pool of IO workers
* @warning this api is thread-local
* @warning this api does not change the behaviour of overlapped file streamss
*/
AUKN_SYM bool OverlappedForceDelegatedIO(bool bForceIOWorkerThreads);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedCompress(const AuString &path, AuInt8 iLevel = 17);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedDecompress(const AuString &path);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedWrite(const AuString &path, AuSPtr<Aurora::Memory::MemoryViewRead> pMemoryView);
AUKN_SYM AuSPtr<IOverlappedReadOperation> OverlappedRead(const AuString &path);
AUKN_SYM AuSPtr<IOverlappedStatOperation> OverlappedStat(const AuString &path);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedCopy(const AuString &path, const AuString &dest);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedRelink(const AuString &path, const AuString &dest);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedTrustFile(const AuString &path);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedBlockFile(const AuString &path);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedUnblockFile(const AuString &path);
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedDelete(const AuString &path);
}

View File

@ -11,9 +11,22 @@ namespace Aurora::IO::Net
{ {
struct ISocketServer; struct ISocketServer;
struct NetSocketConnectByHost
{
AuOptionalEx<NetHostname> netHostname;
AuOptionalEx<AuUInt16> uPort;
AuOptionalEx<ETransportProtocol> protocol;
};
struct NetSocketConnect struct NetSocketConnect
{ {
NetEndpoint endpoint; // connect by protocol, address:port
AuOptionalEx<NetEndpoint> endpoint;
// or connect by [string/ip family, ip address], port
NetSocketConnectByHost byHost;
//
AuSPtr<ISocketDriver> pDriver; AuSPtr<ISocketDriver> pDriver;
AuUInt32 uMaxConnectTimeMs {}; AuUInt32 uMaxConnectTimeMs {};
}; };

View File

@ -11,12 +11,16 @@ namespace Aurora::IO::Net
{ {
struct AUKN_SYM NetHostname struct AUKN_SYM NetHostname
{ {
NetHostname(const NetHostname &cpy);
NetHostname();
NetHostname(const AuString &hostname); NetHostname(const AuString &hostname);
NetHostname(const IPAddress &ipAddress); NetHostname(const IPAddress &ipAddress);
const EHostnameType type; EHostnameType type;
const AuString hostname; AuString hostname;
const IPAddress address; IPAddress address;
NetHostname &operator =(const NetHostname &other);
bool operator ==(const NetHostname &other) const; bool operator ==(const NetHostname &other) const;
const AuUInt HashCode() const; const AuUInt HashCode() const;

View File

@ -16,8 +16,11 @@ namespace Aurora::Logging
{ {
struct DirectoryLogger struct DirectoryLogger
{ {
AuUInt32 maxLogsOrZero {}; AuUInt32 uMaxLogsOrZeroBeforeDelete {};
AuUInt32 maxFileSizeOrZero {}; // MB AuUInt32 uMaxCumulativeFileSizeInMiBOrZeroBeforeDelete {};
AuUInt32 uMaxCumulativeFileSizeInMiBOrZeroBeforeCompress {};
AuUInt32 uMaxFileTimeInDeltaMSOrZeroBeforeCompress {};
AuUInt32 uMaxFileTimeInDeltaMSOrZeroBeforeDelete {};
}; };
/** /**

View File

@ -116,7 +116,13 @@ namespace Aurora::Memory
*/ */
inline ByteBuffer(const ByteBuffer &buffer, bool preservePointers = true) inline ByteBuffer(const ByteBuffer &buffer, bool preservePointers = true)
{ {
this->base = FAlloc<AuUInt8 *>(buffer.length); if (buffer.length)
{
this->base = FAlloc<AuUInt8 *>(buffer.length);
}
this->scaleSize = buffer.scaleSize;
this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable;
if (!this->base) if (!this->base)
{ {
Reset(); Reset();
@ -135,9 +141,6 @@ namespace Aurora::Memory
this->readPtr = this->base; this->readPtr = this->base;
} }
AuMemcpy(this->base, buffer.base, this->length); AuMemcpy(this->base, buffer.base, this->length);
this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable;
this->scaleSize = buffer.scaleSize;
} }
/** /**
@ -149,7 +152,8 @@ namespace Aurora::Memory
*/ */
inline ByteBuffer(const void *in, AuUInt length, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0) inline ByteBuffer(const void *in, AuUInt length, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{ {
this->base = FAlloc<AuUInt8 *>(length); this->scaleSize = kBufferInitialPower;
this->base = length ? FAlloc<AuUInt8 *>(length) : nullptr;
if (!this->base) if (!this->base)
{ {
Reset(); Reset();
@ -160,12 +164,12 @@ namespace Aurora::Memory
this->readPtr = this->base; this->readPtr = this->base;
this->writePtr = this->readPtr + this->length; this->writePtr = this->readPtr + this->length;
AuMemcpy(this->base, in, this->length); AuMemcpy(this->base, in, this->length);
this->scaleSize = kBufferInitialPower;
} }
inline ByteBuffer(const AuList<AuUInt8> &vector, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0) inline ByteBuffer(const AuList<AuUInt8> &vector, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{ {
this->base = FAlloc<AuUInt8 *>(vector.size()); this->scaleSize = kBufferInitialPower;
this->base = vector.size() ? FAlloc<AuUInt8 *>(vector.size()) : nullptr;
if (!this->base) if (!this->base)
{ {
Reset(); Reset();
@ -176,11 +180,11 @@ namespace Aurora::Memory
this->readPtr = this->base; this->readPtr = this->base;
this->writePtr = this->readPtr + this->length; this->writePtr = this->readPtr + this->length;
AuMemcpy(this->base, vector.data(), this->length); AuMemcpy(this->base, vector.data(), this->length);
this->scaleSize = kBufferInitialPower;
} }
inline ByteBuffer(AuUInt length, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0) inline ByteBuffer(AuUInt length, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{ {
this->scaleSize = kBufferInitialPower;
if (!length) if (!length)
{ {
Reset(); Reset();
@ -196,7 +200,6 @@ namespace Aurora::Memory
this->allocSize = length; this->allocSize = length;
this->readPtr = this->base; this->readPtr = this->base;
this->writePtr = this->base; this->writePtr = this->base;
this->scaleSize = kBufferInitialPower;
} }
inline ByteBuffer(AuUInt length, AuUInt alignment, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0) inline ByteBuffer(AuUInt length, AuUInt alignment, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
@ -206,6 +209,7 @@ namespace Aurora::Memory
Reset(); Reset();
return; return;
} }
this->scaleSize = kBufferInitialPower;
this->base = ZAlloc<AuUInt8 *>(length, alignment); this->base = ZAlloc<AuUInt8 *>(length, alignment);
if (!this->base) if (!this->base)
{ {
@ -216,14 +220,14 @@ namespace Aurora::Memory
this->allocSize = length; this->allocSize = length;
this->readPtr = this->base; this->readPtr = this->base;
this->writePtr = this->base; this->writePtr = this->base;
this->scaleSize = kBufferInitialPower;
} }
template<typename T> template<typename T>
ByteBuffer(T *base, T *end, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0) ByteBuffer(T *base, T *end, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{ {
auto length = static_cast<AuUInt>(end - base) * sizeof(T); auto length = static_cast<AuUInt>(end - base) * sizeof(T);
this->base = ZAlloc<AuUInt8 *>(length); this->base = length ? ZAlloc<AuUInt8 *>(length) : nullptr;
this->scaleSize = kBufferInitialPower;
if (!this->base) if (!this->base)
{ {
Reset(); Reset();
@ -233,7 +237,6 @@ namespace Aurora::Memory
this->allocSize = length; this->allocSize = length;
this->readPtr = this->base; this->readPtr = this->base;
this->writePtr = this->base + length; this->writePtr = this->base + length;
this->scaleSize = kBufferInitialPower;
AuMemcpy(this->base, base, length); AuMemcpy(this->base, base, length);
} }
@ -285,14 +288,14 @@ namespace Aurora::Memory
* @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...) * @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...)
* @return * @return
*/ */
inline auline AuUInt8 * begin() const; inline auline const AuUInt8 * begin() const;
/** /**
* @brief linear read end * @brief linear read end
* @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...) * @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...)
* @return * @return
*/ */
inline auline AuUInt8 * end() const; inline auline const AuUInt8 * end() const;
inline auline bool empty() const; inline auline bool empty() const;

View File

@ -16,6 +16,16 @@ namespace Aurora::Memory
Free(this->base); Free(this->base);
this->base = nullptr; this->base = nullptr;
} }
if (!length)
{
this->length = length;
this->allocSize = length;
this->readPtr = this->base;
this->writePtr = this->base;
return true;
}
this->base = fast ? FAlloc<AuUInt8 *>(length) : ZAlloc<AuUInt8 *>(length); this->base = fast ? FAlloc<AuUInt8 *>(length) : ZAlloc<AuUInt8 *>(length);
if (!this->base) if (!this->base)
{ {
@ -35,11 +45,22 @@ namespace Aurora::Memory
Free(this->base); Free(this->base);
this->base = nullptr; this->base = nullptr;
} }
if (!length)
{
this->length = length;
this->allocSize = length;
this->readPtr = this->base;
this->writePtr = this->base;
return true;
}
this->base = fast ? FAlloc<AuUInt8 *>(length, alignment) : ZAlloc<AuUInt8 *>(length, alignment); this->base = fast ? FAlloc<AuUInt8 *>(length, alignment) : ZAlloc<AuUInt8 *>(length, alignment);
if (!this->base) if (!this->base)
{ {
return false; return false;
} }
this->length = length; this->length = length;
this->allocSize = length; this->allocSize = length;
this->readPtr = this->base; this->readPtr = this->base;
@ -119,9 +140,9 @@ namespace Aurora::Memory
if (length == 0) if (length == 0)
{ {
this->length = 0; this->length = 0;
this->writePtr = this->base; this->writePtr = this->base;
this->readPtr = this->base; this->readPtr = this->base;
return true; return true;
} }

View File

@ -9,6 +9,8 @@
namespace Aurora::Memory namespace Aurora::Memory
{ {
static const auto kMaxSaneElementsForAuMemory = 0xFFFFF;
template<typename T> template<typename T>
bool ByteBuffer::Read(T &out) bool ByteBuffer::Read(T &out)
{ {
@ -22,10 +24,16 @@ namespace Aurora::Memory
return false; return false;
} }
auto len = Read<AuUInt32>(); auto uLength = Read<AuUInt32>();
out.resize(len); if (uLength > kMaxSaneElementsForAuMemory)
{
this->flagReadError = true;
return false;
}
for (auto i = 0u; i < len; i++) out.resize(uLength);
for (auto i = 0u; i < uLength; i++)
{ {
Read<T::value_type>(out[i]); Read<T::value_type>(out[i]);
} }
@ -34,7 +42,13 @@ namespace Aurora::Memory
} }
else if constexpr (AuIsSame_v<AuRemoveReference_t<T>, AuString>) else if constexpr (AuIsSame_v<AuRemoveReference_t<T>, AuString>)
{ {
out.resize(Read<AuUInt32>()); auto uLength = Read<AuUInt32>();
if (uLength > kMaxSaneElementsForAuMemory)
{
this->flagReadError = true;
return false;
}
out.resize(uLength);
Read(out.data(), out.size()); Read(out.data(), out.size());
return !this->flagReadError; return !this->flagReadError;
} }

View File

@ -41,7 +41,7 @@ namespace Aurora::Memory
AuUInt8 &ByteBuffer::operator [](AuUInt idx) const AuUInt8 &ByteBuffer::operator [](AuUInt idx) const
{ {
auto pBegin = this->begin(); auto pBegin = (AuUInt8 *)this->begin(); // intentionally returning a volatile reference
auto pEnd = this->end(); auto pEnd = this->end();
SysAssert(idx < (AuUInt)(pEnd - pBegin)); SysAssert(idx < (AuUInt)(pEnd - pBegin));
return *(pBegin + idx); return *(pBegin + idx);
@ -62,7 +62,7 @@ namespace Aurora::Memory
return IsEmpty(); return IsEmpty();
} }
AuUInt8 *ByteBuffer::begin() const const AuUInt8 *ByteBuffer::begin() const
{ {
if (this->flagCircular) if (this->flagCircular)
{ {
@ -75,7 +75,7 @@ namespace Aurora::Memory
return this->readPtr; return this->readPtr;
} }
AuUInt8 *ByteBuffer::end() const const AuUInt8 *ByteBuffer::end() const
{ {
AuUInt8 *pBase {}; AuUInt8 *pBase {};
AuUInt uCount {}; AuUInt uCount {};

View File

@ -270,7 +270,9 @@ namespace Aurora
{ {
/// You can bypass branding by assigning an empty string to 'defaultBrand' /// You can bypass branding by assigning an empty string to 'defaultBrand'
AuString defaultBrand = "Aurora SDK Sample"; AuString defaultBrand = "Aurora SDK Sample";
}; bool bForceOverlappedUtilsToDelegatedThreadPool { false };
AuUInt32 uOverlappedUtilsThreadPoolSize { 2 }; // note: this does not relate to the overlapped aio apis
}; // these threads are only spawned as a fallback for AuFS::Overlapped*** apis
struct DebugConfig struct DebugConfig
{ {

View File

@ -26,7 +26,7 @@ namespace Aurora::IO::Character
} }
AuUInt bytesRead; AuUInt bytesRead;
if (this->inputStream_->Read(AuMemoryViewStreamWrite(AuMemoryViewWrite(this->buffer_.writePtr, this->buffer_.end()), bytesRead)) != if (this->inputStream_->Read(AuMemoryViewStreamWrite(AuMemoryViewWrite(this->buffer_.writePtr, this->buffer_.writePtr + this->buffer_.length), bytesRead)) !=
EStreamError::eErrorNone) EStreamError::eErrorNone)
{ {
SysPushErrorIO(); SysPushErrorIO();

View File

@ -17,18 +17,19 @@ namespace Aurora::IO::FS
AuList<AuString> nextLevel2; AuList<AuString> nextLevel2;
AuString curPath; AuString curPath;
AuString curSubDir; AuString curSubDir;
AuList<AuString> failedPaths;
bool OpenDir(const AuString &str) bool OpenDir(const AuString &str)
{ {
curPath = str; this->curPath = str;
pDir = ReadDir(str); this->pDir = ReadDir(str);
return bool(pDir); return bool(pDir);
} }
bool OpenNext(const AuString &str) bool OpenNext(const AuString &str)
{ {
curPath = str; this->curPath = str;
pDir = ReadDir(str); this->pDir = ReadDir(str);
return bool(pDir); return bool(pDir);
} }
@ -36,15 +37,15 @@ namespace Aurora::IO::FS
{ {
this->pDir.reset(); this->pDir.reset();
if (!nextLevel.size()) if (!this->nextLevel.size())
{ {
return; return;
} }
auto a = nextLevel[0]; auto a = this->nextLevel[0];
nextLevel.erase(nextLevel.begin()); this->nextLevel.erase(this->nextLevel.begin());
this->pDir = ReadDir(curPath + "/" + a); this->pDir = ReadDir(this->curPath + "/" + a);
curSubDir = a; this->curSubDir = a;
} }
virtual StatEx *Next() override virtual StatEx *Next() override
@ -79,7 +80,10 @@ namespace Aurora::IO::FS
} }
else else
{ {
AuFS::Remove(pNext->path); if (!AuFS::Remove(pNext->path))
{
this->failedPaths.push_back(pNext->fileName);
}
} }
return pNext; return pNext;
@ -87,9 +91,13 @@ namespace Aurora::IO::FS
void RemoveDirs() void RemoveDirs()
{ {
for (auto itr = nextLevel2.rbegin(); itr != nextLevel2.rend(); itr++) for (auto itr = this->nextLevel2.rbegin(); itr != this->nextLevel2.rend(); itr++)
{ {
AuFS::Remove(curPath + "/" + itr->c_str()); auto dir = this->curPath + "/" + itr->c_str();
if (!AuFS::Remove(dir))
{
this->failedPaths.push_back(itr->c_str());
}
} }
} }
}; };
@ -118,4 +126,44 @@ namespace Aurora::IO::FS
AuFS::Remove(string); AuFS::Remove(string);
return !AuFS::DirExists(string); return !AuFS::DirExists(string);
} }
AUKN_SYM bool DirDeleterEx(const AuString &string, AuList<AuString> &failingPaths)
{
auto pObj = AuMakeShared<RecursiveDirDeleter>();
if (!pObj)
{
SysPushErrorMem();
return {};
}
if (!pObj->OpenDir(string))
{
return {};
}
while (pObj->Next())
{
}
pObj->RemoveDirs();
AuFS::Remove(string);
if (AuFS::DirExists(string))
{
for (const auto &str : pObj->failedPaths)
{
if (AuFS::FileExists(str) ||
AuFS::DirExists(str))
{
failingPaths.push_back(str);
}
}
return false;
}
return true;
}
} }

View File

@ -192,7 +192,18 @@ namespace Aurora::IO::FS
CreateDirectories(pathNormalized, true); CreateDirectories(pathNormalized, true);
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (fileHandle == INVALID_HANDLE_VALUE)
{
AuThreading::ContextYield();
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (fileHandle == INVALID_HANDLE_VALUE) if (fileHandle == INVALID_HANDLE_VALUE)
{ {
SysPushErrorIO("Couldn't open handle: {}", path); SysPushErrorIO("Couldn't open handle: {}", path);

View File

@ -250,7 +250,7 @@ namespace Aurora::IO::FS
// NOTE: Linux filesystems are such a cluster fuck of unimplemented interfaces and half-assed drivers // NOTE: Linux filesystems are such a cluster fuck of unimplemented interfaces and half-assed drivers
// It's not unusual for these "files" to not support the required seek operations across NIX-like oses. // It's not unusual for these "files" to not support the required seek operations across NIX-like oses.
if (len == 0) if (qwLength == 0)
{ {
if (bIsStupidFD) if (bIsStupidFD)
{ {
@ -291,7 +291,7 @@ namespace Aurora::IO::FS
static bool UnixExists(const AuString &path, bool dir) static bool UnixExists(const AuString &path, bool dir)
{ {
struct stat s; struct stat s;
int err = stat(path.c_str(), &s); int err = ::stat(path.c_str(), &s);
if (-1 == err) if (-1 == err)
{ {
SysAssert(ENOENT == errno, "General File IO Error, path {}", path); SysAssert(ENOENT == errno, "General File IO Error, path {}", path);

224
Source/IO/FS/FSCompress.cpp Normal file
View File

@ -0,0 +1,224 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: FSCompress.cpp
Date: 2023-1-26
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "FS.hpp"
#include "FS.Generic.hpp"
#include <Source/Time/Time.hpp>
namespace Aurora::IO::FS
{
static const AuUInt64 kFileCopyBlock = 0xFFFF * 4; // 64KiB
static auto const kCompressionType = AuCompression::ECompressionType::eZSTD;
static const AuString kStringSuffix = ".zst";
AUKN_SYM bool Compress(const AuString &path, AuInt8 level)
{
static const auto kCompressionReadChunks = kFileCopyBlock;
auto pFileSrc = OpenReadShared(path, EFileAdvisoryLockLevel::eBlockWrite);
if (!pFileSrc)
{
SysPushErrorIO("Couldn't open compression source path: {}", path);
return {};
}
auto pFileDest = OpenWriteShared(path + kStringSuffix, EFileAdvisoryLockLevel::eBlockReadWrite);
if (!pFileDest)
{
SysPushErrorIO("Couldn't open compression destination path: {}.{}", path, kStringSuffix);
return {};
}
if (pFileDest->GetLength())
{
SysPushErrorIO("File exists");
return {};
}
auto qwLength = pFileSrc->GetLength();
auto pFileStream = AuMakeShared<AuIO::FS::FileReader>(pFileSrc);
if (!pFileStream)
{
SysPushErrorMemory();
return {};
}
auto pDestStream = AuMakeShared<AuIO::FS::FileWriter>(pFileDest);
if (!pDestStream)
{
SysPushErrorMemory();
return {};
}
AuCompression::CompressInfo compress { kCompressionType };
compress.uCompressionLevel = level;
compress.uInternalStreamSize = kCompressionReadChunks * 2;
auto pCompressor = AuCompression::CompressorUnique(pFileStream, compress);
if (!pCompressor)
{
SysPushErrorMemory("no compressor");
return {};
}
AuUInt64 qwTotalRead {};
{
AuByteBuffer tempMemory(kCompressionReadChunks);
if (!tempMemory)
{
SysPushErrorMemory();
return {};
}
for (AuUInt64 i = 0; i < qwLength; i += 0 /*kCompressionReadChunks*/)
{
auto [read, written] = pCompressor->Ingest(kCompressionReadChunks);
i += read;
if (read == 0)
{
break;
}
qwTotalRead += read;
bool bAnyWritten {};
while (auto uBytes = pCompressor->Read(tempMemory))
{
tempMemory.writePtr += uBytes;
bAnyWritten = true;
AuUInt idc {};
if (AuIO::WriteAll(pDestStream.get(), { tempMemory, idc }) != AuIO::EStreamError::eErrorNone)
{
SysPushErrorIO("AuIO::WriteAll failed");
return {};
}
tempMemory.writePtr = tempMemory.base;
tempMemory.readPtr = tempMemory.base;
}
// zstd u ok?
// if i remove this, we get no data at all.
// even if i try to displace this to above `->Finish()` we still get nothing
// preemptively flushing fixes everything /shrug
pCompressor->Flush();
}
pCompressor->Finish();
while (auto uBytes = pCompressor->Read(tempMemory))
{
tempMemory.writePtr += uBytes;
AuUInt idc {};
if (AuIO::WriteAll(pDestStream.get(), { tempMemory, idc }) != AuIO::EStreamError::eErrorNone)
{
SysPushErrorIO("AuIO::WriteAll failed");
return {};
}
tempMemory.writePtr = tempMemory.base;
tempMemory.readPtr = tempMemory.base;
}
}
return qwTotalRead == qwLength;
}
AUKN_SYM bool Decompress(const AuString &path)
{
static const auto kCompressionReadChunks = kFileCopyBlock;
auto pFileSrc = OpenReadShared(path + kStringSuffix, EFileAdvisoryLockLevel::eBlockWrite);
if (!pFileSrc)
{
SysPushErrorIO("Couldn't open compression source path: {}.{}", path, kStringSuffix);
return {};
}
auto pFileDest = OpenWriteShared(path, EFileAdvisoryLockLevel::eBlockReadWrite);
if (!pFileDest)
{
SysPushErrorIO("Couldn't open decompression destination path: {}", path);
return {};
}
if (pFileDest->GetLength())
{
SysPushErrorIO("File exists");
return {};
}
auto qwLength = pFileSrc->GetLength();
auto pFileStream = AuMakeShared<AuIO::FS::FileReader>(pFileSrc);
if (!pFileStream)
{
SysPushErrorMemory();
return {};
}
auto pDestStream = AuMakeShared<AuIO::FS::FileWriter>(pFileDest);
if (!pDestStream)
{
SysPushErrorMemory();
return {};
}
AuCompression::DecompressInfo decompress{ kCompressionType };
decompress.uInternalStreamSize = kCompressionReadChunks * 5;
auto pDecompressor = AuCompression::DecompressorUnique(pFileStream, decompress);
if (!pDecompressor)
{
SysPushErrorMemory("no decompressor");
return {};
}
AuUInt64 qwTotalRead {};
{
AuByteBuffer tempMemory(kCompressionReadChunks);
if (!tempMemory)
{
SysPushErrorMemory();
return {};
}
for (AuUInt64 i = 0; i < qwLength; i += 0 /*kCompressionReadChunks*/)
{
auto [read, written] = pDecompressor->Ingest(kCompressionReadChunks);
i += read;
if (read == 0)
{
break;
}
qwTotalRead += read;
while (auto uBytes = pDecompressor->Read(tempMemory))
{
tempMemory.writePtr += uBytes;
AuUInt idc {};
if (AuIO::WriteAll(pDestStream.get(), { tempMemory, idc }) != AuIO::EStreamError::eErrorNone)
{
SysPushErrorIO("AuIO::WriteAll failed");
return {};
}
tempMemory.writePtr = tempMemory.base;
tempMemory.readPtr = tempMemory.base;
}
}
}
return qwTotalRead == qwLength;
}
}

View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: FSCompress.hpp
Date: 2023-1-26
Author: Reece
***/
#pragma once
namespace Aurora::IO::FS
{
}

View File

@ -0,0 +1,93 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: FSOverlappedUtilities.cpp
Date: 2023-1-26
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "FS.hpp"
#include "FSOverlappedUtilities.hpp"
namespace Aurora::IO::FS
{
struct OverlappedStatOperation :
virtual BaseOverlappedOperation,
IOverlappedStatOperation
{
Stat stat;
virtual AuSPtr<Stat> GetStats() override;
};
struct OverlappedReadOperation :
virtual BaseOverlappedOperation,
IOverlappedReadOperation
{
AuMemoryViewWrite write;
AuByteBuffer buffer;
virtual AuSPtr<Aurora::Memory::ByteBuffer> GetByteBuffer() override;
virtual AuSPtr<Aurora::Memory::MemoryViewWrite> GetReadView() override;
};
AUKN_SYM bool OverlappedForceDelegatedIO(bool bForceIOWorkerThreads)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedCompress(const AuString &path, AuInt8 iLevel)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedDecompress(const AuString &path)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedWrite(const AuString &path, AuSPtr<Aurora::Memory::MemoryViewRead> pMemoryView)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedReadOperation> OverlappedRead(const AuString &path)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedStatOperation> OverlappedStat(const AuString &path)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedCopy(const AuString &path, const AuString &dest)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedRelink(const AuString &path, const AuString &dest)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedTrustFile(const AuString &path)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedBlockFile(const AuString &path)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedUnblockFile(const AuString &path)
{
return {};
}
AUKN_SYM AuSPtr<IOverlappedOperationBase> OverlappedDelete(const AuString &path)
{
return {};
}
}

View File

@ -0,0 +1,30 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: FSOverlappedUtilities.hpp
Date: 2023-1-26
Author: Reece
***/
#pragma once
namespace Aurora::IO::FS
{
struct BaseOverlappedOperation : virtual IOverlappedOperationBase
{
BaseOverlappedOperation();
virtual AuSPtr<Loop::ILoopSource> ToWaitable() override;
virtual AuSPtr<IOverlappedCallback> SetCallback(AuSPtr<IOverlappedOperationBase> pCallback) override;
virtual bool IsOperationComplete() override;
virtual bool IsOperationSuccessful() override;
void Complete();
void Fail();
private:
AuSPtr<Loop::ILoopSource> pWaitable;
AuSPtr<IOverlappedOperationBase> pCallback;
};
}

View File

@ -250,7 +250,7 @@ namespace Aurora::IO::FS
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE) if (fileHandle == INVALID_HANDLE_VALUE)
{ {
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NtLockAdvisoryToShare(lock), NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NtLockAdvisoryToShare(lock), NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
} }
break; break;
} }
@ -260,7 +260,7 @@ namespace Aurora::IO::FS
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | FILE_READ_ATTRIBUTES, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | FILE_READ_ATTRIBUTES, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE) if (fileHandle == INVALID_HANDLE_VALUE)
{ {
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NtLockAdvisoryToShare(lock), NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, NtLockAdvisoryToShare(lock), NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
} }
break; break;
} }

View File

@ -10,6 +10,19 @@
namespace Aurora::IO::Net namespace Aurora::IO::Net
{ {
NetHostname::NetHostname()
{
}
NetHostname::NetHostname(const NetHostname &cpy) :
type(cpy.type),
hostname(cpy.hostname),
address(cpy.address)
{
}
NetHostname::NetHostname(const AuString &hostname) : NetHostname::NetHostname(const AuString &hostname) :
type(EHostnameType::eHostByDns), type(EHostnameType::eHostByDns),
hostname(hostname), hostname(hostname),
@ -32,6 +45,14 @@ namespace Aurora::IO::Net
this->address == other.address; this->address == other.address;
} }
NetHostname &NetHostname::operator =(const NetHostname &other)
{
this->type = other.type;
this->hostname = other.hostname;
this->address = other.address;
return *this;
}
const AuUInt NetHostname::HashCode() const const AuUInt NetHostname::HashCode() const
{ {
return AuHashCode(this->type) ^ return AuHashCode(this->type) ^

View File

@ -34,7 +34,12 @@ namespace Aurora::IO::Net
ADDRINFOEXW infoEx { 0 }; ADDRINFOEXW infoEx { 0 };
int iInfoEx { 0 }; int iInfoEx { 0 };
if (this->bA && !this->bAAAA) if (this->bA && this->bAAAA)
{
infoEx.ai_family = AF_UNSPEC;
//infoEx.ai_flags = AI_ALL;
}
else if (this->bA && !this->bAAAA)
{ {
infoEx.ai_family = AF_INET; infoEx.ai_family = AF_INET;
} }
@ -43,11 +48,6 @@ namespace Aurora::IO::Net
infoEx.ai_family = AF_INET6; infoEx.ai_family = AF_INET6;
//infoEx.ai_flags = AI_V4MAPPED; // beats returning nothing... //infoEx.ai_flags = AI_V4MAPPED; // beats returning nothing...
} }
else if (this->bA && this->bAAAA)
{
infoEx.ai_family = AF_UNSPEC;
//infoEx.ai_flags = AI_ALL;
}
else else
{ {
return false; return false;

View File

@ -113,7 +113,11 @@ namespace Aurora::IO::Net
{ {
int iInfoEx { 0 }; int iInfoEx { 0 };
if (this->bA && !this->bAAAA) if (this->bA && this->bAAAA)
{
infoEx.ai_family = AF_UNSPEC;
}
else if (this->bA && !this->bAAAA)
{ {
infoEx.ai_family = AF_INET; infoEx.ai_family = AF_INET;
} }
@ -121,10 +125,6 @@ namespace Aurora::IO::Net
{ {
infoEx.ai_family = AF_INET6; infoEx.ai_family = AF_INET6;
} }
else if (this->bA && this->bAAAA)
{
infoEx.ai_family = AF_UNSPEC;
}
else else
{ {
return false; return false;

View File

@ -31,11 +31,22 @@ namespace Aurora::IO::Net
} }
Socket::Socket(struct NetInterface *pInterface, Socket::Socket(struct NetInterface *pInterface,
struct NetWorker *pWorker, struct NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver, const AuSPtr<ISocketDriver> &pSocketDriver,
const NetEndpoint &endpoint) : const NetEndpoint &endpoint) :
SocketBase(pInterface, pWorker, pSocketDriver, endpoint) SocketBase(pInterface, pWorker, pSocketDriver, endpoint)
{ {
}
Socket::Socket(struct NetInterface *pInterface,
struct NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver,
const AuPair<NetHostname, AuUInt16> &endpoint,
AuNet::ETransportProtocol eProtocol) :
SocketBase(pInterface, pWorker, pSocketDriver, endpoint, eProtocol)
{
} }
Socket::Socket(NetInterface *pInterface, Socket::Socket(NetInterface *pInterface,
@ -62,7 +73,7 @@ namespace Aurora::IO::Net
} }
} }
void Socket::FinishConstructAsync() void Socket::RenewSocket()
{ {
if (!this->SendPreestablish()) if (!this->SendPreestablish())
{ {
@ -70,6 +81,18 @@ namespace Aurora::IO::Net
return; return;
} }
if (this->bHasRemoteMany_ && this->connectMany_.ips.size())
{
this->remoteEndpoint_ = this->connectMany_.ips[0];
}
if (this->osHandle_ &&
this->osHandle_ != -1)
{
::closesocket(this->osHandle_);
this->osHandle_ = 0;
}
this->osHandle_ = ::WSASocketW( this->osHandle_ = ::WSASocketW(
IPToDomain(this->remoteEndpoint_), IPToDomain(this->remoteEndpoint_),
TransportToPlatformType(this->remoteEndpoint_), TransportToPlatformType(this->remoteEndpoint_),
@ -79,7 +102,6 @@ namespace Aurora::IO::Net
WSA_FLAG_OVERLAPPED WSA_FLAG_OVERLAPPED
); );
if (this->osHandle_ == -1) if (this->osHandle_ == -1)
{ {
this->SendErrorNoStream(GetLastNetError()); this->SendErrorNoStream(GetLastNetError());
@ -93,10 +115,34 @@ namespace Aurora::IO::Net
} }
#if !defined(AURORA_IS_MODERNNT_DERIVED) #if !defined(AURORA_IS_MODERNNT_DERIVED)
this->osHandleOwner_ = AuMakeShared<AuFS::FileHandle>();
if (!this->osHandle_)
{
this->SendErrorNoStream(GetLastNetError());
return;
}
this->osHandleOwner_->Init((int)this->osHandle_, (int)this->osHandle_); this->osHandleOwner_->Init((int)this->osHandle_, (int)this->osHandle_);
#endif #endif
} }
void Socket::FinishConstructAsync()
{
if (this->resolveLater.size() || this->bResolving_)
{
if (!this->TryStartResolve())
{
this->SendErrorNoStream(GetLastNetError());
return;
}
return;
}
RenewSocket();
}
bool Socket::PrepareConnectOperations() bool Socket::PrepareConnectOperations()
{ {
::setsockopt(this->osHandle_, ::setsockopt(this->osHandle_,

View File

@ -29,6 +29,12 @@ namespace Aurora::IO::Net
const AuSPtr<ISocketDriver> &pSocketDriver, const AuSPtr<ISocketDriver> &pSocketDriver,
AuUInt osHandle); AuUInt osHandle);
Socket(struct NetInterface *pInterface,
struct NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver,
const AuPair<NetHostname, AuUInt16> &endpoint,
AuNet::ETransportProtocol eProtocol);
Socket(struct NetInterface *pInterface, Socket(struct NetInterface *pInterface,
struct NetWorker *pWorker, struct NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver, const AuSPtr<ISocketDriver> &pSocketDriver,
@ -61,5 +67,6 @@ namespace Aurora::IO::Net
virtual void Shutdown(bool bNow) override; virtual void Shutdown(bool bNow) override;
virtual void CloseSocket() override; virtual void CloseSocket() override;
virtual void RenewSocket() override;
}; };
} }

View File

@ -12,6 +12,7 @@
#include "AuIPAddress.hpp" #include "AuIPAddress.hpp"
#include "AuNetError.hpp" #include "AuNetError.hpp"
#include "AuNetSocketServer.hpp" #include "AuNetSocketServer.hpp"
#include "AuNetInterface.hpp"
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
#include "AuNetStream.NT.hpp" #include "AuNetStream.NT.hpp"
@ -54,9 +55,9 @@ namespace Aurora::IO::Net
} }
SocketBase::SocketBase(struct NetInterface *pInterface, SocketBase::SocketBase(struct NetInterface *pInterface,
struct NetWorker *pWorker, struct NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver, const AuSPtr<ISocketDriver> &pSocketDriver,
const NetEndpoint &endpoint) : const NetEndpoint &endpoint) :
connectOperation(this), connectOperation(this),
socketChannel_(this), socketChannel_(this),
pInterface_(pInterface), pInterface_(pInterface),
@ -72,6 +73,45 @@ namespace Aurora::IO::Net
this->pWorker_->AddSocket(this); this->pWorker_->AddSocket(this);
} }
SocketBase::SocketBase(struct NetInterface *pInterface,
struct NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver,
const AuPair<NetHostname, AuUInt16> &endpoint,
AuNet::ETransportProtocol eProtocol) :
connectOperation(this),
socketChannel_(this),
pInterface_(pInterface),
pWorker_(pWorker),
pSocketDriver_(pSocketDriver)
{
auto &[host, uPort] = endpoint;
if (host.type == AuNet::EHostnameType::eHostByIp)
{
this->remoteEndpoint_.ip = host.address;
this->remoteEndpoint_.uPort = uPort;
this->remoteEndpoint_.transportProtocol = eProtocol;
OptimizeEndpoint(this->remoteEndpoint_);
}
else
{
this->resolveLater = host.hostname;
this->remoteEndpoint_.uPort = uPort;
this->remoteEndpoint_.transportProtocol = eProtocol;
this->connectMany_.uPort = uPort;
this->connectMany_.protocol = eProtocol;
}
this->osHandleOwner_ = AuMakeShared<AuFS::FileHandle>();
if (!this->osHandle_)
{
return;
}
this->pWorker_->AddSocket(this);
}
SocketBase::SocketBase(NetInterface *pInterface, SocketBase::SocketBase(NetInterface *pInterface,
NetWorker *pWorker, NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver, const AuSPtr<ISocketDriver> &pSocketDriver,
@ -100,13 +140,48 @@ namespace Aurora::IO::Net
bool SocketBase::IsValid() bool SocketBase::IsValid()
{ {
return bool(this->osHandleOwner_) && return (this->resolveLater.size()) ||
bool(this->osHandleOwner_) &&
bool(this->connectOperation.IsValid()) && bool(this->connectOperation.IsValid()) &&
bool(this->osHandle_ != 0) && bool(this->osHandle_ != 0) &&
bool(this->osHandle_ != -1) && bool(this->osHandle_ != -1) &&
bool(!this->bForceFailConstruct_); bool(!this->bForceFailConstruct_);
} }
bool SocketBase::TryStartResolve()
{
auto pThat = this->SharedFromThis();
if (this->bResolving_)
{
return true;
}
this->bResolving_ = true;
auto address = this->resolveLater;
this->resolveLater.clear();
auto pResolver = this->pInterface_->GetResolveService()->SimpleAllResolve(address,
AuMakeSharedThrow<AuAsync::PromiseCallbackFunctional<AuList<AuNet::IPAddress>,
AuNet::NetError>>(
[=](const AuSPtr<AuList<AuNet::IPAddress>> &ips)
{
pThat->bResolving_ = false;
pThat->connectMany_.uPort = pThat->remoteEndpoint_.uPort;
pThat->connectMany_.ips.insert(pThat->connectMany_.ips.end(), ips->begin(), ips->end());
pThat->bHasRemoteMany_ = true;
pThat->RenewSocket();
pThat->ConnectNext();
},
[=](const AuSPtr<AuNet::NetError> &error)
{
pThat->SendErrorNoStream(error ? *error.get() : AuNet::NetError {});
}));
return bool(pResolver);
}
bool SocketBase::ConnectNext() bool SocketBase::ConnectNext()
{ {
if (this->connectMany_.ips.empty()) if (this->connectMany_.ips.empty())
@ -126,6 +201,12 @@ namespace Aurora::IO::Net
bool SocketBase::Connect(const NetEndpoint &endpoint) bool SocketBase::Connect(const NetEndpoint &endpoint)
{ {
if (!this->IsValid())
{
this->SendErrorNoStream({});
return false;
}
this->remoteEndpoint_ = endpoint; this->remoteEndpoint_ = endpoint;
this->endpointSize_ = OptimizeEndpoint(this->remoteEndpoint_); this->endpointSize_ = OptimizeEndpoint(this->remoteEndpoint_);
this->localEndpoint_.transportProtocol = this->remoteEndpoint_.transportProtocol; this->localEndpoint_.transportProtocol = this->remoteEndpoint_.transportProtocol;
@ -272,7 +353,7 @@ namespace Aurora::IO::Net
void SocketBase::SendOnData() void SocketBase::SendOnData()
{ {
auto pReadableBuffer = this->socketChannel_.AsReadableByteBuffer(); auto pReadableBuffer = this->socketChannel_.AsReadableByteBuffer();
auto pStartOffset = pReadableBuffer->readPtr; auto pStartOffset = pReadableBuffer ? pReadableBuffer->readPtr : nullptr;
if (this->bHasFinalized_) if (this->bHasFinalized_)
{ {
@ -305,7 +386,7 @@ namespace Aurora::IO::Net
this->ToChannel()->ScheduleOutOfFrameWrite(); this->ToChannel()->ScheduleOutOfFrameWrite();
auto uHeadDelta = pReadableBuffer->readPtr - pStartOffset; auto uHeadDelta = pReadableBuffer ? (pReadableBuffer->readPtr - pStartOffset) : 0;
this->socketChannel_.GetRecvStatsEx().AddBytes(uHeadDelta); this->socketChannel_.GetRecvStatsEx().AddBytes(uHeadDelta);
} }
@ -344,6 +425,11 @@ namespace Aurora::IO::Net
bool SocketBase::SendPreestablish(SocketServer *pServer) bool SocketBase::SendPreestablish(SocketServer *pServer)
{ {
if (this->bHasPreestablished_)
{
return true;
}
if (pServer && pServer->uDefaultInputStreamSize) if (pServer && pServer->uDefaultInputStreamSize)
{ {
this->socketChannel_.uBytesInputBuffer = pServer->uDefaultInputStreamSize; this->socketChannel_.uBytesInputBuffer = pServer->uDefaultInputStreamSize;
@ -365,7 +451,7 @@ namespace Aurora::IO::Net
} }
} }
return true; return this->bHasPreestablished_ = true;
} }
void SocketBase::SendEnd() void SocketBase::SendEnd()

View File

@ -37,6 +37,12 @@ namespace Aurora::IO::Net
const AuSPtr<ISocketDriver> &pSocketDriver, const AuSPtr<ISocketDriver> &pSocketDriver,
const NetEndpoint &endpoint); const NetEndpoint &endpoint);
SocketBase(struct NetInterface *pInterface,
struct NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver,
const AuPair<NetHostname, AuUInt16> &endpoint,
AuNet::ETransportProtocol eProtocol);
SocketBase(struct NetInterface *pInterface, SocketBase(struct NetInterface *pInterface,
struct NetWorker *pWorker, struct NetWorker *pWorker,
const AuSPtr<ISocketDriver> &pSocketDriver, const AuSPtr<ISocketDriver> &pSocketDriver,
@ -44,6 +50,7 @@ namespace Aurora::IO::Net
virtual ~SocketBase(); virtual ~SocketBase();
bool TryStartResolve();
bool ConnectNext(); bool ConnectNext();
bool Connect(const NetEndpoint &endpoint); bool Connect(const NetEndpoint &endpoint);
@ -102,14 +109,16 @@ namespace Aurora::IO::Net
virtual bool ConnectBlocking() = 0; virtual bool ConnectBlocking() = 0;
virtual void CloseSocket() = 0; virtual void CloseSocket() = 0;
virtual void RenewSocket() = 0;
AuUInt endpointSize_ {}; AuUInt endpointSize_ {};
bool bHasFinalized_ {}; bool bHasFinalized_ {};
bool bHasEnded {}; bool bHasEnded {};
bool bResolving_ {};
protected: protected:
AuUInt osHandle_; AuUInt osHandle_ {};
NetEndpoint remoteEndpoint_; NetEndpoint remoteEndpoint_;
NetEndpoint localEndpoint_; NetEndpoint localEndpoint_;
@ -128,6 +137,8 @@ namespace Aurora::IO::Net
bool bHasErrored_ {}; bool bHasErrored_ {};
bool bHasConnected_ {}; bool bHasConnected_ {};
bool bHasPreestablished_ {};
AuString resolveLater {};
}; };
} }

View File

@ -25,12 +25,6 @@ namespace Aurora::IO::Net
AuSPtr<ISocket> NetSrvSockets::Connect(const NetSocketConnect &netConnect) AuSPtr<ISocket> NetSrvSockets::Connect(const NetSocketConnect &netConnect)
{ {
if (netConnect.endpoint.transportProtocol != ETransportProtocol::eProtocolTCP)
{
SysPushErrorNet("Invalid transport protocol. Hint: Use ConnectManyEx for UDP.");
return {};
}
auto pWorker = this->pParent_->TryScheduleEx(); auto pWorker = this->pParent_->TryScheduleEx();
if (!pWorker) if (!pWorker)
{ {
@ -38,10 +32,48 @@ namespace Aurora::IO::Net
return {}; return {};
} }
auto pSocket = AuMakeShared<Socket>(this->pParent_, AuSPtr<Socket> pSocket;
pWorker.get(),
netConnect.pDriver, if (netConnect.endpoint)
netConnect.endpoint); {
if (netConnect.endpoint.Value().transportProtocol != ETransportProtocol::eProtocolTCP)
{
SysPushErrorNet("Invalid transport protocol. Hint: Use ConnectManyEx for UDP.");
return {};
}
pSocket = AuMakeShared<Socket>(this->pParent_,
pWorker.get(),
netConnect.pDriver,
netConnect.endpoint.value());
}
else
{
if (!netConnect.byHost.netHostname)
{
SysPushErrorArg("Missing hostname or endpoint");
return {};
}
if (!netConnect.byHost.protocol)
{
SysPushErrorArg("Missing protocol");
return {};
}
if (!netConnect.byHost.uPort)
{
SysPushErrorArg("Missing port");
return {};
}
pSocket = AuMakeShared<Socket>(this->pParent_,
pWorker.get(),
netConnect.pDriver,
AuMakePair(netConnect.byHost.netHostname.value(), netConnect.byHost.uPort.value()),
netConnect.byHost.protocol.value());
}
if (!pSocket) if (!pSocket)
{ {
SysPushErrorNet("No Memory"); SysPushErrorNet("No Memory");
@ -52,6 +84,11 @@ namespace Aurora::IO::Net
{ {
pSocket->FinishConstructAsync(); pSocket->FinishConstructAsync();
if (pSocket->bResolving_)
{
return;
}
if (!pSocket->IsValid()) if (!pSocket->IsValid())
{ {
pSocket->SendErrorNoStream({}); pSocket->SendErrorNoStream({});

View File

@ -11,54 +11,153 @@
namespace Aurora::Logging::Sinks namespace Aurora::Logging::Sinks
{ {
static void EraseFilesByTimestamp(AuUInt32 maxLogs,
const AuString &path, /*const its not worth reallocation*/ AuList<AuString> &files)
{
if (files.size() <= maxLogs)
{
return;
}
// our filenames are usually prefixed by an ISO 8601 timestamp where the most significant bits are last (YYYY-MM-DD?HH-MM-SS)
// a quick ghetto sort should be all we need. no need to waste time parsing timestamps
std::sort(files.begin(), files.end());
auto amount = files.size() - maxLogs;
for (auto x = 0, i = 0; ((x < amount) && (i > files.size())); i++)
{
try
{
if (AuIOFS::Remove(path + "/" + files[i]))
{
x++;
}
}
catch (...)
{
}
}
}
static void CleanupOldLogs(DirectoryLogger logger, const AuString &baseLogPath) static void CleanupOldLogs(DirectoryLogger logger, const AuString &baseLogPath)
{ {
AuList<AuString> files; AuList<AuString> files;
AuBST<AuString, AuIOFS::Stat> fileMeta; AuList<AuPair<AuString, AuIOFS::Stat>> fileMeta;
AuUInt32 size {}; AuUInt64 qwSize {};
AuIOFS::FilesInDirectory(baseLogPath, files); auto doScan = [&]()
for (const auto &file : files)
{ {
AuIOFS::Stat stat; files.clear();
AuIOFS::StatFile(baseLogPath + "/" + file, stat); fileMeta.clear();
fileMeta[file] = stat; qwSize = 0;
size += stat.uSize;
AuIOFS::FilesInDirectory(baseLogPath, files);
for (const auto &file : files)
{
AuIOFS::Stat stat;
AuIOFS::StatFile(baseLogPath + "/" + file, stat);
fileMeta.push_back(AuMakePair(file, stat));
qwSize += stat.uSize;
}
std::sort(fileMeta.begin(), fileMeta.end(), [](AuPair<AuString, AuIOFS::Stat> a, AuPair<AuString, AuIOFS::Stat> b)
{
return AuGet<1>(a).modified < AuGet<1>(b).modified;
});
};
doScan();
if (logger.uMaxFileTimeInDeltaMSOrZeroBeforeCompress)
{
auto qwMaxTime = AuTime::CurrentClockMS() - logger.uMaxFileTimeInDeltaMSOrZeroBeforeCompress;
bool bRescan {};
for (AuUInt i = 0; i < fileMeta.size(); i++)
{
if (qwMaxTime > fileMeta[i].second.modified)
{
auto path = baseLogPath + "/" + fileMeta[i].first;
if (AuIOFS::Compress(path))
{
AuIOFS::Remove(path);
}
bRescan = true;
}
}
if (bRescan)
{
doScan();
}
} }
EraseFilesByTimestamp(logger.maxLogsOrZero, baseLogPath, files); if (logger.uMaxCumulativeFileSizeInMiBOrZeroBeforeCompress)
// TODO: erase when size >= maxFileSizeOrZero * 1024 {
// Didn't auRuntime v1.0 have this? bool bRescan {};
if (qwSize > logger.uMaxCumulativeFileSizeInMiBOrZeroBeforeCompress)
{
std::sort(fileMeta.begin(), fileMeta.end(), [](AuPair<AuString, AuIOFS::Stat> a, AuPair<AuString, AuIOFS::Stat> b)
{
return AuGet<1>(a).uSize > AuGet<1>(b).uSize;
});
for (AuUInt i = 0; i < fileMeta.size(); i++)
{
if (qwSize <= logger.uMaxCumulativeFileSizeInMiBOrZeroBeforeCompress)
{
break;
}
auto path = baseLogPath + "/" + fileMeta[i].first;
if (AuIOFS::Compress(path))
{
AuIOFS::Remove(path);
}
bRescan = true;
}
}
if (bRescan)
{
doScan();
}
}
if (logger.uMaxLogsOrZeroBeforeDelete)
{
if (fileMeta.size() > logger.uMaxLogsOrZeroBeforeDelete)
{
for (AuUInt i = logger.uMaxLogsOrZeroBeforeDelete; i < fileMeta.size(); i++)
{
AuIOFS::Remove(baseLogPath + "/" + fileMeta[i].first);
}
doScan();
}
}
if (logger.uMaxCumulativeFileSizeInMiBOrZeroBeforeDelete)
{
bool bRescan {};
if (qwSize > logger.uMaxCumulativeFileSizeInMiBOrZeroBeforeDelete)
{
std::sort(fileMeta.begin(), fileMeta.end(), [](AuPair<AuString, AuIOFS::Stat> a, AuPair<AuString, AuIOFS::Stat> b)
{
return AuGet<1>(a).uSize > AuGet<1>(b).uSize;
});
for (AuUInt i = 0; i < fileMeta.size(); i++)
{
if (qwSize <= logger.uMaxCumulativeFileSizeInMiBOrZeroBeforeDelete)
{
break;
}
if (AuIOFS::Remove(baseLogPath + "/" + fileMeta[i].first))
{
qwSize -= fileMeta[i].second.uSize;
bRescan = true;
}
}
}
if (bRescan)
{
doScan();
}
}
if (logger.uMaxFileTimeInDeltaMSOrZeroBeforeDelete)
{
auto qwMaxTime = AuTime::CurrentClockMS() - logger.uMaxFileTimeInDeltaMSOrZeroBeforeDelete;
for (AuUInt i = 0; i < fileMeta.size(); i++)
{
if (qwMaxTime > fileMeta[i].second.modified)
{
AuIOFS::Remove(baseLogPath + "/" + fileMeta[i].first);
}
}
}
} }
IBasicSink *NewDirectoryLoggerNew(const AuString &baseDirectory, IBasicSink *NewDirectoryLoggerNew(const AuString &baseDirectory,
@ -68,10 +167,11 @@ namespace Aurora::Logging::Sinks
AuString path; AuString path;
auto tm = Time::ToCivilTime(Time::CurrentClockMS()); auto tm = Time::ToCivilTime(Time::CurrentClockMS());
path = fmt::format("{}/{:04}-{:02}-{:02}T{:02}-{:02}-{:02}Z.txt", path = fmt::format("{}/{:04}-{:02}-{:02}T{:02}-{:02}-{:02}Z.{}",
baseDirectory, baseDirectory,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec); tm.tm_hour, tm.tm_min, tm.tm_sec,
bBinary ? ".log" : ".txt");
CleanupOldLogs(meta, baseDirectory); CleanupOldLogs(meta, baseDirectory);