#pragma once #include "tl/expected.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace rublon { namespace memory { struct holder { static inline std::pmr::memory_resource * _mr = std::pmr::get_default_resource(); }; inline void set_default_resource(std::pmr::memory_resource * memory_resource) { holder{}._mr = memory_resource; } inline std::pmr::memory_resource * default_resource() { return holder{}._mr; } template < std::size_t N > class MonotonicStackResource : public std::pmr::monotonic_buffer_resource { char _buffer[N]; public: MonotonicStackResource() : std::pmr::monotonic_buffer_resource{_buffer, N, std::pmr::null_memory_resource()} {} }; template < std::size_t N > class UnsynchronizedStackResource : public std::pmr::unsynchronized_pool_resource { MonotonicStackResource< N > _upstream; public: UnsynchronizedStackResource() : std::pmr::unsynchronized_pool_resource{&_upstream} {} }; class MonotonicHeapResourceBase { public: std::pmr::memory_resource * _upstream{}; std::size_t _size{}; void * _buffer{nullptr}; MonotonicHeapResourceBase(std::size_t size) : _upstream{default_resource()}, _size{size}, _buffer{_upstream->allocate(size)} {} ~MonotonicHeapResourceBase() { if(_buffer) _upstream->deallocate(_buffer, _size); } }; template < std::size_t N > class MonotonicHeapResource : MonotonicHeapResourceBase, public std::pmr::monotonic_buffer_resource { public: MonotonicHeapResource() : MonotonicHeapResourceBase{N}, std::pmr::monotonic_buffer_resource{this->_buffer, this->_size, default_resource()} {} }; template < std::size_t N > class StrictMonotonicHeapResource : MonotonicHeapResourceBase, public std::pmr::monotonic_buffer_resource { public: StrictMonotonicHeapResource() : MonotonicHeapResourceBase{N}, std::pmr::monotonic_buffer_resource{this->_buffer, this->_size, std::pmr::null_memory_resource()} {} }; using StrictMonotonic_1k_HeapResource = StrictMonotonicHeapResource< 1 * 1024 >; using StrictMonotonic_2k_HeapResource = StrictMonotonicHeapResource< 2 * 1024 >; using StrictMonotonic_4k_HeapResource = StrictMonotonicHeapResource< 4 * 1024 >; using StrictMonotonic_8k_HeapResource = StrictMonotonicHeapResource< 8 * 1024 >; using Monotonic_1k_HeapResource = MonotonicHeapResource< 1 * 1024 >; using Monotonic_2k_HeapResource = MonotonicHeapResource< 2 * 1024 >; using Monotonic_4k_HeapResource = MonotonicHeapResource< 4 * 1024 >; using Monotonic_8k_HeapResource = MonotonicHeapResource< 8 * 1024 >; } // namespace memory enum class LogLevel { Debug, Info, Warning, Error }; inline auto dateStr() { std::array< char, 32 > date; time_t now; time(&now); strftime(date.data(), date.size(), "%FT%TZ", gmtime(&now)); return date; } constexpr const char * LogLevelNames[]{"Debug", "Info", "Warning", "Error"}; constexpr LogLevel g_level = LogLevel::Debug; constexpr bool syncLogFile = true; namespace details { static void doLog(LogLevel level, const char * line) noexcept { constexpr auto file_name = "/var/log/rublon-ssh.log"; auto fp = std::unique_ptr< FILE, int (*)(FILE *) >(fopen(file_name, "a"), fclose); if(fp) { fprintf(fp.get(), "%s [%s] %s\n", dateStr().data(), LogLevelNames[( int ) level], line); if(syncLogFile) sync(); } } } // namespace details inline void log(LogLevel level, const char * line) noexcept { if(level < g_level) return; details::doLog(level, line); } template < typename... Ti > void log(LogLevel level, const char * fmt, Ti &&... ti) noexcept { if(level < g_level) return; std::array< char, 1000 > line; sprintf(line.data(), fmt, std::forward< Ti >(ti)...); details::doLog(level, line.data()); } template < typename T > class NonOwningPtr { T * object; public: constexpr NonOwningPtr(T * obj) : object{obj} {} constexpr T * get() noexcept { assert(object != nullptr); return object; } constexpr const T * get() const noexcept { assert(object != nullptr); return object; } constexpr operator const T *() const noexcept { return get(); } constexpr operator T *() noexcept { return get(); } constexpr T * operator->() { return get(); } constexpr const T * operator->() const { return get(); } }; namespace details { enum class ConversionError { OutOfRange, NotANumber }; inline tl::expected< std::uint32_t, ConversionError > to_uint32(std::string_view userinput) noexcept { try { return std::stoi(userinput.data()); } catch(const std::invalid_argument & e) { return tl::make_unexpected(ConversionError::NotANumber); } catch(const std::out_of_range & e) { return tl::make_unexpected(ConversionError::OutOfRange); } } inline bool to_bool(std::string_view value) { /// TODO change to global allocator auto * buf = ( char * ) alloca(value.size() + 1); buf[value.size()] = '\0'; auto asciitolower = [](char in) { return in - ((in <= 'Z' && in >= 'A') ? ('Z' - 'z') : 0); }; std::transform(value.cbegin(), value.cend(), buf, asciitolower); return strcmp(buf, "true") == 0; } static inline std::string_view ltrim(std::string_view s) { while(s.length() && std::isspace(*s.begin())) s.remove_prefix(1); return s; } static inline std::string_view rtrim(std::string_view s) { while(s.length() && std::isspace(*s.rbegin())) s.remove_suffix(1); return s; } static inline std::string_view trim(std::string_view s) { return ltrim(rtrim(s)); } template < typename Headers > inline void headers(std::string_view data, Headers & headers) { memory::StrictMonotonic_4k_HeapResource stackResource; std::pmr::string tmp{&stackResource}; std::istringstream resp{}; resp.rdbuf()->pubsetbuf(const_cast< char * >(data.data()), data.size()); while(std::getline(resp, tmp) && !(trim(tmp).empty())) { auto line = std::string_view(tmp); auto index = tmp.find(':', 0); if(index != std::string::npos) { headers.insert({// typename Headers::key_type{trim(line.substr(0, index)), headers.get_allocator()}, typename Headers::mapped_type{trim(line.substr(index + 1)), headers.get_allocator()}}); } } } } // namespace details } // namespace rublon