diff --git a/deps/ox/src/ox/CMakeLists.txt b/deps/ox/src/ox/CMakeLists.txt index 743d0426..ecf291c4 100644 --- a/deps/ox/src/ox/CMakeLists.txt +++ b/deps/ox/src/ox/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(clargs) add_subdirectory(claw) add_subdirectory(event) add_subdirectory(fs) +add_subdirectory(logconn) add_subdirectory(mc) add_subdirectory(model) add_subdirectory(preloader) diff --git a/deps/ox/src/ox/logconn/CMakeLists.txt b/deps/ox/src/ox/logconn/CMakeLists.txt new file mode 100644 index 00000000..df3db221 --- /dev/null +++ b/deps/ox/src/ox/logconn/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.10) + +add_library( + OxLogConn + logconn.cpp +) + +set_property( + TARGET + OxLogConn + PROPERTY + POSITION_INDEPENDENT_CODE ON +) + +target_link_libraries( + OxLogConn PUBLIC + OxStd + OxMetalClaw +) + +install( + FILES + circularbuff.hpp + logconn.hpp + DESTINATION + include/ox/logconn +) + +install( + TARGETS + OxLogConn + LIBRARY DESTINATION lib/ox + ARCHIVE DESTINATION lib/ox +) diff --git a/deps/ox/src/ox/logconn/circularbuff.hpp b/deps/ox/src/ox/logconn/circularbuff.hpp new file mode 100644 index 00000000..69a2c32f --- /dev/null +++ b/deps/ox/src/ox/logconn/circularbuff.hpp @@ -0,0 +1,99 @@ +/* + * Copyright 2015 - 2022 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include + +namespace ox::detail { + +class CirculerBuffer { + private: + std::size_t m_readPt = 0; + std::size_t m_writePt = 0; + ox::Buffer m_buff = ox::Buffer(ox::units::MB); + + private: + [[nodiscard]] + constexpr auto avail() const noexcept { + if (m_writePt >= m_readPt) { + return m_buff.size() - (m_writePt - m_readPt); + } else { + return (m_buff.size() - m_writePt) - (m_buff.size() - m_readPt); + } + } + + public: + constexpr ox::Error put(char v) noexcept { + return write(&v, 1); + if (1 > avail()) { + return OxError(1, "Insufficient space in buffer"); + } + m_buff[m_writePt] = v; + ++m_writePt; + return {}; + } + + constexpr ox::Error write(const char *buff, std::size_t sz) noexcept { + if (sz > avail()) { + return OxError(1, "Insufficient space in buffer"); + } + // write seg 1 + const auto seg1Sz = ox::min(sz, m_buff.size() - m_writePt); + ox_memcpy(&m_buff[m_writePt], &buff[0], seg1Sz); + m_writePt += sz; + if (seg1Sz != sz) { + m_writePt -= m_buff.size(); + // write seg 2 + const auto seg2Sz = sz - seg1Sz; + ox_memcpy(&m_buff[0], &buff[seg1Sz], seg2Sz); + oxAssert(m_buff[0] == buff[seg1Sz], "break"); + } + return {}; + } + + constexpr ox::Error seekp(std::size_t bytesFwd) noexcept { + if (bytesFwd > avail()) { + return OxError(1, "Insufficient space in buffer to seek that far ahead"); + } + m_writePt += bytesFwd; + if (m_writePt > m_buff.size()) { + m_writePt -= m_buff.size(); + } + return {}; + } + + constexpr ox::Error seekp(int, ios_base::seekdir) { + return OxError(1, "Unimplemented"); + } + + [[nodiscard]] + constexpr std::size_t tellp() const noexcept { + return m_buff.size() - avail(); + } + + [[nodiscard]] + constexpr std::size_t read(char *out, std::size_t outSize) noexcept { + const auto bytesRead = ox::min(outSize, m_buff.size() - avail()); + // read seg 1 + const auto seg1Sz = ox::min(bytesRead, m_buff.size() - m_readPt); + ox_memcpy(&out[0], &m_buff[m_readPt], seg1Sz); + m_readPt += bytesRead; + if (seg1Sz != bytesRead) { + m_readPt -= m_buff.size(); + // read seg 2 + const auto seg2Sz = bytesRead - seg1Sz; + ox_memcpy(&out[seg1Sz], &m_buff[0], seg2Sz); + } + return bytesRead; + } +}; + +} diff --git a/deps/ox/src/ox/logconn/logconn.cpp b/deps/ox/src/ox/logconn/logconn.cpp new file mode 100644 index 00000000..0ff86b0d --- /dev/null +++ b/deps/ox/src/ox/logconn/logconn.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2015 - 2022 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifdef OX_USE_STDLIB +#include +#include +#include +#include +#include +#include + +#include + +#include "logconn.hpp" + +namespace ox { + +using namespace trace; + +LoggerConn::LoggerConn() noexcept: m_netThread([this]{this->msgSend();}) { +} + +LoggerConn::~LoggerConn() noexcept { + m_running = false; + m_waitCond.notify_one(); + m_netThread.join(); + if (m_socket) { + close(m_socket); + } +} + +ox::Error LoggerConn::initConn(const char *appName) noexcept { + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = htons(5590); + m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + oxReturnError(OxError(connect(m_socket, reinterpret_cast(&addr), sizeof(addr)))); + return sendInit({.appName = appName}); +} + +ox::Error LoggerConn::send(const char *buff, std::size_t len) const noexcept { + std::size_t totalSent = 0; + while (totalSent < len) { + //std::fprintf(stdout, "Sending %lu/%lu bytes on socket %d\n", len, totalSent, m_socket); + const auto sent = ::send(m_socket, buff, len, 0); + if (sent < 0) { + std::fprintf(stderr, "Could not send msg\n"); + return OxError(1, "Could not send msg"); + } + totalSent += static_cast(sent); + } + return {}; +} + +ox::Error LoggerConn::send(const TraceMsg &msg) noexcept { + return send(MsgId::TraceEvent, msg); +} + +ox::Error LoggerConn::sendInit(const InitTraceMsg &msg) noexcept { + return send(MsgId::Init, msg); +} + +void LoggerConn::msgSend() noexcept { + while (true) { + std::unique_lock lk(m_waitMut); + m_waitCond.wait(lk); + if (!m_running) { + break; + } + std::lock_guard buffLk(m_buffMut); + while (true) { + ox::Array tmp; + const auto read = m_buff.read(tmp.data(), tmp.size()); + if (!read) { + break; + } + //std::printf("LoggerConn: sending %lu bytes\n", read); + oxIgnoreError(send(tmp.data(), read)); + } + } +} + +} +#endif diff --git a/deps/ox/src/ox/logconn/logconn.hpp b/deps/ox/src/ox/logconn/logconn.hpp new file mode 100644 index 00000000..d7723b42 --- /dev/null +++ b/deps/ox/src/ox/logconn/logconn.hpp @@ -0,0 +1,78 @@ +/* + * Copyright 2015 - 2022 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#ifdef OX_USE_STDLIB +#include +#include +#include +#endif + +#include +#include + +#include "circularbuff.hpp" + +namespace ox { + +#ifdef OX_USE_STDLIB +class LoggerConn: public trace::Logger { + private: + int m_socket = 0; + detail::CirculerBuffer m_buff; + std::thread m_netThread; + std::condition_variable m_waitCond; + std::mutex m_waitMut; + std::mutex m_buffMut; + bool m_running = true; + public: + LoggerConn() noexcept; + LoggerConn(const LoggerConn&) noexcept = delete; + ~LoggerConn() noexcept override; + LoggerConn &operator=(const LoggerConn&) noexcept = delete; + ox::Error send(const trace::TraceMsg&) noexcept final; + ox::Error sendInit(const trace::InitTraceMsg&) noexcept final; + ox::Error initConn(const char *appName = "") noexcept; + ox::Error send(const char *buff, std::size_t len) const noexcept; + private: + void msgSend() noexcept; + ox::Error send(trace::MsgId msgId, const auto &msg) noexcept { + ox::Array buff; + std::size_t sz = 0; + oxReturnError(ox::writeMC(&buff[0], buff.size(), &msg, &sz)); + //std::printf("sz: %lu\n", sz); + oxRequire(szBuff, serialize(static_cast(sz))); + std::unique_lock buffLk(m_buffMut); + oxReturnError(m_buff.put(static_cast(msgId))); + oxReturnError(m_buff.write(szBuff.data(), szBuff.size())); + oxReturnError(m_buff.write(buff.data(), sz)); + buffLk.unlock(); + m_waitCond.notify_one(); + return {}; + } + +}; + +#else + +class LoggerConn: public trace::Logger { + private: + public: + constexpr LoggerConn() noexcept = default; + LoggerConn(const LoggerConn&) noexcept = delete; + constexpr ~LoggerConn() noexcept override = default; + LoggerConn &operator=(const LoggerConn&) noexcept = delete; + ox::Error send(const trace::TraceMsg&) noexcept final { return {}; } + static ox::Error initConn() noexcept { return {}; } + static ox::Error send(const char*, std::size_t) noexcept { return {}; } +}; +#endif + +} + diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index 6f005e4a..baa0314f 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -41,7 +41,7 @@ class MetalClawWriter { public: constexpr MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept; - constexpr ~MetalClawWriter() noexcept; + constexpr ~MetalClawWriter() noexcept = default; constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; @@ -159,12 +159,6 @@ constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, i m_buff(buff) { } -constexpr MetalClawWriter::~MetalClawWriter() noexcept { - if (m_field != m_fields) { - oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given"; - } -} - constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } diff --git a/deps/ox/src/ox/model/CMakeLists.txt b/deps/ox/src/ox/model/CMakeLists.txt index 79fbfada..39e2e5cc 100644 --- a/deps/ox/src/ox/model/CMakeLists.txt +++ b/deps/ox/src/ox/model/CMakeLists.txt @@ -46,4 +46,4 @@ install(TARGETS OxModel if(OX_RUN_TESTS) add_subdirectory(test) -endif() \ No newline at end of file +endif() diff --git a/deps/ox/src/ox/model/def.hpp b/deps/ox/src/ox/model/def.hpp index e2b20125..253df49c 100644 --- a/deps/ox/src/ox/model/def.hpp +++ b/deps/ox/src/ox/model/def.hpp @@ -10,7 +10,7 @@ #include -#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *o) noexcept { io->template setTypeInfo(); +#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith auto *o) noexcept { io->template setTypeInfo(); #define oxModelEnd() return OxError(0); } #define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName)); #define oxModelFieldRename(serFieldName, objFieldName) oxReturnError(io->field(#serFieldName, &o->objFieldName)); diff --git a/deps/ox/src/ox/model/modelvalue.hpp b/deps/ox/src/ox/model/modelvalue.hpp index 3819ca6c..dd88bb64 100644 --- a/deps/ox/src/ox/model/modelvalue.hpp +++ b/deps/ox/src/ox/model/modelvalue.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/deps/ox/src/ox/std/array.hpp b/deps/ox/src/ox/std/array.hpp index 61f0eda4..dd49009f 100644 --- a/deps/ox/src/ox/std/array.hpp +++ b/deps/ox/src/ox/std/array.hpp @@ -133,7 +133,7 @@ class Array { }; private: - T m_items[ArraySize]; + T m_items[ArraySize]{}; public: constexpr Array() noexcept = default; diff --git a/deps/ox/src/ox/std/fmt.hpp b/deps/ox/src/ox/std/fmt.hpp index 6019adb3..3bc60fb1 100644 --- a/deps/ox/src/ox/std/fmt.hpp +++ b/deps/ox/src/ox/std/fmt.hpp @@ -62,7 +62,7 @@ StringView toStringView(const std::string &s) noexcept { #if __has_include() template inline StringView toStringView(const QString &s) noexcept { - return s.toUtf8(); + return s.toUtf8().data(); } #endif diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp index c697f8b3..664147ac 100644 --- a/deps/ox/src/ox/std/string.hpp +++ b/deps/ox/src/ox/std/string.hpp @@ -304,8 +304,8 @@ constexpr BasicString &BasicString::operat template constexpr BasicString &BasicString::operator=(char c) noexcept { - char str[] = {c, 0}; - set(str); + ox::Array str{c, 0}; + set(str.data()); return *this; } @@ -317,23 +317,25 @@ constexpr BasicString &BasicString::operat template constexpr BasicString &BasicString::operator=(int64_t i) noexcept { - char str[65] = {}; - ox_itoa(i, str); - set(str); + ox::Array str{}; + ox_itoa(i, str.data()); + set(str.data()); return *this; } template constexpr BasicString &BasicString::operator=(uint64_t i) noexcept { - char str[65] = {}; - ox_itoa(i, str); - set(str); + ox::Array str{}; + ox_itoa(i, str.data()); + set(str.data()); return *this; } template constexpr BasicString &BasicString::operator=(const BasicString &src) noexcept { - set(src); + if (this != &src) { + set(src); + } return *this; } diff --git a/deps/ox/src/ox/std/stringview.hpp b/deps/ox/src/ox/std/stringview.hpp index 67972216..e1a65559 100644 --- a/deps/ox/src/ox/std/stringview.hpp +++ b/deps/ox/src/ox/std/stringview.hpp @@ -43,6 +43,7 @@ class StringView { m_max = max; } + [[nodiscard]] constexpr auto offset() const noexcept { return m_offset; } @@ -220,6 +221,7 @@ class StringView { return m_str[m_len - 1]; } + [[nodiscard]] constexpr auto substr(std::size_t pos) const noexcept { return StringView(m_str + pos, m_len - pos); } @@ -228,11 +230,7 @@ class StringView { return m_str[i]; } - constexpr auto operator=(const StringView &other) noexcept { - m_str = other.m_str; - m_len = other.m_len; - return *this; - } + constexpr ox::StringView &operator=(const StringView &other) noexcept = default; constexpr auto operator==(const StringView &other) const noexcept { if (other.len() != len()) { diff --git a/deps/ox/src/ox/std/trace.cpp b/deps/ox/src/ox/std/trace.cpp index f31cf91c..e9910217 100644 --- a/deps/ox/src/ox/std/trace.cpp +++ b/deps/ox/src/ox/std/trace.cpp @@ -14,4 +14,30 @@ void init() { oxTraceInitHook(); } +void init(Logger *logger) { + oxTraceInitHook(); + setLogger(logger); +} + +class NullLogger: public Logger { + public: + ox::Error send(const TraceMsg&) noexcept final { + return {}; + } + ox::Error sendInit(const InitTraceMsg&) noexcept final { + return {}; + } +}; + +static NullLogger defaultLogger; +static Logger *logger = &defaultLogger; + +void setLogger(Logger *logger) noexcept { + trace::logger = logger; +} + +void send(const TraceMsg &msg) noexcept { + oxIgnoreError(logger->send(msg)); +} + } diff --git a/deps/ox/src/ox/std/trace.hpp b/deps/ox/src/ox/std/trace.hpp index 6504ee33..98c370f8 100644 --- a/deps/ox/src/ox/std/trace.hpp +++ b/deps/ox/src/ox/std/trace.hpp @@ -30,9 +30,35 @@ void oxTraceHook(const char *file, int line, const char *ch, const char *msg); namespace ox::trace { +enum class MsgId: char { + Init = 2, + TraceEvent = 1, + Json = '{', +}; + +struct TraceMsgRcv { + static constexpr auto TypeName = "net.drinkingtea.ox.trace.TraceMsg"; + static constexpr auto TypeVersion = 1; + BasicString<50> file = ""; + int line = 0; + uint64_t time = 0; + BasicString<50> ch = ""; + BasicString<100> msg; +}; + +template +constexpr Error model(T *io, ox::CommonPtrWith auto *obj) noexcept { + io->template setTypeInfo(); + oxReturnError(io->field("file", &obj->file)); + oxReturnError(io->field("line", &obj->line)); + oxReturnError(io->field("time", &obj->time)); + oxReturnError(io->field("ch", &obj->ch)); + oxReturnError(io->field("msg", &obj->msg)); + return {}; +} + struct TraceMsg { static constexpr auto TypeName = "net.drinkingtea.ox.trace.TraceMsg"; - static constexpr auto Fields = 5; static constexpr auto TypeVersion = 1; const char *file = ""; int line = 0; @@ -42,16 +68,58 @@ struct TraceMsg { }; template -constexpr Error model(T *io, TraceMsg *obj) { +constexpr Error model(T *io, ox::CommonPtrWith auto *obj) noexcept { io->template setTypeInfo(); - oxReturnError(io->field("ch", &obj->ch)); - oxReturnError(io->field("file", &obj->file)); + oxReturnError(io->fieldCString("file", &obj->file)); oxReturnError(io->field("line", &obj->line)); oxReturnError(io->field("time", &obj->time)); + oxReturnError(io->fieldCString("ch", &obj->ch)); oxReturnError(io->field("msg", &obj->msg)); - return OxError(0); + return {}; } + +struct InitTraceMsgRcv { + static constexpr auto TypeName = "net.drinkingtea.ox.trace.InitTraceMsg"; + static constexpr auto TypeVersion = 1; + ox::String appName; +}; + +template +constexpr Error model(T *io, ox::CommonPtrWith auto *obj) noexcept { + io->template setTypeInfo(); + oxReturnError(io->field("appName", &obj->appName)); + return {}; +} + + +struct InitTraceMsg { + static constexpr auto TypeName = "net.drinkingtea.ox.trace.InitTraceMsg"; + static constexpr auto TypeVersion = 1; + const char *appName = ""; +}; + +template +constexpr Error model(T *io, ox::CommonPtrWith auto *obj) noexcept { + io->template setTypeInfo(); + oxReturnError(io->fieldCString("appName", &obj->appName)); + return {}; +} + +class Logger { + public: + constexpr virtual ~Logger() noexcept = default; + virtual ox::Error send(const TraceMsg&) noexcept = 0; + virtual ox::Error sendInit(const InitTraceMsg&) noexcept = 0; +}; + +/** + * @param logger pointer to the new logger, does NOT take ownership + */ +void setLogger(Logger *logger) noexcept; + +void send(const TraceMsg &msg) noexcept; + class OutStream { protected: @@ -109,6 +177,7 @@ class OutStream { inline ~OutStream() noexcept { oxTraceHook(m_msg.file, m_msg.line, m_msg.ch, m_msg.msg.c_str()); + send(m_msg); } constexpr OutStream &operator<<(Integer_c auto v) noexcept; @@ -238,5 +307,6 @@ inline void logError(const char *file, int line, const Error &err) noexcept { } void init(); +void init(Logger *logger); } diff --git a/deps/ox/src/ox/std/tracehook.cpp b/deps/ox/src/ox/std/tracehook.cpp index f238845c..e6bd63ea 100644 --- a/deps/ox/src/ox/std/tracehook.cpp +++ b/deps/ox/src/ox/std/tracehook.cpp @@ -72,13 +72,17 @@ void oxTraceHook([[maybe_unused]] const char *file, [[maybe_unused]] int line, std::cout << " " << file << ':' << line << "\n"; } else if (ox_strcmp(ch, "debug") == 0 || ox_strcmp(ch, "info") == 0) { printf("%s\n", msg); + fflush(stdout); } else if (ox_strcmp(ch, "stdout") == 0) { printf("%s", msg); + fflush(stdout); } else if (ox_strcmp(ch, "stderr") == 0) { printf("%s", msg); + fflush(stdout); } else if (ox_strcmp(ch, "error") == 0) { //std::cerr << "\033[31;1;1mERROR:\033[0m (" << file << ':' << line << "): " << msg << '\n'; fprintf(stderr, "\033[31;1;1mERROR:\033[0m (%s:%d): %s\n", file, line, msg); + fflush(stderr); } #else if (ox_strcmp(ch, "info") == 0) { diff --git a/deps/ox/src/ox/std/types.hpp b/deps/ox/src/ox/std/types.hpp index 6c66b1d3..6f4dc8b5 100644 --- a/deps/ox/src/ox/std/types.hpp +++ b/deps/ox/src/ox/std/types.hpp @@ -15,6 +15,8 @@ using size_t = decltype(alignof(int)); } +using size_t = decltype(alignof(int)); + #if __has_include() #include @@ -160,4 +162,4 @@ static_assert(sizeof(uint8_t) == 1, "uint8_t is wrong size"); static_assert(sizeof(uint16_t) == 2, "uint16_t is wrong size"); static_assert(sizeof(uint32_t) == 4, "uint32_t is wrong size"); static_assert(sizeof(uint64_t) == 8, "uint64_t is wrong size"); -static_assert(sizeof(uintptr_t) == sizeof(void*), "uintptr_t is wrong size"); \ No newline at end of file +static_assert(sizeof(uintptr_t) == sizeof(void*), "uintptr_t is wrong size");