Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:10:50

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