Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-03 10:21:23

0001 // Author: Sergey Linev <s.linev@gsi.de>
0002 // Date: 2017-10-16
0003 // Warning: This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!
0004 
0005 /*************************************************************************
0006  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
0007  * All rights reserved.                                                  *
0008  *                                                                       *
0009  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0010  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0011  *************************************************************************/
0012 
0013 #ifndef ROOT7_RWebWindow
0014 #define ROOT7_RWebWindow
0015 
0016 #include <ROOT/RWebDisplayHandle.hxx>
0017 
0018 #include "ROOT/RConfig.hxx"
0019 
0020 #include <memory>
0021 #include <vector>
0022 #include <string>
0023 #include <queue>
0024 #include <map>
0025 #include <functional>
0026 #include <mutex>
0027 #include <thread>
0028 #include <chrono>
0029 
0030 class THttpCallArg;
0031 class THttpServer;
0032 
0033 namespace ROOT {
0034 
0035 /// function signature for connect/disconnect call-backs
0036 /// argument is connection id
0037 using WebWindowConnectCallback_t = std::function<void(unsigned)>;
0038 
0039 /// function signature for call-backs from the window clients
0040 /// first argument is connection id, second is received data
0041 using WebWindowDataCallback_t = std::function<void(unsigned, const std::string &)>;
0042 
0043 /// function signature for waiting call-backs
0044 /// Such callback used when calling thread need to waits for some special data,
0045 /// but wants to run application event loop
0046 /// As argument, spent time in second will be provided
0047 /// Waiting will be performed until function returns non-zero value
0048 using WebWindowWaitFunc_t = std::function<int(double)>;
0049 
0050 class RFileDialog;
0051 class RWebWindowsManager;
0052 class RWebWindowWSHandler;
0053 
0054 class RWebWindow {
0055 
0056    friend class RWebWindowsManager;
0057    friend class RWebWindowWSHandler;
0058    friend class RWebDisplayHandle;
0059    friend class RFileDialog;
0060 
0061 private:
0062    using timestamp_t = std::chrono::time_point<std::chrono::system_clock>;
0063 
0064    struct QueueItem {
0065       int fChID{1};      ///<! channel
0066       bool fText{true};  ///<! is text data
0067       std::string fData; ///<! text or binary data
0068       QueueItem(int chid, bool txt, std::string &&data) : fChID(chid), fText(txt), fData(data) {}
0069    };
0070 
0071    struct WebConn {
0072       unsigned fConnId{0};                 ///<! connection id (unique inside the window)
0073       bool fHeadlessMode{false};           ///<! indicate if connection represent batch job
0074       bool fWasFirst{false};               ///<! indicate if this was first connection, will be reinjected also on first place
0075       bool fWasEstablished{false};         ///<! indicate if connection was established at least once
0076       std::string fKey;                    ///<! key value supplied to the window (when exists)
0077       int fKeyUsed{0};                     ///<! key value used to verify connection
0078       std::string fNewKey;                 ///<! new key if connection request reload
0079       std::unique_ptr<RWebDisplayHandle> fDisplayHandle;  ///<! handle assigned with started web display (when exists)
0080       std::shared_ptr<THttpCallArg> fHold; ///<! request used to hold headless browser
0081       timestamp_t fSendStamp;              ///<! last server operation, always used from window thread
0082       bool fActive{false};                 ///<! flag indicates if connection is active
0083       unsigned fWSId{0};                   ///<! websocket id
0084       int fReady{0};                       ///<! 0 - not ready, 1..9 - interim, 10 - done
0085       mutable std::mutex fMutex;           ///<! mutex must be used to protect all following data
0086       timestamp_t fRecvStamp;              ///<! last receive operation, protected with connection mutex
0087       int fRecvCount{0};                   ///<! number of received packets, should return back with next sending
0088       int fSendCredits{0};                 ///<! how many send operation can be performed without confirmation from other side
0089       int fClientCredits{0};               ///<! number of credits received from client
0090       bool fDoingSend{false};              ///<! true when performing send operation
0091       unsigned long fRecvSeq{0};           ///<! sequence id of last received packet
0092       unsigned long fSendSeq{1};           ///<! sequence id of last send packet
0093       std::queue<QueueItem> fQueue;        ///<! output queue
0094       std::map<int,std::shared_ptr<RWebWindow>> fEmbed; ///<! map of embed window for that connection, key value is channel id
0095       WebConn() = default;
0096       WebConn(unsigned connid) : fConnId(connid) {}
0097       WebConn(unsigned connid, unsigned wsid) : fConnId(connid), fActive(true), fWSId(wsid) {}
0098       WebConn(unsigned connid, bool headless_mode, const std::string &key)
0099          : fConnId(connid), fHeadlessMode(headless_mode), fKey(key)
0100       {
0101          ResetStamps();
0102       }
0103       ~WebConn();
0104 
0105       void ResetStamps() { fSendStamp = fRecvStamp = std::chrono::system_clock::now(); }
0106 
0107       void ResetData()
0108       {
0109          fActive = false;
0110          fWSId = 0;
0111          fReady = 0;
0112          fDoingSend = false;
0113          fSendCredits = 0;
0114          fClientCredits = 0;
0115          fRecvSeq = 0;
0116          fSendSeq = 1;
0117          while (!fQueue.empty())
0118             fQueue.pop();
0119       }
0120    };
0121 
0122    struct MasterConn {
0123       unsigned connid{0};
0124       int channel{-1};
0125       MasterConn(unsigned _connid, int _channel) : connid(_connid), channel(_channel) {}
0126    };
0127 
0128    enum EQueueEntryKind { kind_None, kind_Connect, kind_Data, kind_Disconnect };
0129 
0130    struct QueueEntry {
0131       unsigned fConnId{0};               ///<! connection id
0132       EQueueEntryKind fKind{kind_None};  ///<! kind of data
0133       std::string fData;                 ///<! data for given connection
0134       QueueEntry() = default;
0135       QueueEntry(unsigned connid, EQueueEntryKind kind, std::string &&data) : fConnId(connid), fKind(kind), fData(data) {}
0136    };
0137 
0138    using ConnectionsList_t = std::vector<std::shared_ptr<WebConn>>;
0139 
0140    std::shared_ptr<RWebWindowsManager> fMgr;        ///<! display manager
0141    std::shared_ptr<RWebWindow> fMaster;             ///<! master window where this window is embedded
0142    std::vector<MasterConn> fMasterConns;            ///<! master connections
0143    std::string fDefaultPage;                        ///<! HTML page (or file name) returned when window URL is opened
0144    std::string fPanelName;                          ///<! panel name which should be shown in the window
0145    unsigned fId{0};                                 ///<! unique identifier
0146    bool fUseServerThreads{false};                   ///<! indicates that server thread is using, no special window thread
0147    bool fUseProcessEvents{false};                   ///<! all window functionality will run through process events
0148    bool fProcessMT{false};                          ///<! if window event processing performed in dedicated thread
0149    bool fSendMT{false};                             ///<! true is special threads should be used for sending data
0150    bool fRequireAuthKey{true};                      ///<! defines if authentication key always required when connect to the widget
0151    std::shared_ptr<RWebWindowWSHandler> fWSHandler; ///<! specialize websocket handler for all incoming connections
0152    unsigned fConnCnt{0};                            ///<! counter of new connections to assign ids
0153    ConnectionsList_t fPendingConn;                  ///<! list of pending connection with pre-assigned keys
0154    ConnectionsList_t fConn;                         ///<! list of all accepted connections
0155    mutable std::mutex fConnMutex;                   ///<! mutex used to protect connection list
0156    unsigned fConnLimit{1};                          ///<! number of allowed active connections
0157    std::string fConnToken;                          ///<! value of "token" URL parameter which should be provided for connecting window
0158    bool fNativeOnlyConn{false};                     ///<! only native connection are allowed, created by Show() method
0159    bool fUseCurrentDir{false};                      ///<! if window can access local files via currentdir/ path of http server
0160    unsigned fMaxQueueLength{10};                    ///<! maximal number of queue entries
0161    WebWindowConnectCallback_t fConnCallback;        ///<! callback for connect event
0162    WebWindowDataCallback_t fDataCallback;           ///<! main callback when data over channel 1 is arrived
0163    WebWindowConnectCallback_t fDisconnCallback;     ///<! callback for disconnect event
0164    std::thread::id fCallbacksThrdId;                ///<! thread id where callbacks should be invoked
0165    bool fCallbacksThrdIdSet{false};                 ///<! flag indicating that thread id is assigned
0166    bool fHasWindowThrd{false};                      ///<! indicate if special window thread was started
0167    std::thread fWindowThrd;                         ///<! special thread for that window
0168    std::queue<QueueEntry> fInputQueue;              ///<! input queue for all callbacks
0169    std::mutex fInputQueueMutex;                     ///<! mutex to protect input queue
0170    unsigned fWidth{0}, fHeight{0};                  ///<! initial window width and height when displayed, zeros are ignored
0171    int fX{-1}, fY{-1};                              ///<! initial window position, -1 ignored
0172    float fOperationTmout{50.};                      ///<! timeout in seconds to perform synchronous operation, default 50s
0173    std::string fClientVersion;                      ///<! configured client version, used as prefix in scripts URL
0174    std::string fProtocolFileName;                   ///<! local file where communication protocol will be written
0175    int fProtocolCnt{-1};                            ///<! counter for protocol recording
0176    unsigned fProtocolConnId{0};                     ///<! connection id, which is used for writing protocol
0177    std::string fProtocolPrefix;                     ///<! prefix for created files names
0178    std::string fProtocol;                           ///<! protocol
0179    std::string fUserArgs;                           ///<! arbitrary JSON code, which is accessible via conn.getUserArgs() method
0180    std::shared_ptr<void> fClearOnClose;             ///<! entry which is cleared when last connection is closed
0181    static std::string gJSROOTsettings;              ///<! custom settings for JSROOT
0182 
0183    std::shared_ptr<RWebWindowWSHandler> CreateWSHandler(std::shared_ptr<RWebWindowsManager> mgr, unsigned id, double tmout);
0184 
0185    bool ProcessWS(THttpCallArg &arg);
0186 
0187    void CompleteWSSend(unsigned wsid);
0188 
0189    ConnectionsList_t GetWindowConnections(unsigned connid = 0, bool only_active = false) const;
0190 
0191    /// Find connection with specified websocket id
0192    std::shared_ptr<WebConn> FindConnection(unsigned wsid);
0193 
0194    void ClearConnection(std::shared_ptr<WebConn> &conn, bool provide_signal = false);
0195 
0196    std::shared_ptr<WebConn> RemoveConnection(unsigned wsid, bool provide_signal = false);
0197 
0198    bool _CanTrustIn(std::shared_ptr<WebConn> &conn, const std::string &key, const std::string &ntry, bool remote, bool test_first_time);
0199 
0200    std::string _MakeSendHeader(std::shared_ptr<WebConn> &conn, bool txt, const std::string &data, int chid);
0201 
0202    void ProvideQueueEntry(unsigned connid, EQueueEntryKind kind, std::string &&arg);
0203 
0204    void InvokeCallbacks(bool force = false);
0205 
0206    void SubmitData(unsigned connid, bool txt, std::string &&data, int chid = 1);
0207 
0208    bool CheckDataToSend(std::shared_ptr<WebConn> &conn);
0209 
0210    void CheckDataToSend(bool only_once = false);
0211 
0212    bool HasKey(const std::string &key, bool also_newkey = false) const;
0213 
0214    void RemoveKey(const std::string &key);
0215 
0216    std::string GenerateKey() const;
0217 
0218    void CheckPendingConnections();
0219 
0220    void CheckInactiveConnections();
0221 
0222    unsigned AddDisplayHandle(bool headless_mode, const std::string &key, std::unique_ptr<RWebDisplayHandle> &handle);
0223 
0224    unsigned AddEmbedWindow(std::shared_ptr<RWebWindow> window, unsigned connid, int channel);
0225 
0226    void RemoveEmbedWindow(unsigned connid, int channel);
0227 
0228    void AddMasterConnection(std::shared_ptr<RWebWindow> window, unsigned connid, int channel);
0229 
0230    std::vector<MasterConn> GetMasterConnections(unsigned connid = 0) const;
0231 
0232    void RemoveMasterConnection(unsigned connid = 0);
0233 
0234    bool ProcessBatchHolder(std::shared_ptr<THttpCallArg> &arg);
0235 
0236    std::string GetConnToken() const;
0237 
0238    unsigned MakeHeadless(bool create_new = false);
0239 
0240    unsigned FindHeadlessConnection();
0241 
0242    static std::function<bool(const std::shared_ptr<RWebWindow> &, unsigned, const std::string &)> gStartDialogFunc;
0243 
0244    static void SetStartDialogFunc(std::function<bool(const std::shared_ptr<RWebWindow> &, unsigned, const std::string &)>);
0245 
0246    static std::string HMAC(const std::string &key, const std::string &sessionKey, const char *msg, int msglen);
0247 
0248 public:
0249 
0250    RWebWindow();
0251 
0252    ~RWebWindow();
0253 
0254    /// Returns ID for the window - unique inside window manager
0255    unsigned GetId() const { return fId; }
0256 
0257    /// Returns window manager
0258    std::shared_ptr<RWebWindowsManager> GetManager() const { return fMgr; }
0259 
0260    /// Set content of default window HTML page
0261    /// This page returns when URL address of the window will be requested
0262    /// Either HTML code or file name in the form "file:/home/user/data/file.htm"
0263    /// One also can using default locations like "file:rootui5sys/canv/canvas.html"
0264    void SetDefaultPage(const std::string &page) { fDefaultPage = page; }
0265 
0266    void SetPanelName(const std::string &name);
0267 
0268    /// Set window geometry. Will be applied if supported by used web display (like CEF or Chromium)
0269    void SetGeometry(unsigned width, unsigned height)
0270    {
0271       fWidth = width;
0272       fHeight = height;
0273    }
0274 
0275    /// Set window position. Will be applied if supported by used web display (like CEF or Chromium)
0276    void SetPosition(unsigned x, unsigned y)
0277    {
0278       fX = x;
0279       fY = y;
0280    }
0281 
0282    /////////////////////////////////////////////////////////////////////////
0283    /// returns configured window width (0 - default)
0284    /// actual window width can be different
0285    unsigned GetWidth() const { return fWidth; }
0286 
0287    /////////////////////////////////////////////////////////////////////////
0288    /// returns configured window height (0 - default)
0289    unsigned GetHeight() const { return fHeight; }
0290 
0291    /////////////////////////////////////////////////////////////////////////
0292    /// returns configured window X position (-1 - default)
0293    int GetX() const { return fX; }
0294 
0295    /////////////////////////////////////////////////////////////////////////
0296    /// returns configured window Y position (-1 - default)
0297    int GetY() const { return fY; }
0298 
0299    void SetConnLimit(unsigned lmt = 0);
0300 
0301    unsigned GetConnLimit() const;
0302 
0303    void SetConnToken(const std::string &token = "");
0304 
0305    /////////////////////////////////////////////////////////////////////////
0306    /// configures maximal queue length of data which can be held by window
0307    void SetMaxQueueLength(unsigned len = 10) { fMaxQueueLength = len; }
0308 
0309    /////////////////////////////////////////////////////////////////////////
0310    /// Return maximal queue length of data which can be held by window
0311    unsigned GetMaxQueueLength() const { return fMaxQueueLength; }
0312 
0313    /////////////////////////////////////////////////////////////////////////
0314    /// configures that only native (own-created) connections are allowed
0315    void SetNativeOnlyConn(bool on = true) { fNativeOnlyConn = on; }
0316 
0317    /////////////////////////////////////////////////////////////////////////
0318    /// returns true if only native (own-created) connections are allowed
0319    bool IsNativeOnlyConn() const { return fNativeOnlyConn; }
0320 
0321    /////////////////////////////////////////////////////////////////////////
0322    /// Configure if authentication key in connection string is required
0323    void SetRequireAuthKey(bool on) { fRequireAuthKey = on; }
0324 
0325    /////////////////////////////////////////////////////////////////////////
0326    /// returns true if authentication string is required
0327    bool IsRequireAuthKey() const { return fRequireAuthKey; }
0328 
0329    /////////////////////////////////////////////////////////////////////////
0330    /// Configure if window can access local files via currentdir/ path of http server
0331    void SetUseCurrentDir(bool on = true) { fUseCurrentDir = on; }
0332 
0333    /////////////////////////////////////////////////////////////////////////
0334    /// returns true if window can access local files via currentdir/ path of http server
0335    bool IsUseCurrentDir() const { return fUseCurrentDir; }
0336 
0337    void SetClientVersion(const std::string &vers);
0338 
0339    std::string GetClientVersion() const;
0340 
0341    void SetUserArgs(const std::string &args);
0342 
0343    std::string GetUserArgs() const;
0344 
0345    int NumConnections(bool with_pending = false) const;
0346 
0347    unsigned GetConnectionId(int num = 0) const;
0348 
0349    std::vector<unsigned> GetConnections(unsigned excludeid = 0) const;
0350 
0351    bool HasConnection(unsigned connid = 0, bool only_active = true) const;
0352 
0353    void CloseConnections();
0354 
0355    void CloseConnection(unsigned connid);
0356 
0357    /// Returns timeout for synchronous WebWindow operations
0358    float GetOperationTmout() const { return fOperationTmout; }
0359 
0360    /// Set timeout for synchronous WebWindow operations
0361    void SetOperationTmout(float tm = 50.) { fOperationTmout = tm; }
0362 
0363    std::string GetUrl(bool remote = true);
0364 
0365    THttpServer *GetServer();
0366 
0367    void Sync();
0368 
0369    void Run(double tm = 0.);
0370 
0371    unsigned Show(const RWebDisplayArgs &args = "");
0372 
0373    unsigned GetDisplayConnection() const;
0374 
0375    /// Returns true when window was shown at least once
0376    bool IsShown() const { return GetDisplayConnection() != 0; }
0377 
0378    bool CanSend(unsigned connid, bool direct = true) const;
0379 
0380    int GetSendQueueLength(unsigned connid) const;
0381 
0382    void Send(unsigned connid, const std::string &data);
0383 
0384    void SendBinary(unsigned connid, const void *data, std::size_t len);
0385 
0386    void SendBinary(unsigned connid, std::string &&data);
0387 
0388    void RecordData(const std::string &fname = "protocol.json", const std::string &fprefix = "");
0389 
0390    std::string GetAddr() const;
0391 
0392    _R__DEPRECATED_LATER("Use GetUrl() to get valid connection URL") std::string GetRelativeAddr(const std::shared_ptr<RWebWindow> &win) const;
0393 
0394    _R__DEPRECATED_LATER("Use GetAddr() to get valid connection URL") std::string GetRelativeAddr(const RWebWindow &win) const;
0395 
0396    void SetCallBacks(WebWindowConnectCallback_t conn, WebWindowDataCallback_t data, WebWindowConnectCallback_t disconn = nullptr);
0397 
0398    void Reset();
0399 
0400    void SetConnectCallBack(WebWindowConnectCallback_t func);
0401 
0402    void SetDataCallBack(WebWindowDataCallback_t func);
0403 
0404    void SetDisconnectCallBack(WebWindowConnectCallback_t func);
0405 
0406    void SetClearOnClose(const std::shared_ptr<void> &handle = nullptr);
0407 
0408    void AssignThreadId();
0409 
0410    void UseServerThreads();
0411 
0412    int WaitFor(WebWindowWaitFunc_t check);
0413 
0414    int WaitForTimed(WebWindowWaitFunc_t check);
0415 
0416    int WaitForTimed(WebWindowWaitFunc_t check, double duration);
0417 
0418    void StartThread();
0419 
0420    void StopThread();
0421 
0422    void TerminateROOT();
0423 
0424    static std::shared_ptr<RWebWindow> Create();
0425 
0426    static unsigned ShowWindow(std::shared_ptr<RWebWindow> window, const RWebDisplayArgs &args = "");
0427 
0428    static bool IsFileDialogMessage(const std::string &msg);
0429 
0430    static bool EmbedFileDialog(const std::shared_ptr<RWebWindow> &window, unsigned connid, const std::string &args);
0431 
0432    static void SetJSROOTSettings(const std::string &json);
0433 };
0434 
0435 } // namespace ROOT
0436 
0437 #endif