diff --git a/build b/build index 56a6051..d8263ee 100644 --- a/build +++ b/build @@ -1 +1 @@ -1 \ No newline at end of file +2 \ No newline at end of file diff --git a/src/framework/UI_WebSocketClientServer.cpp b/src/framework/UI_WebSocketClientServer.cpp index 5246188..cc42125 100644 --- a/src/framework/UI_WebSocketClientServer.cpp +++ b/src/framework/UI_WebSocketClientServer.cpp @@ -19,9 +19,27 @@ namespace OpenWifi { void UI_WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id, const std::string &UserName ) { std::lock_guard G(Mutex_); - auto Client = std::make_unique(WS,Id,UserName,Logger(), Processor_); - Clients_[Id] = std::make_pair(std::move(Client),""); - } + auto Client = std::make_unique(WS,Id, UserName); + + Clients_[Id] = std::move(Client); + + Client->WS_->setNoDelay(true); + Client->WS_->setKeepAlive(true); + Client->WS_->setBlocking(false); + Reactor_.addEventHandler(*Client->WS_, + Poco::NObserver( + *this, &UI_WebSocketClientServer::OnSocketReadable)); + Reactor_.addEventHandler(*Client->WS_, + Poco::NObserver( + *this, &UI_WebSocketClientServer::OnSocketShutdown)); + Reactor_.addEventHandler(*Client->WS_, + Poco::NObserver( + *this, &UI_WebSocketClientServer::OnSocketError)); + Client->SocketRegistered_ = true; + + std::cout << "B: WS: User -> " << UserName << std::endl; + + } void UI_WebSocketClientServer::SetProcessor( UI_WebSocketClientProcessor * F) { Processor_ = F; @@ -32,21 +50,30 @@ namespace OpenWifi { Clients_.erase(Id); } - void UI_WebSocketClientServer::SetUser(const std::string &Id, const std::string &UserId) { - std::lock_guard G(Mutex_); - - auto it=Clients_.find(Id); - if(it!=Clients_.end()) { - Clients_[Id] = std::make_pair(std::move(it->second.first),UserId); - } - } - [[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload); UI_WebSocketClientServer::UI_WebSocketClientServer() noexcept: SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients") { } + void UI_WebSocketClientServer::EndConnection([[maybe_unused]] std::lock_guard &G, ClientList::iterator &Client) { + if(Client->second->SocketRegistered_) { + Client->second->SocketRegistered_ = false; + (*Client->second->WS_).shutdown(); + Reactor_.removeEventHandler(*Client->second->WS_, + Poco::NObserver(*this,&UI_WebSocketClientServer::OnSocketReadable)); + Reactor_.removeEventHandler(*Client->second->WS_, + Poco::NObserver(*this,&UI_WebSocketClientServer::OnSocketShutdown)); + Reactor_.removeEventHandler(*Client->second->WS_, + Poco::NObserver(*this,&UI_WebSocketClientServer::OnSocketError)); + } + std::cout << "B: WS: User -> " << Client->second->UserName_ << std::endl; ; + Clients_.erase(Client); + } + void UI_WebSocketClientServer::run() { Running_ = true ; Utils::SetThreadName("ws:uiclnt-svr"); @@ -82,7 +109,7 @@ namespace OpenWifi { auto It = Clients_.find(Id); if(It!=Clients_.end()) - return It->second.first->Send(Payload); + return It->second->WS_->sendFrame(Payload.c_str(),Payload.size()); return false; } @@ -91,9 +118,9 @@ namespace OpenWifi { uint64_t Sent=0; for(const auto &client:Clients_) { - if(client.second.second == UserName) { + if(client.second->UserName_ == UserName) { try { - if (client.second.first->Send(Payload)) + if (client.second->WS_->sendFrame(Payload.c_str(),Payload.size())) Sent++; } catch (...) { return false; @@ -108,60 +135,83 @@ namespace OpenWifi { for(const auto &client:Clients_) { try { - client.second.first->Send(Payload); + client.second->WS_->sendFrame(Payload.c_str(),Payload.size()); } catch (...) { } } } - void UI_WebSocketClient::OnSocketError([[maybe_unused]] const Poco::AutoPtr &pNf) { - EndConnection(); + UI_WebSocketClientServer::ClientList::iterator UI_WebSocketClientServer::FindWSClient( [[maybe_unused]] std::lock_guard &G, const Poco::Net::Socket &Socket) { + for(auto i = Clients_.begin();i!=Clients_.end();++i) { + if(*i->second->WS_ == Socket) { + return i; + } + } + return end(Clients_); + } + + void UI_WebSocketClientServer::OnSocketError([[maybe_unused]] const Poco::AutoPtr &pNf) { + std::lock_guard G(LocalMutex_); + auto Client = FindWSClient(G,pNf->socket()); + if(Client==end(Clients_)) + return; + EndConnection(G,Client); } - void UI_WebSocketClient::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr &pNf) { + void UI_WebSocketClientServer::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr &pNf) { int flags; int n; bool Done=false; + + + UI_WebSocketClientServer::ClientList::iterator Client; + std::lock_guard G(LocalMutex_); + try { + + Client = FindWSClient(G,pNf->socket()); + if( Client == end(Clients_)) + return; + Poco::Buffer IncomingFrame(0); - n = WS_->receiveFrame(IncomingFrame, flags); + n = Client->second->WS_->receiveFrame(IncomingFrame, flags); auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; if (n == 0) { - poco_debug(Logger(),fmt::format("CLOSE({}): {} UI Client is closing WS connection.", Id_, UserName_)); - return EndConnection(); + poco_debug(Logger(),fmt::format("CLOSE({}): {} UI Client is closing WS connection.", Client->second->Id_, Client->second->UserName_)); + return EndConnection(G, Client); } switch (Op) { case Poco::Net::WebSocket::FRAME_OP_PING: { - WS_->sendFrame("", 0, + Client->second->WS_->sendFrame("", 0, (int)Poco::Net::WebSocket::FRAME_OP_PONG | (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); } break; case Poco::Net::WebSocket::FRAME_OP_PONG: { } break; case Poco::Net::WebSocket::FRAME_OP_CLOSE: { - poco_debug(Logger(),fmt::format("CLOSE({}): {} UI Client is closing WS connection.", Id_, UserName_)); + poco_debug(Logger(),fmt::format("CLOSE({}): {} UI Client is closing WS connection.", Client->second->Id_, Client->second->UserName_)); Done = true; } break; case Poco::Net::WebSocket::FRAME_OP_TEXT: { IncomingFrame.append(0); - if (!Authenticated_) { + if (!Client->second->Authenticated_) { std::string Frame{IncomingFrame.begin()}; auto Tokens = Utils::Split(Frame, ':'); bool Expired = false, Contacted = false; if (Tokens.size() == 2 && - AuthClient()->IsAuthorized(Tokens[1], UserInfo_, 0, Expired, Contacted)) { - Authenticated_ = true; - UserName_ = UserInfo_.userinfo.email; - poco_debug(Logger(),fmt::format("START({}): {} UI Client is starting WS connection.", Id_, UserName_)); + AuthClient()->IsAuthorized(Tokens[1], Client->second->UserInfo_, 0, Expired, Contacted)) { + Client->second->Authenticated_ = true; + Client->second->UserName_ = Client->second->UserInfo_.userinfo.email; + poco_debug(Logger(),fmt::format("START({}): {} UI Client is starting WS connection.", Client->second->Id_, Client->second->UserName_)); std::string S{"Welcome! Bienvenue! Bienvenidos!"}; - WS_->sendFrame(S.c_str(), S.size()); - UI_WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email); + Client->second->WS_->sendFrame(S.c_str(), S.size()); + Client->second->UserName_ = Client->second->UserInfo_.userinfo.email; } else { std::string S{"Invalid token. Closing connection."}; - WS_->sendFrame(S.c_str(), S.size()); + Client->second->WS_->sendFrame(S.c_str(), S.size()); Done = true; } @@ -174,9 +224,9 @@ namespace OpenWifi { if (Processor_ != nullptr) Processor_->Processor(Obj, Answer, Done); if (!Answer.empty()) - WS_->sendFrame(Answer.c_str(), (int)Answer.size()); + Client->second->WS_->sendFrame(Answer.c_str(), (int)Answer.size()); else { - WS_->sendFrame("{}", 2); + Client->second->WS_->sendFrame("{}", 2); } } catch (const Poco::JSON::JSONException &E) { Logger().log(E); @@ -192,75 +242,21 @@ namespace OpenWifi { } if(Done) { - return EndConnection(); + return EndConnection(G, Client);; } } - void UI_WebSocketClient::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr &pNf) { - EndConnection(); + void UI_WebSocketClientServer::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr &pNf) { + ClientList::iterator Client; + std::lock_guard G(LocalMutex_); + try { + Client = FindWSClient(G, pNf->socket()); + if (Client == end(Clients_)) + return; + EndConnection(G, Client); + } catch (...) { + + } } - - UI_WebSocketClient::UI_WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, const std::string &UserName, Poco::Logger & L, UI_WebSocketClientProcessor * Processor) : - Reactor_(UI_WebSocketClientServer()->Reactor()), - Id_(Id), - UserName_(UserName), - Logger_(L), - Processor_(Processor) { - WS_ = std::make_unique(WS); - WS_->setNoDelay(true); - WS_->setKeepAlive(true); - WS_->setBlocking(false); - Reactor_.addEventHandler(*WS_, - Poco::NObserver( - *this, &UI_WebSocketClient::OnSocketReadable)); - Reactor_.addEventHandler(*WS_, - Poco::NObserver( - *this, &UI_WebSocketClient::OnSocketShutdown)); - Reactor_.addEventHandler(*WS_, - Poco::NObserver( - *this, &UI_WebSocketClient::OnSocketError)); - SocketRegistered_ = true; - } - - void UI_WebSocketClient::EndConnection() { - if(SocketRegistered_) { - SocketRegistered_ = false; - (*WS_).shutdown(); - Reactor_.removeEventHandler(*WS_, - Poco::NObserver(*this,&UI_WebSocketClient::OnSocketReadable)); - Reactor_.removeEventHandler(*WS_, - Poco::NObserver(*this,&UI_WebSocketClient::OnSocketShutdown)); - Reactor_.removeEventHandler(*WS_, - Poco::NObserver(*this,&UI_WebSocketClient::OnSocketError)); - UI_WebSocketClientServer()->UnRegister(Id_); - } - } - - UI_WebSocketClient::~UI_WebSocketClient() { - EndConnection(); - } - - [[nodiscard]] const std::string & UI_WebSocketClient::Id() { - return Id_; - }; - - [[nodiscard]] Poco::Logger & UI_WebSocketClient::Logger() { - return Logger_; - } - - [[nodiscard]] bool UI_WebSocketClient::Send(const std::string &Payload) { - try { - WS_->sendFrame(Payload.c_str(),Payload.size()); - return true; - } catch (...) { - - } - return false; - } - - } // namespace OpenWifi \ No newline at end of file diff --git a/src/framework/UI_WebSocketClientServer.h b/src/framework/UI_WebSocketClientServer.h index 6a4804f..81f5f58 100644 --- a/src/framework/UI_WebSocketClientServer.h +++ b/src/framework/UI_WebSocketClientServer.h @@ -27,6 +27,21 @@ namespace OpenWifi { private: }; + struct UI_WebSocketClientInfo { + std::unique_ptr WS_ = nullptr; + std::string Id_; + std::string UserName_; + bool Authenticated_ = false; + bool SocketRegistered_=false; + SecurityObjects::UserInfoAndPolicy UserInfo_; + + UI_WebSocketClientInfo(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &username) { + WS_ = std::make_unique(WS); + Id_ = Id; + UserName_ = username; + } + }; + class UI_WebSocketClientServer : public SubSystemServer, Poco::Runnable { public: @@ -42,7 +57,6 @@ namespace OpenWifi { void NewClient(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &UserName); void SetProcessor(UI_WebSocketClientProcessor *F); void UnRegister(const std::string &Id); - void SetUser(const std::string &Id, const std::string &UserId); [[nodiscard]] inline bool GeoCodeEnabled() const { return GeoCodeEnabled_; } [[nodiscard]] inline std::string GoogleApiKey() const { return GoogleApiKey_; } [[nodiscard]] bool Send(const std::string &Id, const std::string &Payload); @@ -73,46 +87,30 @@ namespace OpenWifi { [[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload); void SendToAll(const std::string &Payload); - private: + using ClientList = std::map>; + private: mutable std::atomic_bool Running_ = false; Poco::Thread Thr_; Poco::Net::SocketReactor Reactor_; Poco::Thread ReactorThread_; + std::recursive_mutex LocalMutex_; bool GeoCodeEnabled_ = false; std::string GoogleApiKey_; - std::map, std::string>> Clients_; - UI_WebSocketClientProcessor *Processor_ = nullptr; + ClientList Clients_; + UI_WebSocketClientProcessor *Processor_ = nullptr; UI_WebSocketClientServer() noexcept; + void EndConnection(std::lock_guard &G, ClientList::iterator & Client); + + void OnSocketReadable(const Poco::AutoPtr &pNf); + void OnSocketShutdown(const Poco::AutoPtr &pNf); + void OnSocketError(const Poco::AutoPtr &pNf); + + ClientList::iterator FindWSClient( std::lock_guard &G, const Poco::Net::Socket & S); + + }; inline auto UI_WebSocketClientServer() { return UI_WebSocketClientServer::instance(); } - class UI_WebSocketClient { - public: - explicit UI_WebSocketClient(Poco::Net::WebSocket &WS, - const std::string &Id, - const std::string &UserName, - Poco::Logger &L, - UI_WebSocketClientProcessor *Processor); - virtual ~UI_WebSocketClient(); - [[nodiscard]] inline const std::string &Id(); - [[nodiscard]] Poco::Logger &Logger(); - bool Send(const std::string &Payload); - void EndConnection(); - private: - std::unique_ptr WS_; - Poco::Net::SocketReactor &Reactor_; - std::string Id_; - std::string UserName_; - Poco::Logger &Logger_; - std::atomic_bool Authenticated_ = false; - volatile bool SocketRegistered_=false; - SecurityObjects::UserInfoAndPolicy UserInfo_; - UI_WebSocketClientProcessor *Processor_ = nullptr; - void OnSocketReadable(const Poco::AutoPtr &pNf); - void OnSocketShutdown(const Poco::AutoPtr &pNf); - void OnSocketError(const Poco::AutoPtr &pNf); - }; - };