diff options
| author | Martin Ridgers <[email protected]> | 2021-09-16 10:13:28 +0200 |
|---|---|---|
| committer | Martin Ridgers <[email protected]> | 2021-09-16 10:13:58 +0200 |
| commit | 7aa3ceabe4254479bd066ae3ea941396fdc6733c (patch) | |
| tree | a7d0a7fde0a5a3c42302238965c25c665fc28005 | |
| parent | Missing include (diff) | |
| parent | Added some placeholder HttpClient functions to be fleshed out (diff) | |
| download | zen-7aa3ceabe4254479bd066ae3ea941396fdc6733c.tar.xz zen-7aa3ceabe4254479bd066ae3ea941396fdc6733c.zip | |
Merge from main
40 files changed, 319 insertions, 117 deletions
diff --git a/zen/cmds/copy.cpp b/zen/cmds/copy.cpp index 2830f8c28..4ce09c982 100644 --- a/zen/cmds/copy.cpp +++ b/zen/cmds/copy.cpp @@ -37,10 +37,10 @@ CopyCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) // Validate arguments if (m_CopySource.empty()) - throw std::exception("No source specified"); + throw std::runtime_error("No source specified"); if (m_CopyTarget.empty()) - throw std::exception("No target specified"); + throw std::runtime_error("No target specified"); std::filesystem::path FromPath; std::filesystem::path ToPath; @@ -53,12 +53,12 @@ CopyCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) if (!IsFileCopy && !IsDirCopy) { - throw std::exception("Invalid source specification (neither directory nor file)"); + throw std::runtime_error("Invalid source specification (neither directory nor file)"); } if (IsFileCopy && IsDirCopy) { - throw std::exception("Invalid source specification (both directory AND file!?)"); + throw std::runtime_error("Invalid source specification (both directory AND file!?)"); } if (IsDirCopy) @@ -70,7 +70,7 @@ CopyCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) { if (std::filesystem::is_regular_file(ToPath)) { - throw std::exception("Attempted copy of directory into file"); + throw std::runtime_error("Attempted copy of directory into file"); } } } diff --git a/zen/cmds/deploy.cpp b/zen/cmds/deploy.cpp index bee7baf90..b8879fefb 100644 --- a/zen/cmds/deploy.cpp +++ b/zen/cmds/deploy.cpp @@ -38,10 +38,10 @@ DeployCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) // Validate arguments if (m_CopySource.empty()) - throw std::exception("No source specified"); + throw std::runtime_error("No source specified"); if (m_CopyTarget.empty()) - throw std::exception("No target specified"); + throw std::runtime_error("No target specified"); std::filesystem::path ToPath; @@ -52,7 +52,7 @@ DeployCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) if (!IsTargetNew && !IsTargetDir) { - throw std::exception("Invalid target specification (needs to be a directory)"); + throw std::runtime_error("Invalid target specification (needs to be a directory)"); } zen::ExtendableStringBuilder<128> Path8; diff --git a/zen/zen.cpp b/zen/zen.cpp index 4b8d3adc1..d8bfa13e5 100644 --- a/zen/zen.cpp +++ b/zen/zen.cpp @@ -96,6 +96,8 @@ main(int argc, char** argv) { mi_version(); + zen::logging::InitializeLogging(); + #if TEST_UWS /* Overly simple hello world app, using multiple threads */ std::vector<std::thread*> threads(4); diff --git a/zencore-test/zencore-test.cpp b/zencore-test/zencore-test.cpp index 8c53cf349..1782f1926 100644 --- a/zencore-test/zencore-test.cpp +++ b/zencore-test/zencore-test.cpp @@ -1,8 +1,8 @@ // zencore-test.cpp : Defines the entry point for the console application. // -#include <zencore/sha1.h> #include <zencore/zencore.h> +#include <zencore/logging.h> #define DOCTEST_CONFIG_IMPLEMENT #include <doctest/doctest.h> @@ -17,5 +17,7 @@ forceLinkTests() int main(int argc, char* argv[]) { + zen::logging::InitializeLogging(); + return doctest::Context(argc, argv).run(); } diff --git a/zencore/compactbinaryvalidation.cpp b/zencore/compactbinaryvalidation.cpp index 316da76a6..dafd1bcc8 100644 --- a/zencore/compactbinaryvalidation.cpp +++ b/zencore/compactbinaryvalidation.cpp @@ -418,7 +418,7 @@ ValidateCbPackageAttachment(CbFieldView& Value, MemoryView& View, CbValidateMode { if (const CbObjectView ObjectView = Value.AsObjectView(); !Value.HasError()) { - return CbObject().GetHash(); + return ObjectView.GetHash(); } if (const IoHash ObjectAttachmentHash = Value.AsObjectAttachment(); !Value.HasError()) diff --git a/zencore/compress.cpp b/zencore/compress.cpp index 55808375e..12a7b9ef8 100644 --- a/zencore/compress.cpp +++ b/zencore/compress.cpp @@ -103,7 +103,7 @@ struct BufferHeader constexpr uint64_t MethodOffset = offsetof(BufferHeader, Method); for (MemoryView View = HeaderView + MethodOffset; const uint64_t ViewSize = View.GetSize();) { - const int32_t Size = static_cast<int32_t>(zen::Min<uint64_t>(ViewSize, INT_MAX)); + const int32_t Size = static_cast<int32_t>(zen::Min<uint64_t>(ViewSize, /* INT_MAX */ 2147483647u)); Crc32 = zen::MemCrc32(View.GetData(), Size, Crc32); View += Size; } @@ -211,7 +211,7 @@ private: CompositeBuffer BlockEncoder::Compress(const CompositeBuffer& RawData, const uint64_t BlockSize) const { - ZEN_ASSERT(IsPow2(BlockSize) && BlockSize <= (1 << 31)); + ZEN_ASSERT(IsPow2(BlockSize) && (BlockSize <= (1u << 31))); const uint64_t RawSize = RawData.GetSize(); BLAKE3Stream RawHash; @@ -592,7 +592,7 @@ protected: const int Size = LZ4_decompress_safe(static_cast<const char*>(CompressedData.GetData()), static_cast<char*>(RawData.GetData()), static_cast<int>(CompressedData.GetSize()), - static_cast<int>(zen::Min<uint64_t>(RawData.GetSize(), LZ4_MAX_INPUT_SIZE))); + static_cast<int>(zen::Min<uint64_t>(RawData.GetSize(), uint64_t(LZ4_MAX_INPUT_SIZE)))); return static_cast<uint64_t>(Size) == RawData.GetSize(); } return false; diff --git a/zencore/except.cpp b/zencore/except.cpp index 123d8e231..75d0c8dd1 100644 --- a/zencore/except.cpp +++ b/zencore/except.cpp @@ -40,6 +40,7 @@ GetErrorAsString(uint32_t ErrorCode) return std::error_code(ErrorCode, std::system_category()).message(); } +#if __cpp_lib_source_location void ThrowLastError(std::string_view Message, const std::source_location& Location) { @@ -47,5 +48,6 @@ ThrowLastError(std::string_view Message, const std::source_location& Location) throw std::system_error(std::error_code(zen::GetLastError(), std::system_category()), "{}({}): {}"_format(Location.file_name(), Location.line(), Message)); } +#endif } // namespace zen diff --git a/zencore/filesystem.cpp b/zencore/filesystem.cpp index 14eef812f..2942910ed 100644 --- a/zencore/filesystem.cpp +++ b/zencore/filesystem.cpp @@ -619,6 +619,8 @@ PathFromHandle(void* NativeHandle) const DWORD FinalLength = GetFinalPathNameByHandleW(NativeHandle, FullPath.data(), RequiredLengthIncludingNul, FILE_NAME_OPENED); + ZEN_UNUSED(FinalLength); + return FullPath; #elif ZEN_PLATFORM_LINUX char Buffer[256]; diff --git a/zencore/include/zencore/except.h b/zencore/include/zencore/except.h index 5b4a49364..90f7d45db 100644 --- a/zencore/include/zencore/except.h +++ b/zencore/include/zencore/except.h @@ -54,7 +54,11 @@ ZENCORE_API void ThrowSystemException(HRESULT hRes, std::string_view Message); #endif // ZEN_PLATFORM_WINDOWS ZENCORE_API void ThrowLastError(std::string_view Message); + +#if __cpp_lib_source_location ZENCORE_API void ThrowLastError(std::string_view Message, const std::source_location& Location); +#endif + ZENCORE_API std::string GetLastErrorAsString(); ZENCORE_API std::string GetErrorAsString(uint32_t ErrorCode); diff --git a/zencore/include/zencore/intmath.h b/zencore/include/zencore/intmath.h index 85447c17a..814a03df4 100644 --- a/zencore/include/zencore/intmath.h +++ b/zencore/include/zencore/intmath.h @@ -9,7 +9,7 @@ ////////////////////////////////////////////////////////////////////////// -#if ZEN_COMPILER_MSC +#if ZEN_COMPILER_MSC || ZEN_PLATFORM_WINDOWS # pragma intrinsic(_BitScanReverse) # pragma intrinsic(_BitScanReverse64) #else diff --git a/zencore/include/zencore/iobuffer.h b/zencore/include/zencore/iobuffer.h index 034c3566f..c3860f2b0 100644 --- a/zencore/include/zencore/iobuffer.h +++ b/zencore/include/zencore/iobuffer.h @@ -13,14 +13,16 @@ struct IoBufferExtendedCore; enum class ZenContentType : uint8_t { - kBinary, // Note that since this is zero, this will be the default value in IoBuffer - kText, - kJSON, - kCbObject, - kCbPackage, - kYAML, - kCbPackageOffer, - kUnknownContentType + kBinary = 0, // Note that since this is zero, this will be the default value in IoBuffer + kText = 1, + kJSON = 2, + kCbObject = 3, + kCbPackage = 4, + kYAML = 5, + kCbPackageOffer = 6, + kCompressedBinary = 7, + kUnknownContentType = 8, + kCOUNT }; struct IoBufferFileReference @@ -321,7 +323,9 @@ public: [[nodiscard]] void* MutableData() const { return m_Core->MutableDataPointer(); } void MakeImmutable() { m_Core->SetIsImmutable(true); } [[nodiscard]] const void* Data() const { return m_Core->DataPointer(); } + [[nodiscard]] const void* GetData() const { return m_Core->DataPointer(); } [[nodiscard]] size_t Size() const { return m_Core->DataBytes(); } + [[nodiscard]] size_t GetSize() const { return m_Core->DataBytes(); } inline void SetContentType(ZenContentType ContentType) { m_Core->SetContentType(ContentType); } [[nodiscard]] inline ZenContentType GetContentType() const { return m_Core->GetContentType(); } [[nodiscard]] ZENCORE_API bool GetFileReference(IoBufferFileReference& OutRef) const; diff --git a/zencore/include/zencore/logging.h b/zencore/include/zencore/logging.h index eefed4efa..8e6b3a244 100644 --- a/zencore/include/zencore/logging.h +++ b/zencore/include/zencore/logging.h @@ -13,6 +13,7 @@ namespace zen::logging { spdlog::logger& Default(); +void SetDefault(std::shared_ptr<spdlog::logger> NewDefaultLogger); spdlog::logger& ConsoleLog(); spdlog::logger& Get(std::string_view Name); @@ -22,7 +23,14 @@ void ShutdownLogging(); } // namespace zen::logging namespace zen { -spdlog::logger& Log(); +extern spdlog::logger* TheDefaultLogger; + +inline spdlog::logger& +Log() +{ + return *TheDefaultLogger; +} + using logging::ConsoleLog; } // namespace zen @@ -31,9 +39,44 @@ using zen::Log; // Helper macros for logging -#define ZEN_TRACE(...) Log().trace(__VA_ARGS__) -#define ZEN_DEBUG(...) Log().debug(__VA_ARGS__) -#define ZEN_INFO(...) Log().info(__VA_ARGS__) -#define ZEN_WARN(...) Log().warn(__VA_ARGS__) -#define ZEN_ERROR(...) Log().error(__VA_ARGS__) -#define ZEN_CRITICAL(...) Log().critical(__VA_ARGS__) +#define ZEN_TRACE(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().trace(fmtstr##sv, __VA_ARGS__); \ + } while (false) + +#define ZEN_DEBUG(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().debug(fmtstr##sv, __VA_ARGS__); \ + } while (false) + +#define ZEN_INFO(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().info(fmtstr##sv, __VA_ARGS__); \ + } while (false) + +#define ZEN_WARN(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().warn(fmtstr##sv, __VA_ARGS__); \ + } while (false) + +#define ZEN_ERROR(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().error(fmtstr##sv, __VA_ARGS__); \ + } while (false) + +#define ZEN_CRITICAL(fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + Log().critical(fmtstr##sv, __VA_ARGS__); \ + } while (false) diff --git a/zencore/include/zencore/session.h b/zencore/include/zencore/session.h new file mode 100644 index 000000000..e66794704 --- /dev/null +++ b/zencore/include/zencore/session.h @@ -0,0 +1,11 @@ +#pragma once + +#include <zencore/zencore.h> + +namespace zen { + +struct Oid; + +ZENCORE_API Oid GetSessionId(); + +} diff --git a/zencore/include/zencore/stream.h b/zencore/include/zencore/stream.h index 4e8c58382..a0e165bdc 100644 --- a/zencore/include/zencore/stream.h +++ b/zencore/include/zencore/stream.h @@ -36,6 +36,7 @@ class InStream : public RefCounted public: virtual void Read(void* DataPtr, size_t ByteCount, uint64_t Offset) = 0; virtual uint64_t Size() const = 0; + uint64_t GetSize() const { return Size(); } }; /** @@ -50,7 +51,9 @@ public: virtual void Write(const void* DataPtr, size_t ByteCount, uint64_t Offset) override; virtual void Flush() override; inline const uint8_t* Data() const { return m_Buffer.data(); } + inline const uint8_t* GetData() const { return m_Buffer.data(); } inline uint64_t Size() const { return m_Buffer.size(); } + inline uint64_t GetSize() const { return m_Buffer.size(); } private: RwLock m_Lock; @@ -76,6 +79,7 @@ public: virtual void Read(void* DataPtr, size_t ByteCount, uint64_t ReadOffset) override; virtual uint64_t Size() const override { return m_Buffer.size(); } inline const uint8_t* Data() const { return m_Buffer.data(); } + inline const uint8_t* GetData() const { return m_Buffer.data(); } private: RwLock m_Lock; diff --git a/zencore/iobuffer.cpp b/zencore/iobuffer.cpp index 378105e69..cf167a7c6 100644 --- a/zencore/iobuffer.cpp +++ b/zencore/iobuffer.cpp @@ -224,7 +224,7 @@ IoBufferExtendedCore::Materialize() const if (MappedBase == nullptr) { throw std::system_error( - std::error_code(zen::GetLastError(), std::system_category()), + std::error_code(::GetLastError(), std::system_category()), "MapViewOfFile failed (offset {:#x}, size {:#x}) file: '{}'"_format(MapOffset, MapSize, zen::PathFromHandle(m_FileHandle))); } diff --git a/zencore/logging.cpp b/zencore/logging.cpp index 9d5a726f5..c5c0b6446 100644 --- a/zencore/logging.cpp +++ b/zencore/logging.cpp @@ -6,11 +6,8 @@ namespace zen { -spdlog::logger& -Log() -{ - return *spdlog::default_logger(); -} +// We shadow the underlying spdlog default logger, in order to avoid a bunch of overhead +spdlog::logger* TheDefaultLogger; } // namespace zen @@ -19,20 +16,24 @@ namespace zen::logging { spdlog::logger& Default() { - return *spdlog::default_logger(); + return *TheDefaultLogger; +} + +void +SetDefault(std::shared_ptr<spdlog::logger> NewDefaultLogger) +{ + spdlog::set_default_logger(NewDefaultLogger); + TheDefaultLogger = spdlog::default_logger_raw(); } spdlog::logger& Get(std::string_view Name) { std::shared_ptr<spdlog::logger> Logger = spdlog::get(std::string(Name)); + if (!Logger) { - Logger = std::make_shared<spdlog::logger>(std::string(Name), - begin(spdlog::default_logger()->sinks()), - end(spdlog::default_logger()->sinks())); - - Logger->set_level(spdlog::default_logger()->level()); + Logger = Default().clone(std::string(Name)); spdlog::register_logger(Logger); } @@ -57,6 +58,7 @@ ConsoleLog() void InitializeLogging() { + TheDefaultLogger = spdlog::default_logger_raw(); } void diff --git a/zencore/session.cpp b/zencore/session.cpp new file mode 100644 index 000000000..195a9d97c --- /dev/null +++ b/zencore/session.cpp @@ -0,0 +1,21 @@ +#include "zencore/session.h" + +#include <zencore/uid.h> + +#include <mutex> + +namespace zen { + +static Oid GlobalSessionId; +static std::once_flag SessionInitFlag; + +Oid GetSessionId() +{ + std::call_once(SessionInitFlag, [&] { + GlobalSessionId.Generate(); + }); + + return GlobalSessionId; +} + +}
\ No newline at end of file diff --git a/zencore/uid.cpp b/zencore/uid.cpp index 644d0aa77..acf9f9790 100644 --- a/zencore/uid.cpp +++ b/zencore/uid.cpp @@ -100,6 +100,7 @@ TEST_CASE("Oid") SUBCASE("Basic") { Oid id1 = Oid::NewOid(); + ZEN_UNUSED(id1); std::vector<Oid> ids; std::set<Oid> idset; diff --git a/zencore/zencore.vcxproj b/zencore/zencore.vcxproj index 4f1e63670..150c42cd6 100644 --- a/zencore/zencore.vcxproj +++ b/zencore/zencore.vcxproj @@ -132,6 +132,7 @@ <ClInclude Include="include\zencore\prewindows.h" /> <ClInclude Include="include\zencore\refcount.h" /> <ClInclude Include="include\zencore\scopeguard.h" /> + <ClInclude Include="include\zencore\session.h" /> <ClInclude Include="include\zencore\sha1.h" /> <ClInclude Include="include\zencore\iobuffer.h" /> <ClInclude Include="include\zencore\sharedbuffer.h" /> @@ -166,6 +167,7 @@ <ClCompile Include="md5.cpp" /> <ClCompile Include="memory.cpp" /> <ClCompile Include="refcount.cpp" /> + <ClCompile Include="session.cpp" /> <ClCompile Include="sha1.cpp"> <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization> <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AnySuitable</InlineFunctionExpansion> @@ -189,6 +191,9 @@ <ClCompile Include="xxhash.cpp" /> <ClCompile Include="zencore.cpp" /> </ItemGroup> + <ItemGroup> + <None Include="xmake.lua" /> + </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> diff --git a/zencore/zencore.vcxproj.filters b/zencore/zencore.vcxproj.filters index de3d915b8..ea0f8a912 100644 --- a/zencore/zencore.vcxproj.filters +++ b/zencore/zencore.vcxproj.filters @@ -41,6 +41,7 @@ <ClInclude Include="include\zencore\prewindows.h" /> <ClInclude Include="include\zencore\postwindows.h" /> <ClInclude Include="include\zencore\logging.h" /> + <ClInclude Include="include\zencore\session.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="snapshot_manifest.cpp" /> @@ -72,10 +73,14 @@ <ClCompile Include="crc32.cpp" /> <ClCompile Include="logging.cpp" /> <ClCompile Include="intmath.cpp" /> + <ClCompile Include="session.cpp" /> </ItemGroup> <ItemGroup> <Filter Include="CAS"> <UniqueIdentifier>{af5266fa-37a5-494c-9116-b15a3e6edd29}</UniqueIdentifier> </Filter> </ItemGroup> + <ItemGroup> + <None Include="xmake.lua" /> + </ItemGroup> </Project>
\ No newline at end of file diff --git a/zenhttp/httpclient.cpp b/zenhttp/httpclient.cpp index b7df12026..7e3e9d374 100644 --- a/zenhttp/httpclient.cpp +++ b/zenhttp/httpclient.cpp @@ -7,6 +7,7 @@ #include <zencore/compactbinarypackage.h> #include <zencore/iobuffer.h> #include <zencore/logging.h> +#include <zencore/session.h> #include <zencore/sharedbuffer.h> #include <zencore/stream.h> @@ -30,6 +31,9 @@ FromCprResponse(cpr::Response& InResponse) HttpClient::HttpClient(std::string_view BaseUri) : m_BaseUri(BaseUri) { + StringBuilder<32> SessionId; + GetSessionId().ToString(SessionId); + m_SessionId = SessionId; } HttpClient::~HttpClient() @@ -68,8 +72,7 @@ HttpClient::TransactPackage(std::string_view Url, CbPackage Package) BinaryWriter MemWriter(MemOut); Writer.Save(MemWriter); - Sess.SetHeader( - {{"Content-Type", "application/x-ue-offer"}, {"UE-Session", "123456789012345678901234"}, {"UE-Request", RequestIdString}}); + Sess.SetHeader({{"Content-Type", "application/x-ue-offer"}, {"UE-Session", m_SessionId}, {"UE-Request", RequestIdString}}); Sess.SetBody(cpr::Body{(const char*)MemOut.Data(), MemOut.Size()}); cpr::Response FilterResponse = Sess.Post(); @@ -111,8 +114,7 @@ HttpClient::TransactPackage(std::string_view Url, CbPackage Package) CompositeBuffer Message = FormatPackageMessageBuffer(SendPackage); SharedBuffer FlatMessage = Message.Flatten(); - Sess.SetHeader( - {{"Content-Type", "application/x-ue-cbpkg"}, {"UE-Session", "123456789012345678901234"}, {"UE-Request", RequestIdString}}); + Sess.SetHeader({{"Content-Type", "application/x-ue-cbpkg"}, {"UE-Session", m_SessionId}, {"UE-Request", RequestIdString}}); Sess.SetBody(cpr::Body{(const char*)FlatMessage.GetData(), FlatMessage.GetSize()}); cpr::Response FilterResponse = Sess.Post(); @@ -135,6 +137,21 @@ HttpClient::TransactPackage(std::string_view Url, CbPackage Package) } HttpClient::Response +HttpClient::Put(std::string_view Url, IoBuffer Payload) +{ + ZEN_UNUSED(Url); + ZEN_UNUSED(Payload); + return {}; +} + +HttpClient::Response +HttpClient::Get(std::string_view Url) +{ + ZEN_UNUSED(Url); + return {}; +} + +HttpClient::Response HttpClient::Delete(std::string_view Url) { ZEN_UNUSED(Url); diff --git a/zenhttp/httpserver.cpp b/zenhttp/httpserver.cpp index f97ac0067..f4a5f4345 100644 --- a/zenhttp/httpserver.cpp +++ b/zenhttp/httpserver.cpp @@ -19,6 +19,7 @@ #include <conio.h> #include <new.h> #include <charconv> +#include <mutex> #include <span> #include <string_view> @@ -53,59 +54,81 @@ MapContentTypeToString(HttpContentType ContentType) case HttpContentType::kCbPackageOffer: return "application/x-ue-offer"sv; + case HttpContentType::kCompressedBinary: + return "application/x-ue-comp"sv; + case HttpContentType::kYAML: return "text/yaml"sv; } } -static const uint32_t HashBinary = HashStringDjb2("application/octet-stream"sv); -static const uint32_t HashJson = HashStringDjb2("application/json"sv); -static const uint32_t HashYaml = HashStringDjb2("text/yaml"sv); -static const uint32_t HashText = HashStringDjb2("text/plain"sv); -static const uint32_t HashCompactBinary = HashStringDjb2("application/x-ue-cb"sv); -static const uint32_t HashCompactBinaryPackage = HashStringDjb2("application/x-ue-cbpkg"sv); -static const uint32_t HashCompactBinaryPackageOffer = HashStringDjb2("application/x-ue-offer"sv); +////////////////////////////////////////////////////////////////////////// + +static constinit uint32_t HashBinary = HashStringDjb2("application/octet-stream"sv); +static constinit uint32_t HashJson = HashStringDjb2("application/json"sv); +static constinit uint32_t HashYaml = HashStringDjb2("text/yaml"sv); +static constinit uint32_t HashText = HashStringDjb2("text/plain"sv); +static constinit uint32_t HashCompactBinary = HashStringDjb2("application/x-ue-cb"sv); +static constinit uint32_t HashCompactBinaryPackage = HashStringDjb2("application/x-ue-cbpkg"sv); +static constinit uint32_t HashCompactBinaryPackageOffer = HashStringDjb2("application/x-ue-offer"sv); +static constinit uint32_t HashCompressedBinary = HashStringDjb2("application/x-ue-comp"sv); + +std::once_flag InitContentTypeLookup; + +struct HashedTypeEntry +{ + uint32_t Hash; + HttpContentType Type; +} TypeHashTable[] = {{HashBinary, HttpContentType::kBinary}, + {HashCompactBinary, HttpContentType::kCbObject}, + {HashCompactBinaryPackage, HttpContentType::kCbPackage}, + {HashCompactBinaryPackageOffer, HttpContentType::kCbPackageOffer}, + {HashJson, HttpContentType::kJSON}, + {HashYaml, HttpContentType::kYAML}, + {HashText, HttpContentType::kText}, + {HashCompressedBinary, HttpContentType::kCompressedBinary}}; HttpContentType -ParseContentType(const std::string_view& ContentTypeString) +ParseContentTypeImpl(const std::string_view& ContentTypeString) { if (!ContentTypeString.empty()) { const uint32_t CtHash = HashStringDjb2(ContentTypeString); - if (CtHash == HashBinary) - { - return HttpContentType::kBinary; - } - else if (CtHash == HashCompactBinary) - { - return HttpContentType::kCbObject; - } - else if (CtHash == HashCompactBinaryPackage) + if (auto It = std::lower_bound(std::begin(TypeHashTable), + std::end(TypeHashTable), + CtHash, + [](const HashedTypeEntry& Lhs, const uint32_t Rhs) { return Lhs.Hash < Rhs; }); + It != std::end(TypeHashTable)) { - return HttpContentType::kCbPackage; - } - else if (CtHash == HashCompactBinaryPackageOffer) - { - return HttpContentType::kCbPackageOffer; - } - else if (CtHash == HashJson) - { - return HttpContentType::kJSON; - } - else if (CtHash == HashYaml) - { - return HttpContentType::kYAML; - } - else if (CtHash == HashText) - { - return HttpContentType::kText; + if (It->Hash == CtHash) + { + return It->Type; + } } } return HttpContentType::kUnknownContentType; } +HttpContentType +ParseContentTypeInit(const std::string_view& ContentTypeString) +{ + std::call_once(InitContentTypeLookup, [] { + std::sort(std::begin(TypeHashTable), std::end(TypeHashTable), [](const HashedTypeEntry& Lhs, const HashedTypeEntry& Rhs) { + return Lhs.Hash < Rhs.Hash; + }); + }); + + ParseContentType = ParseContentTypeImpl; + + return ParseContentTypeImpl(ContentTypeString); +} + +HttpContentType (*ParseContentType)(const std::string_view& ContentTypeString) = &ParseContentTypeInit; + +////////////////////////////////////////////////////////////////////////// + const char* ReasonStringForHttpResultCode(int HttpCode) { @@ -502,7 +525,7 @@ CreateHttpServer() ////////////////////////////////////////////////////////////////////////// -TEST_CASE("http") +TEST_CASE("http.common") { using namespace std::literals; @@ -523,6 +546,19 @@ TEST_CASE("http") // TestHttpServerRequest req{}; // r.HandleRequest(req); } + + SUBCASE("content-type") + { + for (uint8_t i = 0; i < uint8_t(HttpContentType::kCOUNT); ++i) + { + HttpContentType Ct{i}; + + if (Ct != HttpContentType::kUnknownContentType) + { + CHECK_EQ(Ct, ParseContentType(MapContentTypeToString(Ct))); + } + } + } } void diff --git a/zenhttp/httpsys.cpp b/zenhttp/httpsys.cpp index 533971c4c..d4c58bffd 100644 --- a/zenhttp/httpsys.cpp +++ b/zenhttp/httpsys.cpp @@ -554,7 +554,7 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode) CancelThreadpoolIo(Iocp); - ZEN_ERROR("failed to send HTTP response (error: '{}'), request URL: {}"sv, SendResult, HttpReq->pRawUrl); + ZEN_ERROR("failed to send HTTP response (error: '{}'), request URL: {}", SendResult, HttpReq->pRawUrl); ErrorCode = MakeErrorCode(SendResult); } @@ -605,7 +605,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create server session for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create server session for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -614,7 +614,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create URL group for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create URL group for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -625,7 +625,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to add base URL to URL group for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to add base URL to URL group for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -640,7 +640,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create request queue for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create request queue for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -652,7 +652,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to set server binding property for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to set server binding property for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -664,7 +664,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (ErrorCode) { - ZEN_ERROR("Failed to create IOCP for '{}': {}"sv, WideToUtf8(UrlPath), ErrorCode.message()); + ZEN_ERROR("Failed to create IOCP for '{}': {}", WideToUtf8(UrlPath), ErrorCode.message()); } else { @@ -803,7 +803,7 @@ HttpSysServer::RegisterService(const char* UrlPath, HttpService& Service) if (Result != NO_ERROR) { - ZEN_ERROR("HttpAddUrlToUrlGroup failed with result {}"sv, Result); + ZEN_ERROR("HttpAddUrlToUrlGroup failed with result {}", Result); return; } @@ -829,7 +829,7 @@ HttpSysServer::UnregisterService(const char* UrlPath, HttpService& Service) if (Result != NO_ERROR) { - ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result {}"sv, Result); + ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result {}", Result); } } @@ -917,7 +917,7 @@ HttpSysTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTran if (ErrorCode) { - ZEN_ERROR("IssueRequest() failed {}"sv, ErrorCode.message()); + ZEN_ERROR("IssueRequest() failed {}", ErrorCode.message()); } else { @@ -926,7 +926,7 @@ HttpSysTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTran } catch (std::exception& Ex) { - ZEN_ERROR("exception caught from IssueRequest(): {}"sv, Ex.what()); + ZEN_ERROR("exception caught from IssueRequest(): {}", Ex.what()); // something went wrong, no request is pending } @@ -980,14 +980,20 @@ HttpSysTransaction::InvokeRequestHandler(HttpService& Service, IoBuffer Payload) { // Should yield bad request response? + ZEN_WARN("found invalid entry in offer"); + continue; } - OfferCids.push_back(CidEntry.AsHash(IoHash::Zero)); + OfferCids.push_back(CidEntry.AsHash()); } + ZEN_TRACE("request #{} -> filtering offer of {} entries", ThisRequest.RequestId(), OfferCids.size()); + m_PackageHandler->FilterOffer(OfferCids); + ZEN_TRACE("request #{} -> filtered to {} entries", ThisRequest.RequestId(), OfferCids.size()); + CbObjectWriter ResponseWriter; ResponseWriter.BeginArray("need"); diff --git a/zenhttp/include/zenhttp/httpclient.h b/zenhttp/include/zenhttp/httpclient.h index 8975f6fe1..3e342f2bd 100644 --- a/zenhttp/include/zenhttp/httpclient.h +++ b/zenhttp/include/zenhttp/httpclient.h @@ -5,6 +5,7 @@ #include "zenhttp.h" #include <zencore/iobuffer.h> +#include <zencore/uid.h> #include <zenhttp/httpcommon.h> #include <zencore/windows.h> @@ -22,7 +23,9 @@ namespace zen { class CbPackage; -/** Asynchronous HTTP client implementation for Zen use cases +/** HTTP client implementation for Zen use cases + + Currently simple and synchronous, should become lean and asynchronous */ class HttpClient { @@ -33,14 +36,17 @@ public: struct Response { int StatusCode = 0; - IoBuffer ResponsePayload; + IoBuffer ResponsePayload; // Note: this also includes the content type }; + [[nodiscard]] Response Put(std::string_view Url, IoBuffer Payload); + [[nodiscard]] Response Get(std::string_view Url); [[nodiscard]] Response TransactPackage(std::string_view Url, CbPackage Package); [[nodiscard]] Response Delete(std::string_view Url); private: std::string m_BaseUri; + std::string m_SessionId; }; } // namespace zen diff --git a/zenhttp/include/zenhttp/httpcommon.h b/zenhttp/include/zenhttp/httpcommon.h index 41ec706f4..08f1b47a9 100644 --- a/zenhttp/include/zenhttp/httpcommon.h +++ b/zenhttp/include/zenhttp/httpcommon.h @@ -18,8 +18,8 @@ class CbPackage; class StringBuilderBase; std::string_view MapContentTypeToString(HttpContentType ContentType); -HttpContentType ParseContentType(const std::string_view& ContentTypeString); -const char* ReasonStringForHttpResultCode(int HttpCode); +extern HttpContentType (*ParseContentType)(const std::string_view& ContentTypeString); +const char* ReasonStringForHttpResultCode(int HttpCode); [[nodiscard]] inline bool IsHttpSuccessCode(int HttpCode) diff --git a/zenhttp/include/zenhttp/httpserver.h b/zenhttp/include/zenhttp/httpserver.h index de097ceb3..f656c69a8 100644 --- a/zenhttp/include/zenhttp/httpserver.h +++ b/zenhttp/include/zenhttp/httpserver.h @@ -268,6 +268,6 @@ private: std::unordered_map<std::string, std::string> m_PatternMap; }; -} // namespace zen - void http_forcelink(); // internal + +} // namespace zen diff --git a/zenhttp/include/zenhttp/zenhttp.h b/zenhttp/include/zenhttp/zenhttp.h index c6ec92e7c..586fc98b4 100644 --- a/zenhttp/include/zenhttp/zenhttp.h +++ b/zenhttp/include/zenhttp/zenhttp.h @@ -5,3 +5,9 @@ #include <zencore/zencore.h> #define ZENHTTP_API // Placeholder to allow DLL configs in the future + +namespace zen { + + ZENHTTP_API void zenhttp_forcelinktests(); + +} diff --git a/zenhttp/zenhttp.cpp b/zenhttp/zenhttp.cpp new file mode 100644 index 000000000..148cf4499 --- /dev/null +++ b/zenhttp/zenhttp.cpp @@ -0,0 +1,13 @@ +#include <zenhttp/zenhttp.h> + +#include <zenhttp/httpserver.h> + +namespace zen { + +void +zenhttp_forcelinktests() +{ + http_forcelink(); +} + +}
\ No newline at end of file diff --git a/zenhttp/zenhttp.vcxproj b/zenhttp/zenhttp.vcxproj index 3536d1929..eca9898d3 100644 --- a/zenhttp/zenhttp.vcxproj +++ b/zenhttp/zenhttp.vcxproj @@ -100,6 +100,7 @@ <ClCompile Include="httpsys.cpp" /> <ClCompile Include="httpuws.cpp" /> <ClCompile Include="iothreadpool.cpp" /> + <ClCompile Include="zenhttp.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="httpnull.h" /> diff --git a/zenhttp/zenhttp.vcxproj.filters b/zenhttp/zenhttp.vcxproj.filters index da292c18f..17f71bed1 100644 --- a/zenhttp/zenhttp.vcxproj.filters +++ b/zenhttp/zenhttp.vcxproj.filters @@ -8,6 +8,7 @@ <ClCompile Include="httpnull.cpp" /> <ClCompile Include="httpuws.cpp" /> <ClCompile Include="httpshared.cpp" /> + <ClCompile Include="zenhttp.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="include\zenhttp\httpclient.h" /> diff --git a/zenserver-test/zenserver-test.cpp b/zenserver-test/zenserver-test.cpp index df17cc353..213648319 100644 --- a/zenserver-test/zenserver-test.cpp +++ b/zenserver-test/zenserver-test.cpp @@ -14,6 +14,7 @@ #include <zencore/string.h> #include <zencore/thread.h> #include <zencore/timer.h> +#include <zenhttp/zenhttp.h> #include <zenhttp/httpclient.h> #include <zenserverprocess.h> @@ -658,6 +659,9 @@ main(int argc, char** argv) mi_version(); zencore_forcelinktests(); + zen::zenhttp_forcelinktests(); + + zen::logging::InitializeLogging(); spdlog::set_level(spdlog::level::debug); spdlog::set_formatter(std::make_unique<logging::full_formatter>("test", std::chrono::system_clock::now())); diff --git a/zenserver/compute/apply.cpp b/zenserver/compute/apply.cpp index 6eeb6cf70..7b76bb80b 100644 --- a/zenserver/compute/apply.cpp +++ b/zenserver/compute/apply.cpp @@ -114,7 +114,7 @@ BasicFunctionJob::Wait(uint32_t TimeoutMs) return true; } - throw std::exception("Failed wait on process handle"); + throw std::runtime_error("Failed wait on process handle"); } int @@ -647,6 +647,7 @@ CbPackage HttpFunctionService::ExecAction(const WorkerDesc& Worker, CbObject Action) { using namespace std::literals; + using namespace fmt::literals; std::filesystem::path SandboxPath = CreateNewSandbox(); @@ -667,7 +668,7 @@ HttpFunctionService::ExecAction(const WorkerDesc& Worker, CbObject Action) if (!DataBuffer) { - throw std::exception("Chunk missing" /* ADD CONTEXT */); + throw std::runtime_error("worker CAS chunk '{}' missing"_format(Hash)); } zen::WriteFile(FilePath, DataBuffer); @@ -693,7 +694,7 @@ HttpFunctionService::ExecAction(const WorkerDesc& Worker, CbObject Action) if (!DataBuffer) { - throw std::exception("Chunk missing" /* ADD CONTEXT */); + throw std::runtime_error("worker CAS chunk '{}' missing"_format(Hash)); } zen::WriteFile(FilePath, DataBuffer); @@ -712,7 +713,7 @@ HttpFunctionService::ExecAction(const WorkerDesc& Worker, CbObject Action) if (!DataBuffer) { - throw std::exception("Chunk missing" /* ADD CONTEXT */); + throw std::runtime_error("input CID chunk '{}' missing"_format(Cid)); } zen::WriteFile(FilePath, DataBuffer); diff --git a/zenserver/config.cpp b/zenserver/config.cpp index ae624b169..578a3a202 100644 --- a/zenserver/config.cpp +++ b/zenserver/config.cpp @@ -242,7 +242,7 @@ ParseServiceConfig(const std::filesystem::path& DataRoot, ZenServiceConfig& Serv { ZEN_ERROR("config script failure: {}", e.what()); - throw std::exception("fatal zen global config script ({}) failure: {}"_format(ConfigScript, e.what()).c_str()); + throw std::runtime_error("fatal zen global config script ({}) failure: {}"_format(ConfigScript, e.what()).c_str()); } ServiceConfig.MeshEnabled = lua["mesh"]["enable"].get_or(ServiceConfig.MeshEnabled); diff --git a/zenserver/diag/logging.cpp b/zenserver/diag/logging.cpp index 5782ce582..48eda7512 100644 --- a/zenserver/diag/logging.cpp +++ b/zenserver/diag/logging.cpp @@ -211,7 +211,7 @@ InitializeLogging(const ZenServerOptions& GlobalOptions) spdlog::init_thread_pool(QueueSize, ThreadCount); auto AsyncLogger = spdlog::create_async<spdlog::sinks::ansicolor_stdout_sink_mt>("main"); - spdlog::set_default_logger(AsyncLogger); + zen::logging::SetDefault(AsyncLogger); } // Sinks @@ -220,16 +220,16 @@ InitializeLogging(const ZenServerOptions& GlobalOptions) auto FileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(zen::WideToUtf8(LogPath.c_str()), /* truncate */ true); // Default - auto DefaultLogger = spdlog::default_logger(); - auto& Sinks = spdlog::default_logger()->sinks(); - Sinks.clear(); + auto& DefaultLogger = zen::logging::Default(); + auto& Sinks = DefaultLogger.sinks(); + + Sinks.clear(); Sinks.push_back(ConsoleSink); Sinks.push_back(FileSink); - DefaultLogger->set_level(LogLevel); - DefaultLogger->flush_on(spdlog::level::err); // Jupiter - only log HTTP traffic to file + auto JupiterLogger = std::make_shared<spdlog::logger>("jupiter", FileSink); spdlog::register_logger(JupiterLogger); JupiterLogger->set_level(LogLevel); @@ -238,7 +238,10 @@ InitializeLogging(const ZenServerOptions& GlobalOptions) spdlog::register_logger(ZenClientLogger); ZenClientLogger->set_level(LogLevel); + // Configure all registered loggers according to settings + spdlog::set_level(LogLevel); + spdlog::flush_on(spdlog::level::err); spdlog::set_formatter(std::make_unique<logging::full_formatter>(GlobalOptions.LogId, std::chrono::system_clock::now())); } diff --git a/zenserver/projectstore.cpp b/zenserver/projectstore.cpp index 79cd250dc..404484edf 100644 --- a/zenserver/projectstore.cpp +++ b/zenserver/projectstore.cpp @@ -142,14 +142,14 @@ struct ProjectStore::OplogStorage : public RefCounted } else { - throw std::exception("column family iteration failed for '{}': '{}'"_format(RocksdbPath, Status.getState()).c_str()); + throw std::runtime_error("column family iteration failed for '{}': '{}'"_format(RocksdbPath, Status.getState()).c_str()); } Status = rocksdb::DB::Open(Options, RocksdbPath, ColumnDescriptors, &m_RocksDbColumnHandles, &Db); if (!Status.ok()) { - throw std::exception("database open failed for '{}': '{}'"_format(RocksdbPath, Status.getState()).c_str()); + throw std::runtime_error("database open failed for '{}': '{}'"_format(RocksdbPath, Status.getState()).c_str()); } m_RocksDb.reset(Db); diff --git a/zenserver/testing/launch.cpp b/zenserver/testing/launch.cpp index 608b515e1..55695ac9c 100644 --- a/zenserver/testing/launch.cpp +++ b/zenserver/testing/launch.cpp @@ -105,7 +105,7 @@ BasicJob::Wait(uint32_t TimeoutMs) return true; } - throw std::exception("Failed wait on process handle"); + throw std::runtime_error("Failed wait on process handle"); } int diff --git a/zenserver/upstream/jupiter.cpp b/zenserver/upstream/jupiter.cpp index 29fee1d32..0af92da6d 100644 --- a/zenserver/upstream/jupiter.cpp +++ b/zenserver/upstream/jupiter.cpp @@ -268,7 +268,7 @@ CloudCacheClient::CloudCacheClient(const CloudCacheClientOptions& Options) { if (!Options.OAuthProvider.starts_with("http://"sv) && !Options.OAuthProvider.starts_with("https://"sv)) { - ZEN_WARN("bad provider specification: '{}' - must be fully qualified"_format(Options.OAuthProvider).c_str()); + ZEN_WARN("bad provider specification: '{}' - must be fully qualified", Options.OAuthProvider); m_IsValid = false; return; diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp index 931fe062e..3b56d8683 100644 --- a/zenserver/zenserver.cpp +++ b/zenserver/zenserver.cpp @@ -112,7 +112,7 @@ public: if (zen::NamedMutex::Exists(MutexName) || (m_ServerMutex.Create(MutexName) == false)) { - throw std::exception("Failed to create mutex '{}' - is another instance already running?"_format(MutexName).c_str()); + throw std::runtime_error("Failed to create mutex '{}' - is another instance already running?"_format(MutexName).c_str()); } // Ok so now we're configured, let's kick things off diff --git a/zenstore/caslog.cpp b/zenstore/caslog.cpp index 34860538a..70bcf4669 100644 --- a/zenstore/caslog.cpp +++ b/zenstore/caslog.cpp @@ -81,7 +81,7 @@ CasLogFile::Open(std::filesystem::path FileName, size_t RecordSize, bool IsCreat if ((0 != memcmp(Header.Magic, FileHeader::MagicSequence, sizeof Header.Magic)) || (Header.Checksum != Header.ComputeChecksum())) { // TODO: provide more context! - throw std::exception("Mangled log header"); + throw std::runtime_error("Mangled log header"); } ULONGLONG Sz; diff --git a/zenutil/zenserverprocess.cpp b/zenutil/zenserverprocess.cpp index 3d8f33559..00f5d4c0d 100644 --- a/zenutil/zenserverprocess.cpp +++ b/zenutil/zenserverprocess.cpp @@ -524,7 +524,7 @@ ZenServerInstance::AttachToRunningServer(int BasePort) if (!State.InitializeReadOnly()) { // TODO: return success/error code instead? - throw std::exception("No zen state found"); + throw std::runtime_error("No zen state found"); } const ZenServerState::ZenServerEntry* Entry = nullptr; @@ -541,7 +541,7 @@ ZenServerInstance::AttachToRunningServer(int BasePort) if (!Entry) { // TODO: return success/error code instead? - throw std::exception("No server found"); + throw std::runtime_error("No server found"); } m_Process.Initialize(Entry->Pid); |