Logo ROOT   6.14/05
Reference Guide
THttpWSHandler.cxx
Go to the documentation of this file.
1 // $Id$
2 // Author: Sergey Linev 20/10/2017
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "THttpWSHandler.h"
13 
14 #include "THttpWSEngine.h"
15 #include "THttpCallArg.h"
16 
17 /////////////////////////////////////////////////////////////////////////
18 ///
19 /// THttpWSHandler
20 ///
21 /// Class for user-side handling of websocket with THttpServer
22 /// 1. Create derived from THttpWSHandler class and implement
23 /// ProcessWS() method, where all web sockets request handled.
24 /// 2. Register instance of derived class to running THttpServer
25 ///
26 /// TUserWSHandler *handler = new TUserWSHandler("name1","title");
27 /// THttpServer *server = new THttpServer("http:8090");
28 /// server->Register("/subfolder", handler)
29 ///
30 /// 3. Now server can accept web socket connection from outside.
31 /// For instance, from JavaScirpt one can connect to it with code:
32 ///
33 /// var ws = new WebSocket("ws://hostname:8090/subfolder/name1/root.websocket")
34 ///
35 /// 4. In the ProcessWS(THttpCallArg *arg) method following code should be implemented:
36 ///
37 /// if (arg->IsMethod("WS_CONNECT")) {
38 /// return true; // to accept incoming request
39 /// }
40 ///
41 /// if (arg->IsMethod("WS_READY")) {
42 /// fWSId = arg->GetWSId(); // fWSId should be member of the user class
43 /// return true; // connection established
44 /// }
45 ///
46 /// if (arg->IsMethod("WS_CLOSE")) {
47 /// fWSId = 0;
48 /// return true; // confirm close of socket
49 /// }
50 ///
51 /// if (arg->IsMethod("WS_DATA")) {
52 /// // received data stored as POST data
53 /// std::string str((const char *)arg->GetPostData(), arg->GetPostDataLength());
54 /// std::cout << "got string " << str << std::endl;
55 /// // immediately send data back using websocket id
56 /// SendCharStarWS(fWSId, "our reply");
57 /// return true;
58 /// }
59 ///
60 ///////////////////////////////////////////////////////////////////////////
61 
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 /// normal constructor
66 
67 THttpWSHandler::THttpWSHandler(const char *name, const char *title) : TNamed(name, title), fEngines()
68 {
69 }
70 
71 ////////////////////////////////////////////////////////////////////////////////
72 /// destructor
73 /// Delete all websockets handles
74 
76 {
77 }
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 /// Return websocket id with given sequential number
81 /// Number of websockets return with GetNumWS() method
82 
84 {
85  auto iter = fEngines.begin() + num;
86  return (*iter)->GetId();
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 /// Find websocket connection handle with given id
91 
93 {
94  for (auto &eng : fEngines)
95  if (eng->GetId() == wsid)
96  return eng.get();
97 
98  return nullptr;
99 }
100 
101 ////////////////////////////////////////////////////////////////////////////////
102 /// Remove and destroy WS connection
103 
105 {
106  for (auto iter = fEngines.begin(); iter != fEngines.end(); iter++)
107  if (iter->get() == engine) {
108  fEngines.erase(iter);
109  break;
110  }
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////
114 /// Process request to websocket
115 /// Different kind of requests coded into THttpCallArg::Method
116 /// "WS_CONNECT" - connection request
117 /// "WS_READY" - connection ready
118 /// "WS_CLOSE" - connection closed
119 /// All other are normal data, which are delivered to users
120 
121 Bool_t THttpWSHandler::HandleWS(std::shared_ptr<THttpCallArg> &arg)
122 {
123  if (!arg->GetWSId())
124  return ProcessWS(arg.get());
125 
126  // normally here one accept or reject connection requests
127  if (arg->IsMethod("WS_CONNECT"))
128  return ProcessWS(arg.get());
129 
130  THttpWSEngine *engine = FindEngine(arg->GetWSId());
131 
132  if (arg->IsMethod("WS_READY")) {
133 
134  if (engine) {
135  Error("HandleWS", "WS engine with similar id exists %u", arg->GetWSId());
136  RemoveEngine(engine);
137  }
138 
139  auto handle = arg->TakeWSEngine();
140  engine = handle.get();
141  fEngines.push_back(std::move(handle));
142 
143  if (!ProcessWS(arg.get())) {
144  // if connection refused, remove engine again
145  RemoveEngine(engine);
146  return kFALSE;
147  }
148 
149  return kTRUE;
150  }
151 
152  if (arg->IsMethod("WS_CLOSE")) {
153  // connection is closed, one can remove handle
154 
155  if (engine) {
156  engine->ClearHandle();
157  RemoveEngine(engine);
158  }
159 
160  return ProcessWS(arg.get());
161  }
162 
163  if (engine && engine->PreviewData(arg))
164  return kTRUE;
165 
166  Bool_t res = ProcessWS(arg.get());
167 
168  if (engine)
169  engine->PostProcess(arg);
170 
171  return res;
172 }
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 /// Close connection with given websocket id
176 
178 {
179  THttpWSEngine *engine = FindEngine(wsid);
180 
181  if (engine)
182  RemoveEngine(engine);
183 }
184 
185 ////////////////////////////////////////////////////////////////////////////////
186 /// Send binary data via given websocket id
187 
188 void THttpWSHandler::SendWS(UInt_t wsid, const void *buf, int len)
189 {
190  THttpWSEngine *engine = FindEngine(wsid);
191 
192  if (engine)
193  engine->Send(buf, len);
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 /// Send binary data with binary data via given websocket id
198 
199 void THttpWSHandler::SendHeaderWS(UInt_t wsid, const char *hdr, const void *buf, int len)
200 {
201  THttpWSEngine *engine = FindEngine(wsid);
202 
203  if (engine)
204  engine->SendHeader(hdr, buf, len);
205 }
206 
207 ////////////////////////////////////////////////////////////////////////////////
208 /// Send string via given websocket id
209 
210 void THttpWSHandler::SendCharStarWS(UInt_t wsid, const char *str)
211 {
212  THttpWSEngine *engine = FindEngine(wsid);
213 
214  if (engine)
215  engine->SendCharStar(str);
216 }
void SendWS(UInt_t wsid, const void *buf, int len)
Send binary data via given websocket id.
Bool_t HandleWS(std::shared_ptr< THttpCallArg > &arg)
Process request to websocket Different kind of requests coded into THttpCallArg::Method "WS_CONNECT" ...
virtual ~THttpWSHandler()
destructor Delete all websockets handles
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
virtual void Send(const void *buf, int len)=0
THttpWSEngine * FindEngine(UInt_t id) const
Find websocket connection handle with given id.
virtual void SendCharStar(const char *str)
Envelope for sending string via the websocket.
virtual void SendHeader(const char *hdr, const void *buf, int len)=0
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
void CloseWS(UInt_t wsid)
Close connection with given websocket id.
void SendCharStarWS(UInt_t wsid, const char *str)
Send string via given websocket id.
void SendHeaderWS(UInt_t wsid, const char *hdr, const void *buf, int len)
Send binary data with binary data via given websocket id.
UInt_t GetWS(Int_t num=0) const
Return websocket id with given sequential number Number of websockets return with GetNumWS() method...
virtual void PostProcess(std::shared_ptr< THttpCallArg > &arg)
Method invoked after user process data received via websocket Normally request is no longer usable af...
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
std::vector< std::shared_ptr< THttpWSEngine > > fEngines
! list of active WS engines (connections)
const Bool_t kFALSE
Definition: RtypesCore.h:88
void RemoveEngine(THttpWSEngine *engine)
Remove and destroy WS connection.
#define ClassImp(name)
Definition: Rtypes.h:359
virtual Bool_t ProcessWS(THttpCallArg *arg)=0
virtual Bool_t PreviewData(std::shared_ptr< THttpCallArg > &arg)
Method should be invoked before processing data coming from websocket If method returns kTRUE...
virtual void ClearHandle()=0
THttpWSHandler(const char *name, const char *title)
THttpWSHandler.
const Bool_t kTRUE
Definition: RtypesCore.h:87
char name[80]
Definition: TGX11.cxx:109