From e3b9c5e1062486fa96397dd52c9d41340246406d Mon Sep 17 00:00:00 2001
From: Sergey Linev <S.Linev@gsi.de>
Date: Tue, 9 Jan 2018 19:04:47 +0100
Subject: [PATCH] http: change THttpWSEngine class

remove inheritance from TNamed,
change signature of PreviewData() and PostProcess() methods
---
 README/ReleaseNotes/v614/index.md    |   6 ++
 gui/webdisplay/cef/base_handler.cxx  |  11 +--
 net/http/inc/THttpCallArg.h          |  12 +--
 net/http/inc/THttpLongPollEngine.h   |   6 +-
 net/http/inc/THttpWSEngine.h         |  12 +--
 net/http/inc/THttpWSHandler.h        |  11 ++-
 net/http/src/TCivetweb.cxx           |   8 +-
 net/http/src/THttpCallArg.cxx        |  22 ++---
 net/http/src/THttpLongPollEngine.cxx |  28 +++---
 net/http/src/THttpServer.cxx         |   2 +-
 net/http/src/THttpWSEngine.cxx       |  24 +++---
 net/http/src/THttpWSHandler.cxx      | 123 ++++++++++++++++++---------
 12 files changed, 159 insertions(+), 106 deletions(-)

diff --git a/README/ReleaseNotes/v614/index.md b/README/ReleaseNotes/v614/index.md
index f398814ab34..acbc3a94d62 100644
--- a/README/ReleaseNotes/v614/index.md
+++ b/README/ReleaseNotes/v614/index.md
@@ -80,6 +80,12 @@ The following people have contributed to this new version:
 
 ## Networking Libraries
 
+Changes in websockets handling in THttpServer. 
+   - New THttpWSHandler class should be used to work with websockets. 
+     It includes all necessary methods to handle multiple connections correctly.
+     See in tutorials/http/ws.C how it can be used.  
+   - Interface of THttpWSEngine class was changed, all its instances handled internally in THttpWSHandler.
+
 ## GUI Libraries
 
 ## Montecarlo Libraries
diff --git a/gui/webdisplay/cef/base_handler.cxx b/gui/webdisplay/cef/base_handler.cxx
index fb5972092bc..d3c30ed5b0f 100644
--- a/gui/webdisplay/cef/base_handler.cxx
+++ b/gui/webdisplay/cef/base_handler.cxx
@@ -11,6 +11,7 @@
 #include "base_handler.h"
 
 #include "TString.h"
+#include "TError.h"
 #include "THttpServer.h"
 #include "THttpWSEngine.h"
 #include "THttpCallArg.h"
@@ -45,8 +46,8 @@ protected:
    CefRefPtr<CefMessageRouterBrowserSide::Callback> fCallback;
 
 public:
-   TCefWSEngine(const char *name, const char *title, CefRefPtr<CefMessageRouterBrowserSide::Callback> callback)
-      : THttpWSEngine(name, title), fCallback(callback)
+   TCefWSEngine(CefRefPtr<CefMessageRouterBrowserSide::Callback> callback)
+      : THttpWSEngine(), fCallback(callback)
    {
    }
 
@@ -66,7 +67,7 @@ public:
 
    virtual void Send(const void * /*buf*/, int /*len*/)
    {
-      Error("Send", "Should never be called, only text is supported");
+      ::Error("TCefWSEngine::Send", "Should never be called, only text is supported");
    }
 
    virtual void SendCharStar(const char *buf)
@@ -76,7 +77,7 @@ public:
          fCallback->Success(buf); // send next message to JS
    }
 
-   virtual Bool_t PreviewData(THttpCallArg *arg)
+   virtual Bool_t PreviewData(THttpCallArg &)
    {
       // function called in the user code before processing correspondent websocket data
       // returns kTRUE when user should ignore such http request - it is for internal use
@@ -154,7 +155,7 @@ public:
       arg->SetFileName("root.ws_emulation");
 
       if (message == "connect") {
-         TCefWSEngine *ws = new TCefWSEngine("name", "title", callback);
+         TCefWSEngine *ws = new TCefWSEngine(callback);
          arg->SetMethod("WS_CONNECT");
          arg->SetWSHandle(ws);
          arg->SetWSId(ws->GetId());
diff --git a/net/http/inc/THttpCallArg.h b/net/http/inc/THttpCallArg.h
index 3103061b09e..eb93414a48f 100644
--- a/net/http/inc/THttpCallArg.h
+++ b/net/http/inc/THttpCallArg.h
@@ -19,7 +19,7 @@
 #include <condition_variable>
 
 class THttpServer;
-class TNamed;
+class THttpWSEngine;
 
 class THttpCallArg : public TObject {
 
@@ -36,8 +36,8 @@ protected:
    void *fPostData;        ///<! binary data received with post request
    Long_t fPostDataLength; ///<! length of binary data
 
-   TNamed *fWSHandle; ///<!  web-socket handle, derived from TNamed class
-   UInt_t fWSId;      ///<! websocket identifier, used in web-socket related operations
+   THttpWSEngine *fWSHandle; ///<!  web-socket engine, which helps to run it
+   UInt_t fWSId;             ///<! websocket identifier, used in web-socket related operations
 
    std::condition_variable fCond; ///<! condition used to wait for processing
 
@@ -86,9 +86,9 @@ public:
 
    void SetPostData(void *data, Long_t length, Bool_t make_copy = kFALSE);
 
-   void SetWSHandle(TNamed *handle);
+   void SetWSHandle(THttpWSEngine *handle);
 
-   TNamed *TakeWSHandle();
+   THttpWSEngine *TakeWSHandle();
 
    /** set web-socket id */
    void SetWSId(UInt_t id) { fWSId = id; }
@@ -127,7 +127,7 @@ public:
    Long_t GetPostDataLength() const { return fPostDataLength; }
 
    /** returns post data as TString */
-   TString GetPostDataAsString() const { return TString((const char *) GetPostData(), GetPostDataLength()); }
+   TString GetPostDataAsString() const { return TString((const char *)GetPostData(), GetPostDataLength()); }
 
    /** returns path name from request URL */
    const char *GetPathName() const { return fPathName.Data(); }
diff --git a/net/http/inc/THttpLongPollEngine.h b/net/http/inc/THttpLongPollEngine.h
index e1887ddb860..b7b69091f1f 100644
--- a/net/http/inc/THttpLongPollEngine.h
+++ b/net/http/inc/THttpLongPollEngine.h
@@ -23,7 +23,7 @@ protected:
    std::list<std::string> fBuf;      ///!< entries submitted to client
    static const char *gLongPollNope; ///!< default reply on the longpoll request
 public:
-   THttpLongPollEngine(const char *name, const char *title) : THttpWSEngine(name, title), fPoll(nullptr), fBuf() {}
+   THttpLongPollEngine() : THttpWSEngine(), fPoll(nullptr), fBuf() {}
 
    virtual UInt_t GetId() const;
 
@@ -33,9 +33,9 @@ public:
 
    virtual void SendCharStar(const char *buf);
 
-   virtual Bool_t PreviewData(THttpCallArg *arg);
+   virtual Bool_t PreviewData(THttpCallArg &arg);
 
-   virtual void PostProcess(THttpCallArg *arg);
+   virtual void PostProcess(THttpCallArg &arg);
 
    ClassDef(THttpLongPollEngine, 0);
 };
diff --git a/net/http/inc/THttpWSEngine.h b/net/http/inc/THttpWSEngine.h
index 105afb8561d..fb0eba135c9 100644
--- a/net/http/inc/THttpWSEngine.h
+++ b/net/http/inc/THttpWSEngine.h
@@ -12,17 +12,17 @@
 #ifndef ROOT_THttpWSEngine
 #define ROOT_THttpWSEngine
 
-#include "TNamed.h"
+#include "Rtypes.h"
 
 class THttpCallArg;
 
-class THttpWSEngine : public TNamed {
+class THttpWSEngine {
 
 protected:
-   THttpWSEngine(const char *name, const char *title);
+   THttpWSEngine() = default;
 
 public:
-   virtual ~THttpWSEngine();
+   virtual ~THttpWSEngine() {}
 
    virtual UInt_t GetId() const = 0;
 
@@ -32,9 +32,9 @@ public:
 
    virtual void SendCharStar(const char *str);
 
-   virtual Bool_t PreviewData(THttpCallArg *) { return kFALSE; }
+   virtual Bool_t PreviewData(THttpCallArg &);
 
-   virtual void PostProcess(THttpCallArg *) {}
+   virtual void PostProcess(THttpCallArg &);
 
    ClassDef(THttpWSEngine, 0) // abstract class for working with WebSockets-like protocol
 };
diff --git a/net/http/inc/THttpWSHandler.h b/net/http/inc/THttpWSHandler.h
index aa1fc2fb8cf..7a9c1d317ca 100644
--- a/net/http/inc/THttpWSHandler.h
+++ b/net/http/inc/THttpWSHandler.h
@@ -14,7 +14,7 @@
 
 #include "TNamed.h"
 
-#include "TList.h"
+#include <vector>
 
 class THttpCallArg;
 class THttpWSEngine;
@@ -30,9 +30,11 @@ private:
 
    Bool_t HandleWS(THttpCallArg *arg);
 
+   void RemoveEngine(THttpWSEngine *engine);
+
 protected:
 
-   TList    fEngines;         ///<!  list of of engines in use, cleaned automatically at the end
+   std::vector<THttpWSEngine *> fEngines;         ///<!  list of active WS engines (connections)
 
    THttpWSHandler(const char *name, const char *title);
 
@@ -49,6 +51,11 @@ public:
    /// Return kTRUE if websocket with given ID exists
    Bool_t HasWS(UInt_t wsid) const { return FindEngine(wsid) != 0; }
 
+   /// Returns current number of websocket connections
+   Int_t GetNumWS() const { return fEngines.size(); }
+
+   UInt_t GetWS(Int_t num = 0) const;
+
    void CloseWS(UInt_t wsid);
 
    void SendWS(UInt_t wsid, const void *buf, int len);
diff --git a/net/http/src/TCivetweb.cxx b/net/http/src/TCivetweb.cxx
index 11d1cddd9d6..0165a649221 100644
--- a/net/http/src/TCivetweb.cxx
+++ b/net/http/src/TCivetweb.cxx
@@ -33,13 +33,11 @@ protected:
    struct mg_connection *fWSconn;
 
 public:
-   TCivetwebWSEngine(const char *name, const char *title, struct mg_connection *conn)
-      : THttpWSEngine(name, title), fWSconn(conn)
+   TCivetwebWSEngine(struct mg_connection *conn)
+      : THttpWSEngine(), fWSconn(conn)
    {
    }
 
-   virtual ~TCivetwebWSEngine() {}
-
    virtual UInt_t GetId() const { return TString::Hash((void *)&fWSconn, sizeof(void *)); }
 
    virtual void ClearHandle() { fWSconn = nullptr; }
@@ -96,7 +94,7 @@ void websocket_ready_handler(struct mg_connection *conn, void *)
    arg.SetMethod("WS_READY");
 
    arg.SetWSId(TString::Hash((void *)&conn, sizeof(void *)));
-   arg.SetWSHandle(new TCivetwebWSEngine("websocket", "title", conn));
+   arg.SetWSHandle(new TCivetwebWSEngine(conn));
 
    serv->ExecuteHttp(&arg);
 }
diff --git a/net/http/src/THttpCallArg.cxx b/net/http/src/THttpCallArg.cxx
index c9657d2ccb9..71b5f26b563 100644
--- a/net/http/src/THttpCallArg.cxx
+++ b/net/http/src/THttpCallArg.cxx
@@ -13,7 +13,7 @@
 
 #include <string.h>
 #include "RZip.h"
-#include "TNamed.h"
+#include "THttpWSEngine.h"
 
 //////////////////////////////////////////////////////////////////////////
 //                                                                      //
@@ -31,7 +31,7 @@ ClassImp(THttpCallArg);
 
 THttpCallArg::THttpCallArg()
    : TObject(), fTopName(), fMethod(), fPathName(), fFileName(), fUserName(), fQuery(), fPostData(0),
-     fPostDataLength(0), fWSHandle(0), fWSId(0), fContentType(), fRequestHeader(), fHeader(), fContent(), fZipping(0),
+     fPostDataLength(0), fWSHandle(nullptr), fWSId(0), fContentType(), fRequestHeader(), fHeader(), fContent(), fZipping(0),
      fBinData(0), fBinDataLength(0), fNotifyFlag(kFALSE)
 {
 }
@@ -43,17 +43,17 @@ THttpCallArg::~THttpCallArg()
 {
    if (fPostData) {
       free(fPostData);
-      fPostData = 0;
+      fPostData = nullptr;
    }
 
    if (fWSHandle) {
       delete fWSHandle;
-      fWSHandle = 0;
+      fWSHandle = nullptr;
    }
 
    if (fBinData) {
       free(fBinData);
-      fBinData = 0;
+      fBinData = nullptr;
    }
 }
 
@@ -147,7 +147,7 @@ void THttpCallArg::SetPostData(void *data, Long_t length, Bool_t make_copy)
 {
    if (fPostData) {
       free(fPostData);
-      fPostData = 0;
+      fPostData = nullptr;
       fPostDataLength = 0;
    }
 
@@ -160,7 +160,7 @@ void THttpCallArg::SetPostData(void *data, Long_t length, Bool_t make_copy)
       data = newdata;
    }
 
-   if (data != 0)
+   if (data)
       *(((char *)data) + length) = 0;
 
    fPostData = data;
@@ -170,7 +170,7 @@ void THttpCallArg::SetPostData(void *data, Long_t length, Bool_t make_copy)
 ////////////////////////////////////////////////////////////////////////////////
 /// assign websocket handle with HTTP call
 
-void THttpCallArg::SetWSHandle(TNamed *handle)
+void THttpCallArg::SetWSHandle(THttpWSEngine *handle)
 {
    if (fWSHandle)
       delete fWSHandle;
@@ -181,10 +181,10 @@ void THttpCallArg::SetWSHandle(TNamed *handle)
 /// takeout websocket handle with HTTP call
 /// can be done only once
 
-TNamed *THttpCallArg::TakeWSHandle()
+THttpWSEngine *THttpCallArg::TakeWSHandle()
 {
-   TNamed *res = fWSHandle;
-   fWSHandle = 0;
+   THttpWSEngine *res = fWSHandle;
+   fWSHandle = nullptr;
    return res;
 }
 
diff --git a/net/http/src/THttpLongPollEngine.cxx b/net/http/src/THttpLongPollEngine.cxx
index 730f41eb264..b0465123eb9 100644
--- a/net/http/src/THttpLongPollEngine.cxx
+++ b/net/http/src/THttpLongPollEngine.cxx
@@ -79,17 +79,17 @@ void THttpLongPollEngine::SendCharStar(const char *buf)
 /// function called in the user code before processing correspondent websocket data
 /// returns kTRUE when user should ignore such http request - it is for internal use
 
-Bool_t THttpLongPollEngine::PreviewData(THttpCallArg *arg)
+Bool_t THttpLongPollEngine::PreviewData(THttpCallArg &arg)
 {
-   if (!strstr(arg->GetQuery(), "&dummy")) {
+   if (!strstr(arg.GetQuery(), "&dummy")) {
       // this is normal request, deliver and process it as any other
       // put dummy content, it can be overwritten in the future
-      arg->SetContentType("text/plain");
-      arg->SetContent(gLongPollNope);
+      arg.SetContentType("text/plain");
+      arg.SetContent(gLongPollNope);
       return kFALSE;
    }
 
-   if (arg == fPoll) {
+   if (&arg == fPoll) {
       Error("PreviewData", "NEVER SHOULD HAPPEN");
       gSystem->Exit(12);
    }
@@ -104,12 +104,12 @@ Bool_t THttpLongPollEngine::PreviewData(THttpCallArg *arg)
    }
 
    if (fBuf.size() > 0) {
-      arg->SetContentType("text/plain");
-      arg->SetContent(fBuf.front().c_str());
+      arg.SetContentType("text/plain");
+      arg.SetContent(fBuf.front().c_str());
       fBuf.pop_front();
    } else {
-      arg->SetPostponed();
-      fPoll = arg;
+      arg.SetPostponed();
+      fPoll = &arg;
    }
 
    // if arguments has "&dummy" string, user should not process it
@@ -120,12 +120,12 @@ Bool_t THttpLongPollEngine::PreviewData(THttpCallArg *arg)
 /// Normally requests from client does not replied directly
 /// Therefore one can use it to send data with it
 
-void THttpLongPollEngine::PostProcess(THttpCallArg *arg)
+void THttpLongPollEngine::PostProcess(THttpCallArg &arg)
 {
-   if ((fBuf.size() > 0) && arg->IsContentType("text/plain") &&
-       (arg->GetContentLength() == (Long_t)strlen(gLongPollNope)) &&
-       (strcmp((const char *)arg->GetContent(), gLongPollNope) == 0)) {
-      arg->SetContent(fBuf.front().c_str());
+   if ((fBuf.size() > 0) && arg.IsContentType("text/plain") &&
+       (arg.GetContentLength() == (Long_t)strlen(gLongPollNope)) &&
+       (strcmp((const char *)arg.GetContent(), gLongPollNope) == 0)) {
+      arg.SetContent(fBuf.front().c_str());
       fBuf.pop_front();
    }
 }
diff --git a/net/http/src/THttpServer.cxx b/net/http/src/THttpServer.cxx
index ae2b012fc32..4c325ff27b2 100644
--- a/net/http/src/THttpServer.cxx
+++ b/net/http/src/THttpServer.cxx
@@ -828,7 +828,7 @@ void THttpServer::ProcessRequest(THttpCallArg *arg)
          // if accepted, reply with connection id, which must be used in the following communications
          arg->SetMethod("WS_CONNECT");
 
-         THttpLongPollEngine *handle = new THttpLongPollEngine("longpoll", arg->fPathName.Data());
+         THttpLongPollEngine *handle = new THttpLongPollEngine();
          arg->SetWSId(handle->GetId());
 
          if (handler->HandleWS(arg)) {
diff --git a/net/http/src/THttpWSEngine.cxx b/net/http/src/THttpWSEngine.cxx
index 03c4b5cf21b..2da1115dd50 100644
--- a/net/http/src/THttpWSEngine.cxx
+++ b/net/http/src/THttpWSEngine.cxx
@@ -20,29 +20,29 @@
 //                                                                      //
 //////////////////////////////////////////////////////////////////////////
 
-
-ClassImp(THttpWSEngine);
-
 ////////////////////////////////////////////////////////////////////////////////
-/// normal constructor
+/// Envelope for sending string via the websocket
 
-THttpWSEngine::THttpWSEngine(const char *name, const char *title)
-   : TNamed(name, title)
+void THttpWSEngine::SendCharStar(const char *str)
 {
+   if (str)
+      Send(str, strlen(str));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-/// destructor
+/// Method should be invoked before processing data coming from websocket
+/// If method returns kTRUE, this is data is processed internally and
+/// not dedicated for further usage
 
-THttpWSEngine::~THttpWSEngine()
+Bool_t THttpWSEngine::PreviewData(THttpCallArg &)
 {
+   return kFALSE;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-/// Envelope for sending string via the websocket
+/// Method invoked after user process data received via websocket
+/// Normally request is no longer usable after that
 
-void THttpWSEngine::SendCharStar(const char *str)
+void THttpWSEngine::PostProcess(THttpCallArg &)
 {
-   if (str) Send(str, strlen(str));
 }
-
diff --git a/net/http/src/THttpWSHandler.cxx b/net/http/src/THttpWSHandler.cxx
index 8412cec943e..0703d1cea8d 100644
--- a/net/http/src/THttpWSHandler.cxx
+++ b/net/http/src/THttpWSHandler.cxx
@@ -14,7 +14,6 @@
 #include "THttpWSEngine.h"
 #include "THttpCallArg.h"
 
-
 /////////////////////////////////////////////////////////////////////////
 ///
 /// THttpWSHandler
@@ -65,62 +64,94 @@ ClassImp(THttpWSHandler);
 ////////////////////////////////////////////////////////////////////////////////
 /// normal constructor
 
-THttpWSHandler::THttpWSHandler(const char *name, const char *title) :
-   TNamed(name, title), fEngines()
+THttpWSHandler::THttpWSHandler(const char *name, const char *title) : TNamed(name, title), fEngines()
 {
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// destructor
+/// Delete all websockets handles
+
 THttpWSHandler::~THttpWSHandler()
 {
-   TIter iter(&fEngines);
-   THttpWSEngine *engine = 0;
-
-   while ((engine = (THttpWSEngine *)iter()) != 0)
+   for (auto iter = fEngines.begin(); iter != fEngines.end(); iter++) {
+      THttpWSEngine *engine = *iter;
       engine->ClearHandle();
+      delete engine;
+   }
 
-   fEngines.Delete();
+   fEngines.clear();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Return websocket id with given sequential number
+/// Number of websockets return with GetNumWS() method
 
-THttpWSEngine *THttpWSHandler::FindEngine(UInt_t id) const
+UInt_t THttpWSHandler::GetWS(Int_t num) const
 {
-   TIter iter(&fEngines);
-   THttpWSEngine *engine = 0;
+   auto iter = fEngines.begin() + num;
+   return (*iter)->GetId();
+}
 
-   while ((engine = (THttpWSEngine *)iter()) != 0) {
-      if (engine->GetId() == id) return engine;
-   }
+////////////////////////////////////////////////////////////////////////////////
+/// Find websocket connection handle with given id
+
+THttpWSEngine *THttpWSHandler::FindEngine(UInt_t wsid) const
+{
+   for (auto iter = fEngines.begin(); iter != fEngines.end(); iter++)
+      if ((*iter)->GetId() == wsid)
+         return *iter;
 
-   return 0;
+   return nullptr;
 }
 
-Bool_t THttpWSHandler::HandleWS(THttpCallArg *arg)
+////////////////////////////////////////////////////////////////////////////////
+/// Remove and destroy WS connection
+
+void THttpWSHandler::RemoveEngine(THttpWSEngine *engine)
 {
-   if (!arg->GetWSId()) return ProcessWS(arg);
+   for (auto iter = fEngines.begin(); iter != fEngines.end(); iter++)
+      if (*iter == engine) {
+         fEngines.erase(iter);
+         break;
+      }
+
+   delete engine;
+}
 
-   THttpWSEngine* engine = FindEngine(arg->GetWSId());
+////////////////////////////////////////////////////////////////////////////////
+/// Process request to websocket
+/// Different kind of requests coded into THttpCallArg::Method
+///  "WS_CONNECT" - connection request
+///  "WS_READY" - connection ready
+///  "WS_CLOSE" - connection closed
+/// All other are normal data, which are delivered to users
 
-   if (arg->IsMethod("WS_CONNECT")) {
-      // accept all requests, in future one could limit number of connections
+Bool_t THttpWSHandler::HandleWS(THttpCallArg *arg)
+{
+   if (!arg->GetWSId())
       return ProcessWS(arg);
-   }
+
+   // normally here one accept or reject connection requests
+   if (arg->IsMethod("WS_CONNECT"))
+      return ProcessWS(arg);
+
+   THttpWSEngine *engine = FindEngine(arg->GetWSId());
 
    if (arg->IsMethod("WS_READY")) {
 
       if (engine) {
-         Error("HandleWS","WS engine with similar id exists %u\n", arg->GetWSId());
-         fEngines.Remove(engine);
-         delete engine;
+         Error("HandleWS", "WS engine with similar id exists %u\n", arg->GetWSId());
+         RemoveEngine(engine);
       }
 
-      THttpWSEngine *wshandle = dynamic_cast<THttpWSEngine *>(arg->TakeWSHandle());
+      engine = arg->TakeWSHandle();
 
-      fEngines.Add(wshandle);
+      fEngines.push_back(engine);
 
       if (!ProcessWS(arg)) {
          // if connection refused, remove engine again
-         fEngines.Remove(wshandle);
-         delete wshandle;
+         RemoveEngine(engine);
          return kFALSE;
       }
 
@@ -132,42 +163,52 @@ Bool_t THttpWSHandler::HandleWS(THttpCallArg *arg)
 
       if (engine) {
          engine->ClearHandle();
-         fEngines.Remove(engine);
-         delete engine;
+         RemoveEngine(engine);
       }
 
       return ProcessWS(arg);
    }
 
-   if (engine && engine->PreviewData(arg)) return kTRUE;
+   if (engine && engine->PreviewData(*arg))
+      return kTRUE;
 
    Bool_t res = ProcessWS(arg);
 
-   if (engine) engine->PostProcess(arg);
+   if (engine)
+      engine->PostProcess(*arg);
 
    return res;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Close connection with given websocket id
+
 void THttpWSHandler::CloseWS(UInt_t wsid)
 {
-   THttpWSEngine* engine = FindEngine(wsid);
+   THttpWSEngine *engine = FindEngine(wsid);
 
-   if (engine) {
-      fEngines.Remove(engine);
-      delete engine;
-   }
+   if (engine)
+      RemoveEngine(engine);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Send binary data via given websocket id
+
 void THttpWSHandler::SendWS(UInt_t wsid, const void *buf, int len)
 {
-   THttpWSEngine* engine = FindEngine(wsid);
+   THttpWSEngine *engine = FindEngine(wsid);
 
-   if (engine) engine->Send(buf, len);
+   if (engine)
+      engine->Send(buf, len);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Send string via given websocket id
+
 void THttpWSHandler::SendCharStarWS(UInt_t wsid, const char *str)
 {
-   THttpWSEngine* engine = FindEngine(wsid);
+   THttpWSEngine *engine = FindEngine(wsid);
 
-   if (engine) engine->SendCharStar(str);
+   if (engine)
+      engine->SendCharStar(str);
 }
-- 
GitLab