From 818d0622e93ac55d942b449804428a0fe5e7fc40 Mon Sep 17 00:00:00 2001 From: talksik Date: Sat, 27 Jan 2024 13:47:39 -0800 Subject: [PATCH] storing full message with username in cache --- ' | 118 ++++++++++++++++++ .../index/Main.cpp.59B438EDC5609780.idx | Bin 718 -> 788 bytes .../index/colors.h.9CBF675E9831E6F4.idx | Bin 0 -> 536 bytes .../MessageCache.cpp.C00C31C15AF0039C.idx | Bin 0 -> 1102 bytes .../MessageCache.hpp.EA225B528CC272FD.idx | Bin 0 -> 732 bytes server/src/Main.cpp | 65 +++++++--- server/src/include/MessageCache.hpp | 1 + 7 files changed, 168 insertions(+), 16 deletions(-) create mode 100644 ' create mode 100644 client/.cache/clangd/index/colors.h.9CBF675E9831E6F4.idx create mode 100644 server/.cache/clangd/index/MessageCache.cpp.C00C31C15AF0039C.idx create mode 100644 server/.cache/clangd/index/MessageCache.hpp.EA225B528CC272FD.idx diff --git a/' b/' new file mode 100644 index 0000000..5125314 --- /dev/null +++ b/' @@ -0,0 +1,118 @@ +#include "include/DateTime.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +struct PerSocketData +{ + std::chrono::system_clock::time_point created_at; + std::string remote_addr; +}; + +std::string full_message(PerSocketData &user_data, std::string_view message) +{ + std::cout << user_data.remote_addr << ": " << message << std::endl; + std::stringstream ss; + ss << user_data.remote_addr << ": " << message; + return ss.str(); +} + +int main() +{ + std::cout << "Welcome to the homechat server!\n"; + + std::mutex message_cache_mutex; + std::unique_ptr message_cache = std::make_unique(); + + /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support. + * You may swap to using uWS:App() if you don't need SSL */ + uWS::App({/* There are example certificates in uWebSockets.js repo */ + .key_file_name = "misc/key.pem", + .cert_file_name = "misc/cert.pem", + .passphrase = "1234"}) + .ws( + "/*", + {/* Settings */ + .compression = uWS::CompressOptions(uWS::DEDICATED_COMPRESSOR_4KB | uWS::DEDICATED_DECOMPRESSOR), + .maxPayloadLength = 100 * 1024 * 1024, + .idleTimeout = 16, + .maxBackpressure = 100 * 1024 * 1024, + .closeOnBackpressureLimit = false, + .resetIdleTimeoutOnSend = false, + .sendPingsAutomatically = true, + /* Handlers */ + .upgrade = nullptr, + .open = + [&](uWS::WebSocket *ws) { + auto user_data = ws->getUserData(); + user_data->created_at = DateTime::now(); + user_data->remote_addr = ws->getRemoteAddressAsText(); + + DateTime::outputTime("Client connected at ", user_data->created_at); + if (!ws->subscribe("*", true)) + { + std::cout << "Failed to subscribe to * channel\n"; + ws->close(); + } + + std::lock_guard lock(message_cache_mutex); + auto messages = message_cache->last_ten_messages(); + ws->send(std::string("Welcome to the homechat server! Here are the last 10 messages: \n"), + uWS::OpCode::TEXT, false); + for (auto &message : messages) + { + ws->send(full_message(*user_data, message), uWS::OpCode::TEXT, false); + } + }, + .message = + [&](uWS::WebSocket *ws, std::string_view message, uWS::OpCode opCode) { + /* This is the opposite of what you probably want; compress if message is LARGER than 16 kb + * the reason we do the opposite here; compress if SMALLER than 16 kb is to allow for + * benchmarking of large message sending without compression */ + std::cout << "Message received: " << message << std::endl; + ws->send(message, opCode, false); + ws->publish("*", message, opCode, false); + + std::lock_guard lock(message_cache_mutex); + if (!message_cache->add_message(std::string(message))) + { + std::cerr << "Failed to add message to cache" << std::endl; + } + }, + .dropped = + [](auto * /*ws*/, std::string_view /*message*/, uWS::OpCode /*opCode*/) { + /* A message was dropped due to set maxBackpressure and closeOnBackpressureLimit limit */ + }, + .drain = + [](auto * /*ws*/) { + /* Check ws->getBufferedAmount() here */ + }, + .ping = + [](auto * /*ws*/, std::string_view) { + /* Not implemented yet */ + }, + .pong = + [](auto * /*ws*/, std::string_view) { + /* Not implemented yet */ + }, + .close = + [](auto * /*ws*/, int /*code*/, std::string_view /*message*/) { + /* You may access ws->getUserData() here */ + std::cout << "Client disconnected\n"; + }}) + .listen(9001, + [](auto *listen_socket) { + if (listen_socket) + { + std::cout << "Listening on port " << 9001 << std::endl; + } + }) + .run(); + + return 0; +} diff --git a/client/.cache/clangd/index/Main.cpp.59B438EDC5609780.idx b/client/.cache/clangd/index/Main.cpp.59B438EDC5609780.idx index bb9b014ab66b9ff61e3b1820916260e05d117b36..baf90bad18158d3fa67670db0f1a4b3a7e7198e1 100644 GIT binary patch literal 788 zcmWIYbaUfjW?*nm@vO*AElFfyU|MdDEyuO#k+x{!|t}LvERwp3-7;W*q`Y! z`O=|89kWSSj;&Q<)>k=bq8GAhf-C3ha0kXWjKT@mCSB9%y7%c}VHdZjMS!G*_R(%% zlS0plY11ZF>y{cEznA}V`OV$s*Ml~^+wXK%Zr+BgYsLN;A6ot2IJ(5>yhHZME0HQI zpUa=Oc{RN?>*W^5M&uy^39r^zZup6h1ogTd0>V_ zI@Ij$Ed0F-=m2(JcDPNv=~CvIt7Q%Vg*i1iwP31uxJ|8C=kWXn$hig_#xUW9Io>Q@ zfo+eNfU5a81z^HJo(rcNjAteH@l-Zj;zwo{9#%e9WJS`PvM@zJE!Ld2FkVq=P9n(t z#YM@*${+?Wh=2e-7=wY4XV&8z9MPVi_Av4CF(l`vUlkrpzT;u}^qJ6Ib-w*k9|J`?-A5uI@KMoSd9LD)<=$1!_007VEkBI`PI^2K&r2 zfte2tLT7tKJ&v0=QG8OuEU{ItCnmLA)n35B*C4qe<7~E|YyQ&@JC3&M$gJp#nR4l> zlIuFli)V~JF4(I3%;bk|ZE5xQS5;hPKi39qZ&%NW4debd^Wg0N#?eJa=N+UsUmA#Ck$C*BD3XVPkAZ=QiG_&+OaNsdpeQx1I0YCI*R}-8{I8zE z&B(&T$;-(P({@g|x}(W1n4g)4hed-$2PVwJ!*0cHhv0FWa9hB58)I%5E$ZPH0%_r7 z;e`nUwQ#Z{@whp;;XIfcMlKY`O%-n!bF34o1G4V8Sds z>_+S+2p+c%w;qgVCHL`EHe2FH7N8bB76F(rPzxVB5|5jY8=0rdtqxOJl$w(W3iaZm ts%|k6DZ8V!NCJF z`@`*U=M!d!4*`YwIru>_00s}|?9x9Wy7MGZn45zeZZ`A9lO0!H9zP2d=H=jpduLnG ziqz_~We)N?N)d3Pnd5e9Hg; literal 0 HcmV?d00001 diff --git a/server/.cache/clangd/index/MessageCache.cpp.C00C31C15AF0039C.idx b/server/.cache/clangd/index/MessageCache.cpp.C00C31C15AF0039C.idx new file mode 100644 index 0000000000000000000000000000000000000000..1c355ea8e37a2324bd1d12a6f7029fde9c7c4b44 GIT binary patch literal 1102 zcmWIYbaQiKVPJ4h@vO*AElC728H9kixTGla1CW+rVqmD4Gk4>R7ssH*)FUbAGw_Vu^ZHXPu)>*qHA>)$VtY{>^C!vDB-b>2L=?{?0C znuPg_AGjn2*ehJ`-hIf{cSTT^c~;_=&ckn5c$!}xNHK6VIp2EJBK});7w=5X1>Ztg zE+2L8Sz`In!zMtzOGcwK&+^vWbNgP49ibFv>hGj%@x!a9HIJ%xYf z@9w`joxj$w_9)Axm2*{U+k7vxM;!#(8mmPp$d~0Oc-ddpr|-ZFVL^1;?^)8ObyVlpvZ*z@skgu@>PesH-Hwf z3A4d1*m1PPEOL&mADem*+oMES|IdZg|i7q%_^#o&0AjrEN@C zggL#d-zkh_9%6UZY~jK0VYl+ z23ApZQ42O6SspzG4xk(mMthRurl$m@o@6+!&LFG@pJO?!_0 #include #include +#include #include +#include #include +#include +#include #include +struct PerSocketData +{ + std::chrono::system_clock::time_point created_at; + std::string username; +}; + +std::string full_message(PerSocketData *&user_data, std::string_view message) +{ + std::cout << user_data->username << ": " << message << std::endl; + + std::stringstream ss; + ss << user_data->username << ": " << message; + return ss.str(); +} + int main() { std::cout << "Welcome to the homechat server!\n"; @@ -15,12 +34,6 @@ int main() std::mutex message_cache_mutex; std::unique_ptr message_cache = std::make_unique(); - /* ws->getUserData returns one of these */ - struct PerSocketData - { - std::chrono::system_clock::time_point created_at; - }; - /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support. * You may swap to using uWS:App() if you don't need SSL */ uWS::App({/* There are example certificates in uWebSockets.js repo */ @@ -38,14 +51,31 @@ int main() .resetIdleTimeoutOnSend = false, .sendPingsAutomatically = true, /* Handlers */ - .upgrade = nullptr, + .upgrade = + [](uWS::HttpResponse *res, uWS::HttpRequest *req, us_socket_context_t *ctx) { + std::string_view name = req->getHeader("username"); + if (name.empty()) + { + std::cout << "No username provided\n"; + res->writeStatus("401 Unauthorized: add `username` header")->end(); + return; + } + + res->template upgrade( + { + .created_at = DateTime::now(), + .username = std::string(name), + }, + req->getHeader("sec-websocket-key"), req->getHeader("sec-websocket-protocol"), + req->getHeader("sec-websocket-extensions"), ctx); + }, .open = [&](uWS::WebSocket *ws) { auto user_data = ws->getUserData(); - user_data->created_at = DateTime::now(); - DateTime::outputTime("Client connected at ", user_data->created_at); - if (!ws->subscribe("*")) + auto desc = user_data->username + " connected at: "; + DateTime::outputTime(desc.c_str(), user_data->created_at); + if (!ws->subscribe("*", true)) { std::cout << "Failed to subscribe to * channel\n"; ws->close(); @@ -53,10 +83,11 @@ int main() std::lock_guard lock(message_cache_mutex); auto messages = message_cache->last_ten_messages(); - ws->send(std::string("Welcome to the homechat server! Here are the last 10 messages: \n"), uWS::OpCode::TEXT, false); - for (auto &message : messages) + ws->send(std::string("Welcome to the homechat server! Here are the last 10 messages: \n"), + uWS::OpCode::TEXT, false); + for (auto &full_message : messages) { - ws->send(message, uWS::OpCode::TEXT, false); + ws->send(full_message, uWS::OpCode::TEXT, false); } }, .message = @@ -65,11 +96,13 @@ int main() * the reason we do the opposite here; compress if SMALLER than 16 kb is to allow for * benchmarking of large message sending without compression */ std::cout << "Message received: " << message << std::endl; - ws->send(message, opCode, false); - ws->publish("*", message, opCode, false); + auto user_data = ws->getUserData(); + auto full_message_formed = full_message(user_data, message); + ws->send(full_message_formed, opCode, false); + ws->publish("*", full_message_formed, opCode, false); std::lock_guard lock(message_cache_mutex); - if (!message_cache->add_message(std::string(message))) + if (!message_cache->add_message(full_message_formed)) { std::cerr << "Failed to add message to cache" << std::endl; } diff --git a/server/src/include/MessageCache.hpp b/server/src/include/MessageCache.hpp index ffd96d5..7b9696d 100644 --- a/server/src/include/MessageCache.hpp +++ b/server/src/include/MessageCache.hpp @@ -1,6 +1,7 @@ #include #include +// LRUCache for messages class MessageCache { public: