Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RWebWindow.hxx
Go to the documentation of this file.
1 /// \file ROOT/RWebWindow.hxx
2 /// \ingroup WebGui ROOT7
3 /// \author Sergey Linev <s.linev@gsi.de>
4 /// \date 2017-10-16
5 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6 /// is welcome!
7 
8 /*************************************************************************
9  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10  * All rights reserved. *
11  * *
12  * For the licensing terms see $ROOTSYS/LICENSE. *
13  * For the list of contributors see $ROOTSYS/README/CREDITS. *
14  *************************************************************************/
15 
16 #ifndef ROOT7_RWebWindow
17 #define ROOT7_RWebWindow
18 
20 
21 #include <memory>
22 #include <vector>
23 #include <string>
24 #include <queue>
25 #include <map>
26 #include <functional>
27 #include <mutex>
28 #include <thread>
29 #include <chrono>
30 
31 class THttpCallArg;
32 class THttpServer;
33 
34 namespace ROOT {
35 namespace Experimental {
36 
37 
38 /// function signature for connect/disconnect call-backs
39 /// argument is connection id
40 using WebWindowConnectCallback_t = std::function<void(unsigned)>;
41 
42 /// function signature for call-backs from the window clients
43 /// first argument is connection id, second is received data
44 using WebWindowDataCallback_t = std::function<void(unsigned, const std::string &)>;
45 
46 /// function signature for waiting call-backs
47 /// Such callback used when calling thread need to waits for some special data,
48 /// but wants to run application event loop
49 /// As argument, spent time in second will be provided
50 /// Waiting will be performed until function returns non-zero value
51 using WebWindowWaitFunc_t = std::function<int(double)>;
52 
53 class RWebWindowsManager;
54 class RWebWindowWSHandler;
55 
56 class RWebWindow {
57 
58  friend class RWebWindowsManager;
59  friend class RWebWindowWSHandler;
60  friend class RWebDisplayHandle;
61 
62 private:
63  using timestamp_t = std::chrono::time_point<std::chrono::system_clock>;
64 
65  struct QueueItem {
66  int fChID{1}; ///<! channel
67  bool fText{true}; ///<! is text data
68  std::string fData; ///<! text or binary data
69  QueueItem(int chid, bool txt, std::string &&data) : fChID(chid), fText(txt), fData(data) {}
70  };
71 
72  struct WebConn {
73  unsigned fConnId{0}; ///<! connection id (unique inside the window)
74  bool fBatchMode{false}; ///<! indicate if connection represent batch job
75  std::string fKey; ///<! key value supplied to the window (when exists)
76  std::unique_ptr<RWebDisplayHandle> fDisplayHandle; ///<! handle assigned with started web display (when exists)
77  std::shared_ptr<THttpCallArg> fHold; ///<! request used to hold headless browser
78  timestamp_t fSendStamp; ///<! last server operation, always used from window thread
79  bool fActive{false}; ///<! flag indicates if connection is active
80  unsigned fWSId{0}; ///<! websocket id
81  int fReady{0}; ///<! 0 - not ready, 1..9 - interim, 10 - done
82  mutable std::mutex fMutex; ///<! mutex must be used to protect all following data
83  timestamp_t fRecvStamp; ///<! last receive operation, protected with connection mutex
84  int fRecvCount{0}; ///<! number of received packets, should return back with next sending
85  int fSendCredits{0}; ///<! how many send operation can be performed without confirmation from other side
86  int fClientCredits{0}; ///<! number of credits received from client
87  bool fDoingSend{false}; ///<! true when performing send operation
88  std::queue<QueueItem> fQueue; ///<! output queue
89  std::map<int,std::shared_ptr<RWebWindow>> fEmbed; ///<! map of embed window for that connection, key value is channel id
90  WebConn() = default;
91  WebConn(unsigned connid) : fConnId(connid) {}
92  WebConn(unsigned connid, unsigned wsid) : fConnId(connid), fActive(true), fWSId(wsid) {}
93  WebConn(unsigned connid, bool batch_mode, const std::string &key)
94  : fConnId(connid), fBatchMode(batch_mode), fKey(key)
95  {
96  ResetStamps();
97  }
98  ~WebConn();
99 
100  void ResetStamps() { fSendStamp = fRecvStamp = std::chrono::system_clock::now(); }
101  };
102 
103  enum EQueueEntryKind { kind_None, kind_Connect, kind_Data, kind_Disconnect };
104 
105  struct QueueEntry {
106  unsigned fConnId{0}; ///<! connection id
107  EQueueEntryKind fKind{kind_None}; ///<! kind of data
108  std::string fData; ///<! data for given connection
109  QueueEntry() = default;
110  QueueEntry(unsigned connid, EQueueEntryKind kind, std::string &&data) : fConnId(connid), fKind(kind), fData(data) {}
111  };
112 
113  using ConnectionsList_t = std::vector<std::shared_ptr<WebConn>>;
114 
115  std::shared_ptr<RWebWindowsManager> fMgr; ///<! display manager
116  std::shared_ptr<RWebWindow> fMaster; ///<! master window where this window is embeded
117  unsigned fMasterConnId{0}; ///<! master connection id
118  int fMasterChannel{-1}; ///<! channel id in the master window
119  std::string fDefaultPage; ///<! HTML page (or file name) returned when window URL is opened
120  std::string fPanelName; ///<! panel name which should be shown in the window
121  unsigned fId{0}; ///<! unique identifier
122  bool fProcessMT{false}; ///<! if window event processing performed in dedicated thread
123  bool fSendMT{false}; ///<! true is special threads should be used for sending data
124  std::shared_ptr<RWebWindowWSHandler> fWSHandler; ///<! specialize websocket handler for all incoming connections
125  unsigned fConnCnt{0}; ///<! counter of new connections to assign ids
126  ConnectionsList_t fPendingConn; ///<! list of pending connection with pre-assigned keys
127  ConnectionsList_t fConn; ///<! list of all accepted connections
128  mutable std::mutex fConnMutex; ///<! mutex used to protect connection list
129  unsigned fConnLimit{1}; ///<! number of allowed active connections
130  bool fNativeOnlyConn{false}; ///<! only native connection are allowed, created by Show() method
131  unsigned fMaxQueueLength{10}; ///<! maximal number of queue entries
132  WebWindowConnectCallback_t fConnCallback; ///<! callback for connect event
133  WebWindowDataCallback_t fDataCallback; ///<! main callback when data over channel 1 is arrived
134  WebWindowConnectCallback_t fDisconnCallback; ///<! callback for disconnect event
135  std::thread::id fCallbacksThrdId; ///<! thread id where callbacks should be invoked
136  bool fCallbacksThrdIdSet{false}; ///<! flag indicating that thread id is assigned
137  std::queue<QueueEntry> fInputQueue; ///<! input queue for all callbacks
138  std::mutex fInputQueueMutex; ///<! mutex to protect input queue
139  unsigned fWidth{0}; ///<! initial window width when displayed
140  unsigned fHeight{0}; ///<! initial window height when displayed
141  float fOperationTmout{50.}; ///<! timeout in seconds to perform synchronous operation, default 50s
142  std::string fClientVersion; ///<! configured client version, used as prefix in scripts URL
143  std::string fProtocolFileName; ///<! local file where communication protocol will be written
144  int fProtocolCnt{-1}; ///<! counter for protocol recording
145  unsigned fProtocolConnId{0}; ///<! connection id, which is used for writing protocol
146  std::string fProtocolPrefix; ///<! prefix for created files names
147  std::string fProtocol; ///<! protocol
148  std::string fUserArgs; ///<! arbitrary JSON code, which is accessible via conn.getUserArgs() method
149 
150  std::shared_ptr<RWebWindowWSHandler> CreateWSHandler(std::shared_ptr<RWebWindowsManager> mgr, unsigned id, double tmout);
151 
152  bool ProcessWS(THttpCallArg &arg);
153 
154  void CompleteWSSend(unsigned wsid);
155 
156  ConnectionsList_t GetConnections(unsigned connid = 0, bool only_active = false) const;
157 
158  std::shared_ptr<WebConn> FindOrCreateConnection(unsigned wsid, bool make_new, const char *query);
159 
160  std::shared_ptr<WebConn> FindConnection(unsigned wsid) { return FindOrCreateConnection(wsid, false, nullptr); }
161 
162  std::shared_ptr<WebConn> RemoveConnection(unsigned wsid);
163 
164  std::string _MakeSendHeader(std::shared_ptr<WebConn> &conn, bool txt, const std::string &data, int chid);
165 
166  void ProvideQueueEntry(unsigned connid, EQueueEntryKind kind, std::string &&arg);
167 
168  void InvokeCallbacks(bool force = false);
169 
170  void SubmitData(unsigned connid, bool txt, std::string &&data, int chid = 1);
171 
172  bool CheckDataToSend(std::shared_ptr<WebConn> &conn);
173 
174  void CheckDataToSend(bool only_once = false);
175 
176  bool HasKey(const std::string &key) const;
177 
178  void CheckPendingConnections();
179 
180  void CheckInactiveConnections();
181 
182  unsigned AddDisplayHandle(bool batch_mode, const std::string &key, std::unique_ptr<RWebDisplayHandle> &handle);
183 
184  unsigned AddEmbedWindow(std::shared_ptr<RWebWindow> window, int channel);
185 
186  void RemoveEmbedWindow(unsigned connid, int channel);
187 
188  bool ProcessBatchHolder(std::shared_ptr<THttpCallArg> &arg);
189 
190  void AssignCallbackThreadId();
191 
192 public:
193 
194  RWebWindow();
195 
196  ~RWebWindow();
197 
198  /// Returns ID for the window - unique inside window manager
199  unsigned GetId() const { return fId; }
200 
201  /// Set content of default window HTML page
202  /// This page returns when URL address of the window will be requested
203  /// Either HTML code or file name in the form "file:/home/user/data/file.htm"
204  /// One also can using default locations like "file:rootui5sys/canv/canvas.html"
205  void SetDefaultPage(const std::string &page) { fDefaultPage = page; }
206 
207  void SetPanelName(const std::string &name);
208 
209  /// Set window geometry. Will be applied if supported by used web display (like CEF or Chromium)
210  void SetGeometry(unsigned width, unsigned height)
211  {
212  fWidth = width;
213  fHeight = height;
214  }
215 
216  /////////////////////////////////////////////////////////////////////////
217  /// returns configured window width (0 - default)
218  /// actual window width can be different
219  unsigned GetWidth() const { return fWidth; }
220 
221  /////////////////////////////////////////////////////////////////////////
222  /// returns configured window height (0 - default)
223  unsigned GetHeight() const { return fHeight; }
224 
225  /////////////////////////////////////////////////////////////////////////
226  /// Configure maximal number of allowed connections - 0 is unlimited
227  /// Will not affect already existing connections
228  /// Default is 1 - the only client is allowed
229  void SetConnLimit(unsigned lmt = 0) { fConnLimit = lmt; }
230 
231  /////////////////////////////////////////////////////////////////////////
232  /// returns configured connections limit (0 - default)
233  unsigned GetConnLimit() const { return fConnLimit; }
234 
235  /////////////////////////////////////////////////////////////////////////
236  /// configures maximal queue length of data which can be held by window
237  void SetMaxQueueLength(unsigned len = 10) { fMaxQueueLength = len; }
238 
239  /////////////////////////////////////////////////////////////////////////
240  /// Return maximal queue length of data which can be held by window
241  unsigned GetMaxQueueLength() const { return fMaxQueueLength; }
242 
243  /////////////////////////////////////////////////////////////////////////
244  /// configures that only native (own-created) connections are allowed
245  void SetNativeOnlyConn(bool on = true) { fNativeOnlyConn = on; }
246 
247  /////////////////////////////////////////////////////////////////////////
248  /// returns true if only native (own-created) connections are allowed
249  bool IsNativeOnlyConn() const { return fNativeOnlyConn; }
250 
251  void SetClientVersion(const std::string &vers);
252 
253  std::string GetClientVersion() const;
254 
255  void SetUserArgs(const std::string &args);
256 
257  std::string GetUserArgs() const;
258 
259  int NumConnections(bool with_pending = false) const;
260 
261  unsigned GetConnectionId(int num = 0) const;
262 
263  bool HasConnection(unsigned connid = 0, bool only_active = true) const;
264 
265  void CloseConnections();
266 
267  void CloseConnection(unsigned connid);
268 
269  /// Returns timeout for synchronous WebWindow operations
270  float GetOperationTmout() const { return fOperationTmout; }
271 
272  /// Set timeout for synchronous WebWindow operations
273  void SetOperationTmout(float tm = 50.) { fOperationTmout = tm; }
274 
275  std::string GetUrl(bool remote = true);
276 
277  THttpServer *GetServer();
278 
279  void Sync();
280 
281  void Run(double tm = 0.);
282 
283  unsigned Show(const RWebDisplayArgs &args = "");
284 
285  unsigned GetDisplayConnection() const;
286 
287  /// Returns true when window was shown at least once
288  bool IsShown() const { return GetDisplayConnection() != 0; }
289 
290  unsigned MakeBatch(bool create_new = false, const RWebDisplayArgs &args = "");
291 
292  unsigned FindBatch();
293 
294  bool CanSend(unsigned connid, bool direct = true) const;
295 
296  int GetSendQueueLength(unsigned connid) const;
297 
298  void Send(unsigned connid, const std::string &data);
299 
300  void SendBinary(unsigned connid, const void *data, std::size_t len);
301 
302  void SendBinary(unsigned connid, std::string &&data);
303 
304  void RecordData(const std::string &fname = "protocol.json", const std::string &fprefix = "");
305 
306  std::string GetAddr() const;
307 
308  std::string GetRelativeAddr(const std::shared_ptr<RWebWindow> &win) const;
309 
310  void SetCallBacks(WebWindowConnectCallback_t conn, WebWindowDataCallback_t data, WebWindowConnectCallback_t disconn = nullptr);
311 
312  void SetConnectCallBack(WebWindowConnectCallback_t func);
313 
314  void SetDataCallBack(WebWindowDataCallback_t func);
315 
316  void SetDisconnectCallBack(WebWindowConnectCallback_t func);
317 
318  int WaitFor(WebWindowWaitFunc_t check);
319 
320  int WaitForTimed(WebWindowWaitFunc_t check);
321 
322  int WaitForTimed(WebWindowWaitFunc_t check, double duration);
323 
324  void TerminateROOT();
325 
326  static std::shared_ptr<RWebWindow> Create();
327 
328  static unsigned ShowWindow(std::shared_ptr<RWebWindow> window, const RWebDisplayArgs &args = "");
329 
330 };
331 
332 } // namespace Experimental
333 } // namespace ROOT
334 
335 #endif