diff --git a/CMakeLists.txt b/CMakeLists.txt index e463c4f..23479d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,4 +2,5 @@ cmake_minimum_required(VERSION 3.17) project(Project_1) set(CMAKE_CXX_STANDARD 17) + add_executable(Project_1 main.cpp modernize/sockets.cpp) \ No newline at end of file diff --git a/libraries/osyncstream.h b/libraries/osyncstream.h index 4547742..966403f 100755 --- a/libraries/osyncstream.h +++ b/libraries/osyncstream.h @@ -7,21 +7,22 @@ #include #include +template class osyncstream_locked final { std::unique_lock lock_; - std::ostream& stream_; + std::basic_ostream& stream_; public: - osyncstream_locked(std::recursive_mutex& mtx, std::ostream& stream) : lock_(mtx), stream_(stream) {} //construct and lock the mutex from osyncstream. + osyncstream_locked(std::recursive_mutex& mtx, std::basic_ostream& stream) : lock_(mtx), stream_(stream) {} //construct and lock the mutex from osyncstream. osyncstream_locked(const osyncstream_locked& o) = delete; /* A recursive mutex isn't great here (reference forwarding would be better except...only a recursive mutex can assure lock-before-release on ownership transfer */ - template - friend auto operator<<(osyncstream_locked&& os, const T& d) -> osyncstream_locked&& + template + friend auto operator<<(osyncstream_locked&& os, const J& d) -> osyncstream_locked&& { os.stream_ << d; return std::move(os); /* move semantics :( ... thanks Clang/GCC */ } - friend auto operator<<(osyncstream_locked&& os, std::ostream& (*func)(std::ostream&)) -> std::ostream& + friend auto operator<<(osyncstream_locked&& os, std::basic_ostream& (*func)(std::basic_ostream&)) -> std::basic_ostream& { return os.stream_ << func; } @@ -31,20 +32,21 @@ public: ~osyncstream_locked() = default; }; +template class osyncstream final { std::recursive_mutex mutex_{}; - std::ostream& stream_; + std::basic_ostream& stream_; public: - explicit osyncstream(std::ostream& stream) : stream_(stream) {} - template - friend auto operator<<(osyncstream& os, const T& d) -> osyncstream_locked + explicit osyncstream(std::basic_ostream& stream) : stream_(stream) {} + template + friend auto operator<<(osyncstream& os, const J& d) -> osyncstream_locked { std::unique_lock lock(os.mutex_); os.stream_ << d; - return osyncstream_locked { os.mutex_, os.stream_ }; + return osyncstream_locked { os.mutex_, os.stream_ }; } - friend auto operator<<(osyncstream& os, std::ostream& (*func)(std::ostream&)) -> osyncstream_locked + friend auto operator<<(osyncstream& os, std::basic_ostream& (*func)(std::basic_ostream&)) -> osyncstream_locked { std::unique_lock lock(os.mutex_); os.stream_ << func; @@ -54,11 +56,17 @@ public: struct streams { - static std::ostream& cout; - static std::ostream& cerr; + static std::basic_ostream& cout; + static std::basic_ostream& cerr; + static std::basic_ostream& wcout; + static std::basic_ostream& wcerr; }; -inline std::ostream& streams::cout = std::cout; -inline std::ostream& streams::cerr = std::cerr; +inline std::basic_ostream& streams::cout = std::cout; +inline std::basic_ostream& streams::cerr = std::cerr; +inline std::basic_ostream& streams::wcout = std::wcout; +inline std::basic_ostream& streams::wcerr = std::wcerr; [[maybe_unused]] inline osyncstream sscout(streams::cout); // NOLINT(cert-err58-cpp) -[[maybe_unused]] inline osyncstream sscerr(streams::cerr); // NOLINT(cert-err58-cpp) \ No newline at end of file +[[maybe_unused]] inline osyncstream sscerr(streams::cerr); // NOLINT(cert-err58-cpp) +[[maybe_unused]] inline osyncstream sswcout(streams::wcout); // NOLINT(cert-err58-cpp) +[[maybe_unused]] inline osyncstream sswcerr(streams::wcerr); // NOLINT(cert-err58-cpp) \ No newline at end of file diff --git a/libraries/terminal.h b/libraries/terminal.h index 2da37fb..8f5f1d3 100644 --- a/libraries/terminal.h +++ b/libraries/terminal.h @@ -1,18 +1,34 @@ #pragma once #include #include +#include -inline auto terminal_size() -{ - struct winsize result{}; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &result); - return std::make_tuple(result.ws_col, result.ws_row); -} -template -std::basic_ostream& hr(std::basic_ostream& os) +namespace term { - auto [width, height] = terminal_size(); - os << std::setfill('-') << std::setw(width) << "\n" << std::setfill(' ') << std::setw(0); - return os; -} + + inline auto use_unicode() + { + std::locale unicode( std::locale(), new std::codecvt_utf8_utf16 ); + std::cout.imbue(unicode); + std::wcout.imbue(unicode); + } + inline auto size() + { + struct winsize result{}; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &result); //POSIX + return std::make_tuple(result.ws_col, result.ws_row); + } + std::basic_ostream& hr(std::basic_ostream& os) + { + auto [width, height] = size(); + os << std::setfill('-') << std::setw(width) << "\n" << std::setfill(' ') << std::setw(0); + return os; + } + std::basic_ostream& hr(std::basic_ostream& os) + { + auto [width, height] = size(); + os << std::setfill(L'─') << std::setw(width) << "\n" << std::setfill(L' ') << std::setw(0); + return os; + } +} \ No newline at end of file diff --git a/main.cpp b/main.cpp index 4e31e6c..27d9688 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,3 @@ -#pragma clang diagnostic push -#pragma ide diagnostic ignored "EndlessLoop" #include "modernize/sockets.h" #include "libraries/user_input.h" #include "libraries/osyncstream.h" @@ -12,33 +10,34 @@ #include #include +#include +#include +#include + using json = nlohmann::json; auto onClientConnected(networked& client) { sscout << "Accepted Client on Server.\n"; - using namespace std::chrono_literals; auto start = std::chrono::high_resolution_clock::now(); - //std::this_thread::sleep_for(2000ms); - return true; } auto onClientMessaged(networked& client, std::string& message) { - //TODO vm_stat -> vmstat - std::string commands[6] = {"date", "uptime", "vm_stat", "netstat -ant", "who", "ps"}; + std::string commands[6] = {"date", "uptime", "vmstat", "netstat -ant", "who", "ps"}; auto badOperand = []() {sscout << "Invalid OPCode, Ignored.\n";}; try { int operation = std::stoi(message); - sscout << "OPCode is " << operation << ".\n"; + sscout << "Received OPCode " << operation << " from Client.\n"; if (math::is_between<0,7>(operation)) client.send_message(net::system(commands[operation-1])); else badOperand(); }catch(std::invalid_argument& invalid_number) { badOperand(); } client.disconnect(); + sscout << "Disconnected Client.\n"; return true; } @@ -50,7 +49,7 @@ auto get_ip_port(int mode) ipaddress = "0.0.0.0"; else ipaddress = get_input("Enter IP: ", "Invalid IP", ip_validator()); - port = get_input("Enter Port:"); + port = get_input("Enter Port: "); return std::make_tuple(mode == 1 ? "Server" : mode == 2 ? "Client" : "Unknown", ipaddress, port); } @@ -67,7 +66,7 @@ auto execute_as_client(std::string ipaddress, std::uint16_t port) metrics::job this_job{}; this_job.operation = operation; this_job.client_metrics.reserve(num_clients); - + auto failures = 0; for(int i = 0; i < num_clients; ++i) { threads.emplace_back(std::thread([&]() @@ -81,9 +80,9 @@ auto execute_as_client(std::string ipaddress, std::uint16_t port) auto client_num = this_job.client_metrics.size()+1; //UX sscout << client_num << math::numerical_suffix(client_num) << " client response\n" - << message - << "Round Trip Was " << elapsed.count() << " ms\n" - << hr; + << message + << "Round Trip Was " << elapsed.count() << " ms\n" + << term::hr; //Metrics metrics::client_message client_metric{}; client_metric.client_number = client_num; @@ -96,12 +95,16 @@ auto execute_as_client(std::string ipaddress, std::uint16_t port) { net_client.send_message(std::to_string(operation)); res.join(); + }else{ + ++failures; } })); } - sscout << "All clients connected.\n" << hr; + sscout << "Client setup complete.\n" << term::hr; for(auto&& thread : threads) thread.join(); + if (failures) + sscout << failures << " client(s) failed to connect."; metrics::job_metrics.emplace_back(this_job); sscout << "Finished!\n"; } @@ -110,15 +113,36 @@ auto execute_as_client(std::string ipaddress, std::uint16_t port) metrics.open ("metrics.json", std::ios::out | std::ios::trunc); //again, metrics data metrics << metrics_json; metrics.close(); + sscout << "Metrics Saved to metrics.json\n"; } +auto operator<<(std::basic_ostream& os, const std::string& str) -> std::basic_ostream& +{ + std::wstring_convert> converter; + std::wstring wide = converter.from_bytes(str); + os << wide; + return os; +} int main() { + term::use_unicode(); + sswcout + << L"┌───────────╖\n" + << L"│ Project 1 ║\n" + << L"╘═══════════╝\n"; + + sswcout + << L"┌────────────────────╖\n" + << L"│ Riley Strickland ║\n" + << L"│ Jacob Jerris ║\n" + << L"│ Jacqueline Shrader ║\n" + << L"╘════════════════════╝\n"; + net::prologue(); const auto mode = get_input("Select Mode\n\t1. Server\n\t2. Client\n>:", "Invalid Choice!", math::is_between<0, 3>); auto[prefix, ipaddress, port] = get_ip_port(mode); - sscout << prefix << " selected, ip/port is " << ipaddress << "/" << port << ".\n"; + sscout << prefix << " selected, ip/port is " << ipaddress << ":" << port << ".\n"; if (mode == 2) { execute_as_client(ipaddress, port); } else { @@ -128,6 +152,11 @@ int main() { net_server.listen(ipaddress, port).join(); } net::epilogue(); + + sswcout + << L"┌────────────────────╖\n" + << L"│ Thanks for using ║\n" + << L"╘════════════════════╝\n"; + return 0; -} -#pragma clang diagnostic pop \ No newline at end of file +} \ No newline at end of file