diff --git a/include/ylt/thirdparty/cinatra/coro_http_connection.hpp b/include/ylt/thirdparty/cinatra/coro_http_connection.hpp index 346aa3b95..b1b36180d 100644 --- a/include/ylt/thirdparty/cinatra/coro_http_connection.hpp +++ b/include/ylt/thirdparty/cinatra/coro_http_connection.hpp @@ -108,7 +108,7 @@ class coro_http_connection auto [ec, size] = co_await async_read_until(head_buf_, TWO_CRCF); if (ec) { if (ec != asio::error::eof) { - CINATRA_LOG_ERROR << "read http header error: " << ec.message(); + CINATRA_LOG_WARNING << "read http header error: " << ec.message(); } close(); break; diff --git a/include/ylt/thirdparty/cinatra/coro_http_server.hpp b/include/ylt/thirdparty/cinatra/coro_http_server.hpp index 6225325db..b2ceddf04 100644 --- a/include/ylt/thirdparty/cinatra/coro_http_server.hpp +++ b/include/ylt/thirdparty/cinatra/coro_http_server.hpp @@ -13,6 +13,7 @@ #include "cinatra/mime_types.hpp" #include "cinatra_log_wrapper.hpp" #include "coro_http_connection.hpp" +#include "ylt/coro_io/coro_file.hpp" #include "ylt/coro_io/coro_io.hpp" #include "ylt/coro_io/io_context_pool.hpp" diff --git a/include/ylt/thirdparty/frozen/bits/pmh.h b/include/ylt/thirdparty/frozen/bits/pmh.h index 801f25433..24b38a07f 100644 --- a/include/ylt/thirdparty/frozen/bits/pmh.h +++ b/include/ylt/thirdparty/frozen/bits/pmh.h @@ -138,7 +138,7 @@ struct seed_or_index { private: static constexpr value_type MINUS_ONE = - std::numeric_limits::max(); + (std::numeric_limits::max)(); static constexpr value_type HIGH_BIT = ~(MINUS_ONE >> 1); value_type value_ = 0; @@ -201,7 +201,7 @@ pmh_tables constexpr make_pmh_tables(const carray &items, carray G; // Default constructed to "index 0" // H becomes the second hash table in the resulting pmh function - constexpr std::size_t UNUSED = std::numeric_limits::max(); + constexpr std::size_t UNUSED = (std::numeric_limits::max)(); carray H; H.fill(UNUSED); diff --git a/include/ylt/thirdparty/frozen/random.h b/include/ylt/thirdparty/frozen/random.h index 8089ecd8e..cbdcdcbdc 100644 --- a/include/ylt/thirdparty/frozen/random.h +++ b/include/ylt/thirdparty/frozen/random.h @@ -66,11 +66,11 @@ class linear_congruential_engine { state_ = modulo(tmp, std::integral_constant()); return state_; } - constexpr void discard(unsigned long long n) { - while (n--) operator()(); - } - static constexpr result_type min() { return increment == 0u ? 1u : 0u; } - static constexpr result_type max() { return modulus - 1u; } + // constexpr void discard(unsigned long long n) { + // while (n--) operator()(); + // } + // static constexpr result_type min() { return increment == 0u ? 1u : 0u; } + // static constexpr result_type max() { return modulus - 1u; } friend constexpr bool operator==(linear_congruential_engine const &self, linear_congruential_engine const &other) { return self.state_ == other.state_; diff --git a/include/ylt/thirdparty/iguana/detail/fast_float.h b/include/ylt/thirdparty/iguana/detail/fast_float.h index 0c32c0743..ddc7f9e4a 100644 --- a/include/ylt/thirdparty/iguana/detail/fast_float.h +++ b/include/ylt/thirdparty/iguana/detail/fast_float.h @@ -2708,7 +2708,7 @@ fastfloat_really_inline void round(adjusted_mantissa& am, if (-am.power2 >= mantissa_shift) { // have a denormal float int32_t shift = -am.power2 + 1; - cb(am, std::min(shift, 64)); + cb(am, (std::min)(shift, 64)); // check for round-up: if rounding-nearest carried us to the hidden bit. am.power2 = (am.mantissa < (uint64_t(1) << binary_format::mantissa_explicit_bits())) diff --git a/src/coro_http/examples/CMakeLists.txt b/src/coro_http/examples/CMakeLists.txt index 7d87880f2..81029f1f2 100644 --- a/src/coro_http/examples/CMakeLists.txt +++ b/src/coro_http/examples/CMakeLists.txt @@ -29,8 +29,10 @@ endif() add_executable(coro_http_example example.cpp) add_executable(coro_http_channel channel.cpp) +add_executable(coro_chat_room chat_room.cpp) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows") # mingw-w64 target_link_libraries(coro_http_example wsock32 ws2_32) target_link_libraries(coro_http_channel wsock32 ws2_32) + target_link_libraries(coro_chat_room wsock32 ws2_32) endif() \ No newline at end of file diff --git a/src/coro_http/examples/chat_room.cpp b/src/coro_http/examples/chat_room.cpp new file mode 100644 index 000000000..bbb84a615 --- /dev/null +++ b/src/coro_http/examples/chat_room.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "async_simple/coro/Lazy.h" +#include "ylt/coro_http/coro_http_server.hpp" +#include "ylt/struct_json/json_reader.h" +#include "ylt/struct_json/json_writer.h" + +using namespace coro_http; + +struct login_info_t { + std::string_view type; + std::string_view content; + std::vector user_list; +}; +REFLECTION(login_info_t, type, content, user_list); + +using logout_info_t = login_info_t; + +struct user_info_t { + std::string_view type; + std::string_view from; + std::string_view content; +}; +REFLECTION(user_info_t, type, from, content); + +struct message_t { + std::string type; + std::string_view content; +}; +REFLECTION(message_t, type, content); + +async_simple::coro::Lazy broadcast(auto &conn_map, + std::string &resp_str) { + for (auto &[conn_ptr, user_name] : conn_map) { + auto conn = (coro_http_connection *)conn_ptr; + auto ec = co_await conn->write_websocket(resp_str); + if (ec) { + std::cout << ec.message() << "\n"; + continue; + } + } + resp_str.clear(); +} + +int main() { + coro_http::coro_http_server server(1, 9001); + std::mutex mtx; + std::unordered_map conn_map; + server.set_http_handler( + "/", + [&](coro_http_request &req, + coro_http_response &resp) -> async_simple::coro::Lazy { + websocket_result result{}; + + std::unordered_map map; + std::string resp_str; + while (true) { + result = co_await req.get_conn()->read_websocket(); + if (result.ec) { + break; + } + + message_t msg{}; + if (result.type == ws_frame_type::WS_CLOSE_FRAME) { + std::cout << "close frame\n"; + msg.type = "logout"; + } + else { + struct_json::from_json(msg, result.data); + } + + if (msg.type == "user") { + std::string from; + { + std::scoped_lock lock(mtx); + from = conn_map.at((intptr_t)req.get_conn()); + map = conn_map; + } + + user_info_t info{msg.type, from, msg.content}; + struct_json::to_json(info, resp_str); + } + else if (msg.type == "login" || msg.type == "logout") { + std::string user_name; + + { + std::scoped_lock lock(mtx); + if (msg.type == "login") { + user_name = std::string{msg.content}; + conn_map.emplace((intptr_t)req.get_conn(), user_name); + } + else { + user_name = conn_map.at((intptr_t)req.get_conn()); + conn_map.erase((intptr_t)req.get_conn()); + } + map = conn_map; + } + + if (!map.empty()) { + std::vector user_list; + std::transform(map.begin(), map.end(), + std::back_inserter(user_list), [](auto &kv) { + return kv.second; + }); + logout_info_t info{msg.type, user_name, std::move(user_list)}; + struct_json::to_json(info, resp_str); + } + } + + std::cout << result.data << "\n"; + + co_await broadcast(map, resp_str); + if (msg.type == "logout") { + break; + } + } + }); + server.sync_start(); +} \ No newline at end of file diff --git a/src/coro_http/examples/client.html b/src/coro_http/examples/client.html new file mode 100644 index 000000000..d0736ca77 --- /dev/null +++ b/src/coro_http/examples/client.html @@ -0,0 +1,156 @@ + + + + + + + + + + +
+

基于C++20 协程的websocket聊天室

+
+
+

当前在线:0

+
+ +
+
+
+
+
+
+
+ +
+ + + + + \ No newline at end of file