stephb9959
2022-10-29 23:51:55 -07:00
parent d08d64ae27
commit c0004dc804
3 changed files with 126 additions and 132 deletions

2
build
View File

@@ -1 +1 @@
1 2

View File

@@ -19,9 +19,27 @@ namespace OpenWifi {
void UI_WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id, const std::string &UserName ) { void UI_WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id, const std::string &UserName ) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
auto Client = std::make_unique<UI_WebSocketClient>(WS,Id,UserName,Logger(), Processor_); auto Client = std::make_unique<UI_WebSocketClientInfo>(WS,Id, UserName);
Clients_[Id] = std::make_pair(std::move(Client),"");
} Clients_[Id] = std::move(Client);
Client->WS_->setNoDelay(true);
Client->WS_->setKeepAlive(true);
Client->WS_->setBlocking(false);
Reactor_.addEventHandler(*Client->WS_,
Poco::NObserver<UI_WebSocketClientServer, Poco::Net::ReadableNotification>(
*this, &UI_WebSocketClientServer::OnSocketReadable));
Reactor_.addEventHandler(*Client->WS_,
Poco::NObserver<UI_WebSocketClientServer, Poco::Net::ShutdownNotification>(
*this, &UI_WebSocketClientServer::OnSocketShutdown));
Reactor_.addEventHandler(*Client->WS_,
Poco::NObserver<UI_WebSocketClientServer, Poco::Net::ErrorNotification>(
*this, &UI_WebSocketClientServer::OnSocketError));
Client->SocketRegistered_ = true;
std::cout << "B: WS: User -> " << UserName << std::endl;
}
void UI_WebSocketClientServer::SetProcessor( UI_WebSocketClientProcessor * F) { void UI_WebSocketClientServer::SetProcessor( UI_WebSocketClientProcessor * F) {
Processor_ = F; Processor_ = F;
@@ -32,21 +50,30 @@ namespace OpenWifi {
Clients_.erase(Id); 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); [[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload);
UI_WebSocketClientServer::UI_WebSocketClientServer() noexcept: UI_WebSocketClientServer::UI_WebSocketClientServer() noexcept:
SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients") SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients")
{ {
} }
void UI_WebSocketClientServer::EndConnection([[maybe_unused]] std::lock_guard<std::recursive_mutex> &G, ClientList::iterator &Client) {
if(Client->second->SocketRegistered_) {
Client->second->SocketRegistered_ = false;
(*Client->second->WS_).shutdown();
Reactor_.removeEventHandler(*Client->second->WS_,
Poco::NObserver<UI_WebSocketClientServer,
Poco::Net::ReadableNotification>(*this,&UI_WebSocketClientServer::OnSocketReadable));
Reactor_.removeEventHandler(*Client->second->WS_,
Poco::NObserver<UI_WebSocketClientServer,
Poco::Net::ShutdownNotification>(*this,&UI_WebSocketClientServer::OnSocketShutdown));
Reactor_.removeEventHandler(*Client->second->WS_,
Poco::NObserver<UI_WebSocketClientServer,
Poco::Net::ErrorNotification>(*this,&UI_WebSocketClientServer::OnSocketError));
}
std::cout << "B: WS: User -> " << Client->second->UserName_ << std::endl; ;
Clients_.erase(Client);
}
void UI_WebSocketClientServer::run() { void UI_WebSocketClientServer::run() {
Running_ = true ; Running_ = true ;
Utils::SetThreadName("ws:uiclnt-svr"); Utils::SetThreadName("ws:uiclnt-svr");
@@ -82,7 +109,7 @@ namespace OpenWifi {
auto It = Clients_.find(Id); auto It = Clients_.find(Id);
if(It!=Clients_.end()) if(It!=Clients_.end())
return It->second.first->Send(Payload); return It->second->WS_->sendFrame(Payload.c_str(),Payload.size());
return false; return false;
} }
@@ -91,9 +118,9 @@ namespace OpenWifi {
uint64_t Sent=0; uint64_t Sent=0;
for(const auto &client:Clients_) { for(const auto &client:Clients_) {
if(client.second.second == UserName) { if(client.second->UserName_ == UserName) {
try { try {
if (client.second.first->Send(Payload)) if (client.second->WS_->sendFrame(Payload.c_str(),Payload.size()))
Sent++; Sent++;
} catch (...) { } catch (...) {
return false; return false;
@@ -108,60 +135,83 @@ namespace OpenWifi {
for(const auto &client:Clients_) { for(const auto &client:Clients_) {
try { try {
client.second.first->Send(Payload); client.second->WS_->sendFrame(Payload.c_str(),Payload.size());
} catch (...) { } catch (...) {
} }
} }
} }
void UI_WebSocketClient::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) { UI_WebSocketClientServer::ClientList::iterator UI_WebSocketClientServer::FindWSClient( [[maybe_unused]] std::lock_guard<std::recursive_mutex> &G, const Poco::Net::Socket &Socket) {
EndConnection(); 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<Poco::Net::ErrorNotification> &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<Poco::Net::ReadableNotification> &pNf) { void UI_WebSocketClientServer::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
int flags; int flags;
int n; int n;
bool Done=false; bool Done=false;
UI_WebSocketClientServer::ClientList::iterator Client;
std::lock_guard G(LocalMutex_);
try { try {
Client = FindWSClient(G,pNf->socket());
if( Client == end(Clients_))
return;
Poco::Buffer<char> IncomingFrame(0); Poco::Buffer<char> IncomingFrame(0);
n = WS_->receiveFrame(IncomingFrame, flags); n = Client->second->WS_->receiveFrame(IncomingFrame, flags);
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
if (n == 0) { if (n == 0) {
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_));
return EndConnection(); return EndConnection(G, Client);
} }
switch (Op) { switch (Op) {
case Poco::Net::WebSocket::FRAME_OP_PING: { 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_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN); (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
} break; } break;
case Poco::Net::WebSocket::FRAME_OP_PONG: { case Poco::Net::WebSocket::FRAME_OP_PONG: {
} break; } break;
case Poco::Net::WebSocket::FRAME_OP_CLOSE: { 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; Done = true;
} break; } break;
case Poco::Net::WebSocket::FRAME_OP_TEXT: { case Poco::Net::WebSocket::FRAME_OP_TEXT: {
IncomingFrame.append(0); IncomingFrame.append(0);
if (!Authenticated_) { if (!Client->second->Authenticated_) {
std::string Frame{IncomingFrame.begin()}; std::string Frame{IncomingFrame.begin()};
auto Tokens = Utils::Split(Frame, ':'); auto Tokens = Utils::Split(Frame, ':');
bool Expired = false, Contacted = false; bool Expired = false, Contacted = false;
if (Tokens.size() == 2 && if (Tokens.size() == 2 &&
AuthClient()->IsAuthorized(Tokens[1], UserInfo_, 0, Expired, Contacted)) { AuthClient()->IsAuthorized(Tokens[1], Client->second->UserInfo_, 0, Expired, Contacted)) {
Authenticated_ = true; Client->second->Authenticated_ = true;
UserName_ = UserInfo_.userinfo.email; Client->second->UserName_ = Client->second->UserInfo_.userinfo.email;
poco_debug(Logger(),fmt::format("START({}): {} UI Client is starting WS connection.", Id_, UserName_)); poco_debug(Logger(),fmt::format("START({}): {} UI Client is starting WS connection.", Client->second->Id_, Client->second->UserName_));
std::string S{"Welcome! Bienvenue! Bienvenidos!"}; std::string S{"Welcome! Bienvenue! Bienvenidos!"};
WS_->sendFrame(S.c_str(), S.size()); Client->second->WS_->sendFrame(S.c_str(), S.size());
UI_WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email); Client->second->UserName_ = Client->second->UserInfo_.userinfo.email;
} else { } else {
std::string S{"Invalid token. Closing connection."}; 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; Done = true;
} }
@@ -174,9 +224,9 @@ namespace OpenWifi {
if (Processor_ != nullptr) if (Processor_ != nullptr)
Processor_->Processor(Obj, Answer, Done); Processor_->Processor(Obj, Answer, Done);
if (!Answer.empty()) if (!Answer.empty())
WS_->sendFrame(Answer.c_str(), (int)Answer.size()); Client->second->WS_->sendFrame(Answer.c_str(), (int)Answer.size());
else { else {
WS_->sendFrame("{}", 2); Client->second->WS_->sendFrame("{}", 2);
} }
} catch (const Poco::JSON::JSONException &E) { } catch (const Poco::JSON::JSONException &E) {
Logger().log(E); Logger().log(E);
@@ -192,75 +242,21 @@ namespace OpenWifi {
} }
if(Done) { if(Done) {
return EndConnection(); return EndConnection(G, Client);;
} }
} }
void UI_WebSocketClient::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) { void UI_WebSocketClientServer::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
EndConnection(); 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<Poco::Net::WebSocket>(WS);
WS_->setNoDelay(true);
WS_->setKeepAlive(true);
WS_->setBlocking(false);
Reactor_.addEventHandler(*WS_,
Poco::NObserver<UI_WebSocketClient, Poco::Net::ReadableNotification>(
*this, &UI_WebSocketClient::OnSocketReadable));
Reactor_.addEventHandler(*WS_,
Poco::NObserver<UI_WebSocketClient, Poco::Net::ShutdownNotification>(
*this, &UI_WebSocketClient::OnSocketShutdown));
Reactor_.addEventHandler(*WS_,
Poco::NObserver<UI_WebSocketClient, Poco::Net::ErrorNotification>(
*this, &UI_WebSocketClient::OnSocketError));
SocketRegistered_ = true;
}
void UI_WebSocketClient::EndConnection() {
if(SocketRegistered_) {
SocketRegistered_ = false;
(*WS_).shutdown();
Reactor_.removeEventHandler(*WS_,
Poco::NObserver<UI_WebSocketClient,
Poco::Net::ReadableNotification>(*this,&UI_WebSocketClient::OnSocketReadable));
Reactor_.removeEventHandler(*WS_,
Poco::NObserver<UI_WebSocketClient,
Poco::Net::ShutdownNotification>(*this,&UI_WebSocketClient::OnSocketShutdown));
Reactor_.removeEventHandler(*WS_,
Poco::NObserver<UI_WebSocketClient,
Poco::Net::ErrorNotification>(*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 } // namespace OpenWifi

View File

@@ -27,6 +27,21 @@ namespace OpenWifi {
private: private:
}; };
struct UI_WebSocketClientInfo {
std::unique_ptr<Poco::Net::WebSocket> 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<Poco::Net::WebSocket>(WS);
Id_ = Id;
UserName_ = username;
}
};
class UI_WebSocketClientServer : public SubSystemServer, Poco::Runnable { class UI_WebSocketClientServer : public SubSystemServer, Poco::Runnable {
public: public:
@@ -42,7 +57,6 @@ namespace OpenWifi {
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &UserName); void NewClient(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &UserName);
void SetProcessor(UI_WebSocketClientProcessor *F); void SetProcessor(UI_WebSocketClientProcessor *F);
void UnRegister(const std::string &Id); 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 bool GeoCodeEnabled() const { return GeoCodeEnabled_; }
[[nodiscard]] inline std::string GoogleApiKey() const { return GoogleApiKey_; } [[nodiscard]] inline std::string GoogleApiKey() const { return GoogleApiKey_; }
[[nodiscard]] bool Send(const std::string &Id, const std::string &Payload); [[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); [[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload);
void SendToAll(const std::string &Payload); void SendToAll(const std::string &Payload);
private: using ClientList = std::map<std::string,std::unique_ptr<UI_WebSocketClientInfo>>;
private:
mutable std::atomic_bool Running_ = false; mutable std::atomic_bool Running_ = false;
Poco::Thread Thr_; Poco::Thread Thr_;
Poco::Net::SocketReactor Reactor_; Poco::Net::SocketReactor Reactor_;
Poco::Thread ReactorThread_; Poco::Thread ReactorThread_;
std::recursive_mutex LocalMutex_;
bool GeoCodeEnabled_ = false; bool GeoCodeEnabled_ = false;
std::string GoogleApiKey_; std::string GoogleApiKey_;
std::map<std::string, std::pair<std::unique_ptr<UI_WebSocketClient>, std::string>> Clients_; ClientList Clients_;
UI_WebSocketClientProcessor *Processor_ = nullptr; UI_WebSocketClientProcessor *Processor_ = nullptr;
UI_WebSocketClientServer() noexcept; UI_WebSocketClientServer() noexcept;
void EndConnection(std::lock_guard<std::recursive_mutex> &G, ClientList::iterator & Client);
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf);
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
ClientList::iterator FindWSClient( std::lock_guard<std::recursive_mutex> &G, const Poco::Net::Socket & S);
}; };
inline auto UI_WebSocketClientServer() { return UI_WebSocketClientServer::instance(); } 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<Poco::Net::WebSocket> 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<Poco::Net::ReadableNotification> &pNf);
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf);
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
};
}; };