Skip to content

Commit

Permalink
[coro_http][demo]add chat room demo (#528)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored Dec 15, 2023
1 parent 8229d72 commit 9ae8f00
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 9 deletions.
2 changes: 1 addition & 1 deletion include/ylt/thirdparty/cinatra/coro_http_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions include/ylt/thirdparty/cinatra/coro_http_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
4 changes: 2 additions & 2 deletions include/ylt/thirdparty/frozen/bits/pmh.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ struct seed_or_index {

private:
static constexpr value_type MINUS_ONE =
std::numeric_limits<value_type>::max();
(std::numeric_limits<value_type>::max)();
static constexpr value_type HIGH_BIT = ~(MINUS_ONE >> 1);

value_type value_ = 0;
Expand Down Expand Up @@ -201,7 +201,7 @@ pmh_tables<M, Hash> constexpr make_pmh_tables(const carray<Item, N> &items,
carray<seed_or_index, M> 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<std::size_t>::max();
constexpr std::size_t UNUSED = (std::numeric_limits<std::size_t>::max)();
carray<std::size_t, M> H;
H.fill(UNUSED);

Expand Down
10 changes: 5 additions & 5 deletions include/ylt/thirdparty/frozen/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ class linear_congruential_engine {
state_ = modulo(tmp, std::integral_constant<UIntType, modulus>());
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_;
Expand Down
2 changes: 1 addition & 1 deletion include/ylt/thirdparty/iguana/detail/fast_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>::mantissa_explicit_bits()))
Expand Down
2 changes: 2 additions & 0 deletions src/coro_http/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
126 changes: 126 additions & 0 deletions src/coro_http/examples/chat_room.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <mutex>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>

#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<std::string> 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<void> 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<intptr_t, std::string> conn_map;
server.set_http_handler<cinatra::GET>(
"/",
[&](coro_http_request &req,
coro_http_response &resp) -> async_simple::coro::Lazy<void> {
websocket_result result{};

std::unordered_map<intptr_t, std::string> 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<std::string> 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();
}
156 changes: 156 additions & 0 deletions src/coro_http/examples/client.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<!DOCTYPE html>
<html>

<head>
<title></title>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<style>
p {
text-align: left;
padding-left: 20px;
}
</style>
</head>

<body>
<div style="width: 800px;height: 600px;margin: 30px auto;text-align: center">
<h1>基于C++20 协程的websocket聊天室</h1>
<div style="width: 800px;border: 1px solid gray;height: 300px;">
<div style="width: 200px;height: 300px;float: left;text-align: left;">
<p><span>当前在线:</span><span id="user_num">0</span></p>
<div id="user_list" style="overflow: auto;">

</div>
</div>
<div id="msg_list"
style="width: 598px;border: 1px solid gray; height: 300px;overflow: scroll;float: left;">
</div>
</div>
<br>
<textarea id="msg_box" rows="6" cols="50" onkeydown="confirm(event)"></textarea><br>
<input type="button" value="发送" onclick="send()">
</div>
</body>

</html>

<script type="text/javascript">
var uname = prompt('请输入用户名', 'user' + uuid(8, 16));
var ws = new WebSocket("ws://127.0.0.1:9001/");
ws.onopen = function () {
var data = "系统消息:建立连接成功";
let user_info = { 'type': 'login', 'content': uname };
sendMsg(user_info);
};

ws.onmessage = function (e) {
var msg = JSON.parse(e.data);
var sender, user_name, name_list, change_type;

switch (msg.type) {
case 'user':
sender = '<b style="color:green;">' + msg.from + '说: ' + '</b>';
break;
case 'login':
case 'logout':
user_name = msg.content;
name_list = msg.user_list;
change_type = msg.type;
dealUser(user_name, change_type, name_list);
return;
}

var data = sender + msg.content;
listMsg(data);
};

ws.onerror = function () {
var data = "系统消息 : 出错了,请退出重试.";
listMsg(data);
};

function confirm(event) {
var key_num = event.keyCode;
if (13 == key_num) {
send();
} else {
return false;
}
}

function send() {
var msg_box = document.getElementById("msg_box");
var content = msg_box.value;
var reg = new RegExp("\r\n", "g");
content = content.replace(reg, "");
var msg = { 'type': 'user', 'content': content.trim() };
sendMsg(msg);
msg_box.value = '';
}

function listMsg(data) {
var msg_list = document.getElementById("msg_list");
var msg = document.createElement("p");

msg.innerHTML = data;
msg_list.appendChild(msg);
msg_list.scrollTop = msg_list.scrollHeight;
}

/**
* 处理用户登陆消息
*
* @param user_name 用户名
* @param type login/logout
* @param name_list 用户列表
*/
function dealUser(user_name, type, name_list) {
var user_list = document.getElementById("user_list");
var user_num = document.getElementById("user_num");
while (user_list.hasChildNodes()) {
user_list.removeChild(user_list.firstChild);
}

for (var index in name_list) {
var user = document.createElement("p");
user.innerHTML = name_list[index];
user_list.appendChild(user);
}
user_num.innerHTML = name_list.length;
user_list.scrollTop = user_list.scrollHeight;

var change = type == 'login' ? '上线' : '下线';

var data = '<b style="color:red;">系统消息</b>: ' + user_name + ' 已' + change;
listMsg(data);
}

function sendMsg(msg) {
var data = JSON.stringify(msg);
ws.send(data);
}

function uuid(len, radix) {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
var uuid = [], i;
radix = radix || chars.length;

if (len) {
for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
} else {
var r;

uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';

for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
}
}
}

return uuid.join('');
}
</script>

0 comments on commit 9ae8f00

Please sign in to comment.