31using namespace std::string_literals;
40 fHold->SetTextContent(
"console.log('execute holder script'); if (window) setTimeout (window.close, 1000); if (window) window.close();");
41 fHold->NotifyCondition();
96 for (
auto &conn : lst) {
97 conn->fActive =
false;
98 for (
auto &elem: conn->fEmbed)
99 elem.second->fMaster.reset();
102 fMgr->Unregister(*
this);
115 if (!
fConn.empty()) {
128std::shared_ptr<RWebWindowWSHandler>
147 return fMgr->GetUrl(*
this, remote);
155 return fMgr->GetServer();
165 return fMgr->ShowWindow(*
this,
false, args);
180 connid =
fMgr->ShowWindow(*
this,
true, args);
194 if (entry->fBatchMode)
195 return entry->fConnId;
198 for (
auto &conn :
fConn) {
199 if (conn->fBatchMode)
200 return conn->fConnId;
217 if (!entry->fBatchMode)
218 return entry->fConnId;
221 for (
auto &conn :
fConn) {
222 if (!conn->fBatchMode)
223 return conn->fConnId;
237 for (
auto &conn :
fConn) {
238 if (conn->fWSId == wsid)
246 std::shared_ptr<WebConn> key;
247 std::string keyvalue;
256 if (!keyvalue.empty())
268 fConn.emplace_back(key);
270 fConn.emplace_back(std::make_shared<WebConn>(++
fConnCnt, wsid));
283 std::shared_ptr<WebConn> res;
288 for (
size_t n = 0;
n <
fConn.size(); ++
n)
289 if (
fConn[
n]->fWSId == wsid) {
290 res = std::move(
fConn[
n]);
292 res->fActive =
false;
298 for (
auto &elem: res->fEmbed)
299 elem.second->fMaster.reset();
311 std::string query = arg->GetQuery();
313 if (query.compare(0, 4,
"key=") != 0)
316 std::string key = query.substr(4);
318 std::shared_ptr<THttpCallArg> prev;
320 bool found_key =
false;
326 if (entry->fKey == key) {
329 prev = std::move(entry->fHold);
335 for (
auto &conn :
fConn) {
336 if (conn->fKey == key) {
338 prev = std::move(conn->fHold);
346 prev->SetTextContent(
"console.log('execute holder script'); if (window) window.close();");
347 prev->NotifyCondition();
386 connid = entry.fConnId;
388 arg = std::move(entry.fData);
421 auto conn = std::make_shared<WebConn>(
fConnCnt, batch_mode, key);
423 std::swap(conn->fDisplayHandle, handle);
438 if (entry->fKey == key)
442 for (
auto &conn :
fConn) {
443 if (conn->fKey == key)
458 timestamp_t stamp = std::chrono::system_clock::now();
460 float tmout =
fMgr->GetLaunchTmout();
467 auto pred = [&](std::shared_ptr<WebConn> &
e) {
468 std::chrono::duration<double> diff = stamp -
e->fSendStamp;
470 if (diff.count() > tmout) {
472 selected.emplace_back(
e);
491 timestamp_t stamp = std::chrono::system_clock::now();
493 double batch_tmout = 20.;
495 std::vector<std::shared_ptr<WebConn>> clr;
500 auto pred = [&](std::shared_ptr<WebConn> &conn) {
501 std::chrono::duration<double> diff = stamp - conn->fSendStamp;
503 if ((diff.count() > batch_tmout) && conn->fBatchMode) {
504 conn->fActive =
false;
505 clr.emplace_back(conn);
514 for (
auto &entry : clr)
634 char *str_end =
nullptr;
636 unsigned long ackn_oper = std::strtoul(buf, &str_end, 10);
637 if (!str_end || *str_end !=
':') {
642 unsigned long can_send = std::strtoul(str_end + 1, &str_end, 10);
643 if (!str_end || *str_end !=
':') {
648 unsigned long nchannel = std::strtoul(str_end + 1, &str_end, 10);
649 if (!str_end || *str_end !=
':') {
654 Long_t processed_len = (str_end + 1 - buf);
663 timestamp_t stamp = std::chrono::system_clock::now();
666 std::lock_guard<std::mutex> grd(conn->fMutex);
668 conn->fSendCredits += ackn_oper;
670 conn->fClientCredits = (
int)can_send;
671 conn->fRecvStamp = stamp;
679 if ((nchannel != 0) || (cdata.find(
"READY=") == 0)) {
692 if ((cdata.find(
"READY=") == 0) && !conn->fReady) {
693 std::string key = cdata.substr(6);
700 if (!key.empty() && !conn->fKey.empty() && (conn->fKey != key)) {
701 R__LOG_ERROR(
WebGUILog()) <<
"Key mismatch after established connection " << key <<
" != " << conn->fKey;
714 }
else if (cdata.compare(0,8,
"CLOSECH=") == 0) {
715 int channel = std::stoi(cdata.substr(8));
716 auto iter = conn->fEmbed.find(channel);
717 if (iter != conn->fEmbed.end()) {
719 conn->fEmbed.erase(iter);
722 }
else if (
fPanelName.length() && (conn->fReady < 10)) {
723 if (cdata ==
"PANEL_READY") {
731 }
else if (nchannel == 1) {
733 }
else if (nchannel > 1) {
735 auto embed_window = conn->fEmbed[nchannel];
737 embed_window->ProvideQueueEntry(conn->fConnId,
kind_Data, std::move(cdata));
753 std::lock_guard<std::mutex> grd(conn->fMutex);
754 conn->fDoingSend =
false;
773 if (conn->fSendCredits <= 0) {
778 if (conn->fDoingSend) {
784 buf.reserve(data.length() + 100);
786 buf.append(std::to_string(conn->fRecvCount));
788 buf.append(std::to_string(conn->fSendCredits));
790 conn->fRecvCount = 0;
791 conn->fSendCredits--;
793 buf.append(std::to_string(chid));
798 }
else if (data.length()==0) {
799 buf.append(
"$$nullbinary$$");
801 buf.append(
"$$binary$$");
813 std::string hdr, data;
816 std::lock_guard<std::mutex> grd(conn->fMutex);
818 if (!conn->fActive || (conn->fSendCredits <= 0) || conn->fDoingSend)
return false;
820 if (!conn->fQueue.empty()) {
823 if (!hdr.empty() && !item.
fText)
824 data = std::move(item.
fData);
826 }
else if ((conn->fClientCredits < 3) && (conn->fRecvCount > 1)) {
831 if (hdr.empty())
return false;
833 conn->fDoingSend =
true;
839 res =
fWSHandler->SendCharStarWS(conn->fWSId, hdr.c_str());
841 res =
fWSHandler->SendHeaderWS(conn->fWSId, hdr.c_str(), data.data(), data.length());
845 if (res >=0)
return true;
849 std::lock_guard<std::mutex> grd(conn->fMutex);
850 conn->fDoingSend =
false;
867 for (
auto &conn : arr)
873 }
while (!only_once);
905 if (
fMgr != win->fMgr) {
910 std::string res(
"../");
911 res.append(win->GetAddr());
964 auto sz =
fConn.size();
995 return ((num >= 0) && (num < (
int)
fConn.size()) &&
fConn[num]->fActive) ?
fConn[num]->fConnId : 0;
1007 for (
auto &conn :
fConn) {
1008 if (connid && (conn->fConnId != connid))
1010 if (conn->fActive || !only_active)
1016 if (!connid || (conn->fConnId == connid))
1053 for (
auto &conn :
fConn) {
1054 if ((conn->fActive || !only_active) && (!connid || (conn->fConnId == connid)))
1055 arr.push_back(conn);
1060 if (!connid || (conn->fConnId == connid))
1061 arr.push_back(conn);
1078 for (
auto &conn : arr) {
1080 std::lock_guard<std::mutex> grd(conn->fMutex);
1082 if (direct && (!conn->fQueue.empty() || (conn->fSendCredits == 0) || conn->fDoingSend))
1085 if (conn->fQueue.size() >= maxqlen)
1102 std::lock_guard<std::mutex> grd(conn->fMutex);
1103 int len = conn->fQueue.size();
1104 if (len > maxq) maxq = len;
1122 auto cnt = arr.size();
1125 timestamp_t stamp = std::chrono::system_clock::now();
1127 for (
auto &conn : arr) {
1133 fname.append(
"msg");
1135 fname.append(txt ?
".txt" :
".bin");
1137 std::ofstream ofs(fname);
1138 ofs.write(data.c_str(), data.length());
1150 conn->fSendStamp = stamp;
1152 std::lock_guard<std::mutex> grd(conn->fMutex);
1154 if (conn->fQueue.size() < maxqlen) {
1156 conn->fQueue.emplace(chid, txt, std::string(data));
1158 conn->fQueue.emplace(chid, txt, std::move(data));
1173 SubmitData(connid,
true, std::string(data), 1);
1182 SubmitData(connid,
false, std::move(data), 1);
1193 std::copy((
const char *)data, (
const char *)data + len, buf.begin());
1194 SubmitData(connid,
false, std::move(buf), 1);
1206 }
else if (
fMgr->IsUseHttpThread()) {
1208 R__LOG_ERROR(
WebGUILog()) <<
"create web window from main thread when THttpServer created with special thread - not supported";
1278 return fMgr->WaitFor(*
this, check);
1306 return fMgr->WaitFor(*
this, check,
true, duration);
1339 if (arr.size() == 0)
1343 if (arr[0]->fEmbed.find(channel) != arr[0]->fEmbed.end())
1346 arr[0]->fEmbed[channel] = window;
1348 return arr[0]->fConnId;
1358 for (
auto &conn : arr) {
1359 auto iter = conn->fEmbed.find(channel);
1360 if (iter != conn->fEmbed.end())
1361 conn->fEmbed.erase(iter);
1390 std::swap(arr1,
fConn);
1411 window->fMaster = args.
fMaster;
1412 window->fMasterConnId = connid;
1425 return window->Show(args);
#define R__LOG_WARNING(...)
#define R__LOG_ERROR(...)
#define R__LOG_DEBUG(DEBUGLEVEL,...)
char * Form(const char *fmt,...)
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
int fMasterChannel
! used master channel
EBrowserKind GetBrowserKind() const
returns configured browser kind, see EBrowserKind for supported values
std::shared_ptr< RWebWindow > fMaster
! master window
@ kEmbedded
window will be embedded into other, no extra browser need to be started
bool CheckDataToSend(std::shared_ptr< WebConn > &conn)
Checks if one should send data for specified connection Returns true when send operation was performe...
std::vector< std::shared_ptr< WebConn > > ConnectionsList_t
int WaitFor(WebWindowWaitFunc_t check)
Waits until provided check function or lambdas returns non-zero value Check function has following si...
unsigned AddEmbedWindow(std::shared_ptr< RWebWindow > window, int channel)
Add embed window.
std::shared_ptr< RWebWindow > fMaster
! master window where this window is embeded
void CheckInactiveConnections()
Check if there are connection which are inactive for longer time For instance, batch browser will be ...
ConnectionsList_t GetConnections(unsigned connid=0, bool only_active=false) const
returns connection (or all active connections)
std::string fUserArgs
! arbitrary JSON code, which is accessible via conn.getUserArgs() method
int fMasterChannel
! channel id in the master window
float GetOperationTmout() const
Returns timeout for synchronous WebWindow operations.
std::shared_ptr< WebConn > FindConnection(unsigned wsid)
void SetConnToken(const std::string &token="")
Configures connection token (default none) When specified, in URL of webpage such token should be pro...
std::string GetUrl(bool remote=true)
Return URL string to access web window If remote flag is specified, real HTTP server will be started ...
void CloseConnections()
Closes all connection to clients Normally leads to closing of all correspondent browser windows Some ...
unsigned AddDisplayHandle(bool batch_mode, const std::string &key, std::unique_ptr< RWebDisplayHandle > &handle)
Add display handle and associated key Key is random number generated when starting new window When cl...
void SetDefaultPage(const std::string &page)
Set content of default window HTML page This page returns when URL address of the window will be requ...
int NumConnections(bool with_pending=false) const
Returns current number of active clients connections.
unsigned GetId() const
Returns ID for the window - unique inside window manager.
ConnectionsList_t fConn
! list of all accepted connections
void InvokeCallbacks(bool force=false)
Invoke callbacks with existing data Must be called from appropriate thread.
std::string fProtocolPrefix
! prefix for created files names
std::string GetClientVersion() const
Returns current client version.
void SetConnectCallBack(WebWindowConnectCallback_t func)
Set call-back function for new connection.
WebWindowConnectCallback_t fConnCallback
! callback for connect event
unsigned GetMaxQueueLength() const
Return maximal queue length of data which can be held by window.
void Sync()
Special method to process all internal activity when window runs in separate thread.
void TerminateROOT()
Terminate ROOT session Tries to correctly close THttpServer, associated with RWebWindowsManager After...
unsigned fConnLimit
! number of allowed active connections
void Send(unsigned connid, const std::string &data)
Sends data to specified connection If connid==0, data will be send to all connections.
bool fCallbacksThrdIdSet
! flag indicating that thread id is assigned
unsigned Show(const RWebDisplayArgs &args="")
Show window in specified location See ROOT::Experimental::RWebWindowsManager::Show() docu for more in...
THttpServer * GetServer()
Return THttpServer instance serving requests to the window.
unsigned fMasterConnId
! master connection id
void AssignCallbackThreadId()
Assign thread id which has to be used for callbacks.
bool fSendMT
! true is special threads should be used for sending data
void SendBinary(unsigned connid, const void *data, std::size_t len)
Send binary data to specified connection If connid==0, data will be sent to all connections.
static std::shared_ptr< RWebWindow > Create()
Create new RWebWindow Using default RWebWindowsManager.
std::thread::id fCallbacksThrdId
! thread id where callbacks should be invoked
std::chrono::time_point< std::chrono::system_clock > timestamp_t
std::string fClientVersion
! configured client version, used as prefix in scripts URL
bool ProcessBatchHolder(std::shared_ptr< THttpCallArg > &arg)
Process special http request, used to hold headless browser running Such requests should not be repli...
unsigned MakeBatch(bool create_new=false, const RWebDisplayArgs &args="")
Create batch job for specified window Normally only single batch job is used, but many can be created...
unsigned fConnCnt
! counter of new connections to assign ids
void SetDisconnectCallBack(WebWindowConnectCallback_t func)
Set call-back function for disconnecting.
std::string fPanelName
! panel name which should be shown in the window
void SetDataCallBack(WebWindowDataCallback_t func)
Set call-back function for data, received from the clients via websocket.
unsigned fProtocolConnId
! connection id, which is used for writing protocol
void SetUserArgs(const std::string &args)
Set arbitrary JSON code, which is accessible via conn.GetUserArgs() method This JSON code injected in...
static unsigned ShowWindow(std::shared_ptr< RWebWindow > window, const RWebDisplayArgs &args="")
Static method to show web window Has to be used instead of RWebWindow::Show() when window potentially...
WebWindowDataCallback_t fDataCallback
! main callback when data over channel 1 is arrived
void SubmitData(unsigned connid, bool txt, std::string &&data, int chid=1)
Internal method to send data Allows to specify channel.
~RWebWindow()
RWebWindow destructor Closes all connections and remove window from manager.
void CloseConnection(unsigned connid)
Close specified connection Connection id usually appears in the correspondent call-backs.
unsigned GetConnectionId(int num=0) const
Returns connection for specified connection number Only active connections are returned - where clien...
std::string GetConnToken() const
Returns configured connection token.
ConnectionsList_t fPendingConn
! list of pending connection with pre-assigned keys
void SetConnLimit(unsigned lmt=0)
Configure maximal number of allowed connections - 0 is unlimited Will not affect already existing con...
void SetPanelName(const std::string &name)
Configure window to show some of existing JSROOT panels It uses "file:rootui5sys/panel/panel....
RWebWindow()
RWebWindow constructor Should be defined here because of std::unique_ptr<RWebWindowWSHandler>
std::shared_ptr< WebConn > FindOrCreateConnection(unsigned wsid, bool make_new, const char *query)
Find connection with given websocket id Connection mutex should be locked before method calling.
int GetSendQueueLength(unsigned connid) const
returns send queue length for specified connection if connid==0, maximal value for all connections is...
std::shared_ptr< WebConn > RemoveConnection(unsigned wsid)
Remove connection with given websocket id.
std::shared_ptr< RWebWindowWSHandler > CreateWSHandler(std::shared_ptr< RWebWindowsManager > mgr, unsigned id, double tmout)
Assigns manager reference, window id and creates websocket handler, used for communication with the c...
bool CanSend(unsigned connid, bool direct=true) const
returns true if sending via specified connection can be performed if direct==true,...
std::string GetUserArgs() const
Returns configured user arguments for web window See SetUserArgs method for more details.
void RecordData(const std::string &fname="protocol.json", const std::string &fprefix="")
Configures recording of communication data in protocol file Provided filename will be used to store J...
bool HasKey(const std::string &key) const
Returns true if provided key value already exists (in processes map or in existing connections)
unsigned GetDisplayConnection() const
Returns first connection id where window is displayed It could be that connection(s) not yet fully es...
unsigned GetConnLimit() const
returns configured connections limit (0 - default)
std::string GetRelativeAddr(const std::shared_ptr< RWebWindow > &win) const
Returns relative URL address for the specified window Address can be required if one needs to access ...
void Run(double tm=0.)
Run window functionality for specified time If no action can be performed - just sleep specified time...
unsigned FindBatch()
Returns connection id of batch job Connection to that job may not be initialized yet If connection do...
std::string GetAddr() const
Returns window address which is used in URL.
std::shared_ptr< RWebWindowWSHandler > fWSHandler
! specialize websocket handler for all incoming connections
std::string fProtocolFileName
! local file where communication protocol will be written
std::shared_ptr< RWebWindowsManager > fMgr
! display manager
void CheckPendingConnections()
Check if started process(es) establish connection.
std::string fConnToken
! value of "token" URL parameter which should be provided for connecting window
std::mutex fInputQueueMutex
! mutex to protect input queue
std::string _MakeSendHeader(std::shared_ptr< WebConn > &conn, bool txt, const std::string &data, int chid)
Prepare text part of send data Should be called under locked connection mutex.
bool IsNativeOnlyConn() const
returns true if only native (own-created) connections are allowed
bool ProcessWS(THttpCallArg &arg)
Processing of websockets call-backs, invoked from RWebWindowWSHandler Method invoked from http server...
bool HasConnection(unsigned connid=0, bool only_active=true) const
returns true if specified connection id exists connid is connection (0 - any) if only_active==false,...
int fProtocolCnt
! counter for protocol recording
std::queue< QueueEntry > fInputQueue
! input queue for all callbacks
bool fProcessMT
! if window event processing performed in dedicated thread
std::string fProtocol
! protocol
void ProvideQueueEntry(unsigned connid, EQueueEntryKind kind, std::string &&arg)
Provide data to user callback User callback must be executed in the window thread.
void CompleteWSSend(unsigned wsid)
unsigned fId
! unique identifier
float fOperationTmout
! timeout in seconds to perform synchronous operation, default 50s
int WaitForTimed(WebWindowWaitFunc_t check)
Waits until provided check function or lambdas returns non-zero value Check function has following si...
WebWindowConnectCallback_t fDisconnCallback
! callback for disconnect event
void SetClientVersion(const std::string &vers)
Set client version, used as prefix in scripts URL When changed, web browser will reload all related J...
void RemoveEmbedWindow(unsigned connid, int channel)
Remove RWebWindow associated with the channel.
void SetCallBacks(WebWindowConnectCallback_t conn, WebWindowDataCallback_t data, WebWindowConnectCallback_t disconn=nullptr)
Set call-backs function for connect, data and disconnect events.
std::mutex fConnMutex
! mutex used to protect connection list
static bool IsMainThrd()
Returns true when called from main process Main process recognized at the moment when library is load...
static std::shared_ptr< RWebWindowsManager > & Instance()
Returns default window manager Used to display all standard ROOT elements like TCanvas or TFitPanel.
UInt_t GetWSId() const
get web-socket id
const void * GetPostData() const
return pointer on posted with request data
const char * GetQuery() const
returns request query (string after ? in request URL)
Long_t GetPostDataLength() const
return length of posted with request data
Bool_t IsMethod(const char *name) const
returns kTRUE if post method is used
This class represents a WWW compatible URL.
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
void SetOptions(const char *opt)
Bool_t HasOption(const char *key) const
Returns true if the given key appears in the URL options list.
RLogChannel & WebGUILog()
Log channel for WebGUI diagnostics.
std::function< void(unsigned)> WebWindowConnectCallback_t
function signature for connect/disconnect call-backs argument is connection id
std::function< void(unsigned, const std::string &)> WebWindowDataCallback_t
function signature for call-backs from the window clients first argument is connection id,...
std::function< int(double)> WebWindowWaitFunc_t
function signature for waiting call-backs Such callback used when calling thread need to waits for so...
std::string fData
! text or binary data
~WebConn()
Destructor for WebConn Notify special HTTP request which blocks headless browser from exit.
std::shared_ptr< THttpCallArg > fHold
! request used to hold headless browser