Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-20 09:03:40

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