diff --git a/graf3d/eve7/inc/ROOT/REveManager.hxx b/graf3d/eve7/inc/ROOT/REveManager.hxx index 2c9b93df1ab4e02c752102ba8b8eaee694cb2120..4d47fd0da890b9c6a3925d867c2438091316c13b 100644 --- a/graf3d/eve7/inc/ROOT/REveManager.hxx +++ b/graf3d/eve7/inc/ROOT/REveManager.hxx @@ -126,7 +126,9 @@ protected: std::shared_ptr<ROOT::Experimental::RWebWindow> fWebWindow; std::vector<Conn> fConnList; - void GeomWindowCallback(unsigned connid, const std::string &arg); + void WindowConnect(unsigned connid); + void WindowData(unsigned connid, const std::string &arg); + void WindowDisconnect(unsigned connid); public: REveManager(); // (Bool_t map_window=kTRUE, Option_t* opt="FI"); @@ -216,7 +218,6 @@ public: void EnforceTimerActive (Bool_t ta) { fTimerActive = ta; } - void HttpServerCallback(unsigned connid, const std::string &arg); // void Send(void* buff, unsigned connid); void Send(unsigned connid, const std::string &data); void SendBinary(unsigned connid, const void *data, std::size_t len); diff --git a/graf3d/eve7/src/REveGeomViewer.cxx b/graf3d/eve7/src/REveGeomViewer.cxx index fa967db927cec4dc7ed3c01a5b26da5266088515..e290f145cd3801e23404b71b64023f353ba80dc1 100644 --- a/graf3d/eve7/src/REveGeomViewer.cxx +++ b/graf3d/eve7/src/REveGeomViewer.cxx @@ -150,9 +150,7 @@ void ROOT::Experimental::REveGeomViewer::WebWindowCallback(unsigned connid, cons { printf("Recv %s\n", arg.c_str()); - if (arg == "CONN_READY") { - - } else if (arg == "GETDRAW") { + if (arg == "GETDRAW") { SendGeometry(connid); diff --git a/graf3d/eve7/src/REveManager.cxx b/graf3d/eve7/src/REveManager.cxx index 96050ee3a25084dea9dd31b2d3a0af0ab09bed3f..1ad77eb7420e08a1bb8f65f0d512ca5f833be610 100644 --- a/graf3d/eve7/src/REveManager.cxx +++ b/graf3d/eve7/src/REveManager.cxx @@ -140,7 +140,9 @@ REveManager::REveManager() : // (Bool_t map_window, Option_t* opt) : fWebWindow->SetDefaultPage("file:rootui5sys/eve7/index.html"); // this is call-back, invoked when message received via websocket - fWebWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { this->HttpServerCallback(connid, arg); }); + fWebWindow->SetCallBacks([this](unsigned connid) { WindowConnect(connid); }, + [this](unsigned connid, const std::string &arg) { WindowData(connid, arg); }, + [this](unsigned connid) { WindowDisconnect(connid); }); fWebWindow->SetGeometry(900, 700); // configure predefined window geometry fWebWindow->SetConnLimit(100); // maximal number of connections fWebWindow->SetMaxQueueLength(30); // number of allowed entries in the window queue @@ -725,56 +727,55 @@ REveManager::RExceptionHandler::Handle(std::exception &exc) } //////////////////////////////////////////////////////////////////////////////// -/// Callback from THttpServer +/// Process new connection from web window -void REveManager::HttpServerCallback(unsigned connid, const std::string &arg) +void REveManager::WindowConnect(unsigned connid) { - static const REveException eh("REveManager::HttpServerCallback "); + fConnList.emplace_back(connid); + printf("connection established %u\n", connid); - if (arg == "CONN_READY") - { - fConnList.emplace_back(connid); - printf("connection established %u\n", connid); - - // This prepares core and render data buffers. - printf("\nEVEMNG ............. streaming the world scene.\n"); + // This prepares core and render data buffers. + printf("\nEVEMNG ............. streaming the world scene.\n"); - fWorld->AddSubscriber(std::make_unique<REveClient>(connid, fWebWindow)); - fWorld->StreamElements(); + fWorld->AddSubscriber(std::make_unique<REveClient>(connid, fWebWindow)); + fWorld->StreamElements(); - printf(" sending json, len = %d\n", (int) fWorld->fOutputJson.size()); - Send(connid, fWorld->fOutputJson); - printf(" for now assume world-scene has no render data, binary-size=%d\n", fWorld->fTotalBinarySize); - assert(fWorld->fTotalBinarySize == 0); + printf(" sending json, len = %d\n", (int) fWorld->fOutputJson.size()); + Send(connid, fWorld->fOutputJson); + printf(" for now assume world-scene has no render data, binary-size=%d\n", fWorld->fTotalBinarySize); + assert(fWorld->fTotalBinarySize == 0); - for (auto &c: fScenes->RefChildren()) - { - REveScene* scene = dynamic_cast<REveScene *>(c); + for (auto &c: fScenes->RefChildren()) + { + REveScene* scene = dynamic_cast<REveScene *>(c); - scene->AddSubscriber(std::make_unique<REveClient>(connid, fWebWindow)); - printf("\nEVEMNG ............. streaming scene %s [%s]\n", - scene->GetCTitle(), scene->GetCName()); + scene->AddSubscriber(std::make_unique<REveClient>(connid, fWebWindow)); + printf("\nEVEMNG ............. streaming scene %s [%s]\n", + scene->GetCTitle(), scene->GetCName()); - // This prepares core and render data buffers. - scene->StreamElements(); + // This prepares core and render data buffers. + scene->StreamElements(); - printf(" sending json, len = %d\n", (int) scene->fOutputJson.size()); - Send(connid, scene->fOutputJson); + printf(" sending json, len = %d\n", (int) scene->fOutputJson.size()); + Send(connid, scene->fOutputJson); - if (scene->fTotalBinarySize > 0) - { - printf(" sending binary, len = %d\n", scene->fTotalBinarySize); - SendBinary(connid, &scene->fOutputBinary[0], scene->fTotalBinarySize); - } - else - { - printf(" NOT sending binary, len = %d\n", scene->fTotalBinarySize); - } + if (scene->fTotalBinarySize > 0) + { + printf(" sending binary, len = %d\n", scene->fTotalBinarySize); + SendBinary(connid, &scene->fOutputBinary[0], scene->fTotalBinarySize); + } + else + { + printf(" NOT sending binary, len = %d\n", scene->fTotalBinarySize); } - return; } +} - // find connection object +//////////////////////////////////////////////////////////////////////////////// +/// Process disconnect of web window + +void REveManager::WindowDisconnect(unsigned connid) +{ auto conn = fConnList.end(); for (auto i = fConnList.begin(); i != fConnList.end(); ++i) { @@ -787,11 +788,8 @@ void REveManager::HttpServerCallback(unsigned connid, const std::string &arg) // this should not happen, just check if (conn == fConnList.end()) { printf("error, connection not found!"); - return; - } - - if (arg == "CONN_CLOSED") { - printf("connection closed\n"); + } else { + printf("connection closed %u\n", connid); fConnList.erase(conn); for (auto &c: fScenes->RefChildren()) { @@ -800,42 +798,63 @@ void REveManager::HttpServerCallback(unsigned connid, const std::string &arg) } fWorld->RemoveSubscriber(connid); - return; } - else - { - fWorld->BeginAcceptingChanges(); - fScenes->AcceptChanges(true); - - // MIR - nlohmann::json cj = nlohmann::json::parse(arg); - if (gDebug > 0) - ::Info("REveManager::HttpServerCallback", "MIR test %s", cj.dump().c_str()); - std::string mir = cj["mir"]; - std::string ctype = cj["class"]; - int id = cj["fElementId"]; - - auto el = FindElementById(id); - std::stringstream cmd; - cmd << "((" << ctype << "*)" << std::hex << std::showbase << (size_t)el << ")->" << mir << ";"; - if (gDebug > 0) - ::Info("REveManager::HttpServerCallback", "MIR cmd %s", cmd.str().c_str()); - gROOT->ProcessLine(cmd.str().c_str()); - - fScenes->AcceptChanges(false); - fWorld->EndAcceptingChanges(); - Redraw3D(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Process data from web window +void REveManager::WindowData(unsigned connid, const std::string &arg) +{ + static const REveException eh("REveManager::WindowData "); - /* - nlohmann::json resp; - resp["function"] = "replaceElement"; - //el->SetCoreJson(resp); - for (auto &conn : fConnList) - fWebWindow->Send(conn.fId, resp.dump()); - */ + // find connection object + auto conn = fConnList.end(); + for (auto i = fConnList.begin(); i != fConnList.end(); ++i) + { + if (i->fId == connid) + { + conn = i; + break; + } } + // this should not happen, just check + if (conn == fConnList.end()) { + printf("error, connection not found!"); + return; + } + + fWorld->BeginAcceptingChanges(); + fScenes->AcceptChanges(true); + + // MIR + nlohmann::json cj = nlohmann::json::parse(arg); + if (gDebug > 0) + ::Info("REveManager::WindowData", "MIR test %s", cj.dump().c_str()); + std::string mir = cj["mir"]; + std::string ctype = cj["class"]; + int id = cj["fElementId"]; + + auto el = FindElementById(id); + std::stringstream cmd; + cmd << "((" << ctype << "*)" << std::hex << std::showbase << (size_t)el << ")->" << mir << ";"; + if (gDebug > 0) + ::Info("REveManager::WindowData", "MIR cmd %s", cmd.str().c_str()); + gROOT->ProcessLine(cmd.str().c_str()); + + fScenes->AcceptChanges(false); + fWorld->EndAcceptingChanges(); + + Redraw3D(); + + /* + nlohmann::json resp; + resp["function"] = "replaceElement"; + //el->SetCoreJson(resp); + for (auto &conn : fConnList) + fWebWindow->Send(conn.fId, resp.dump()); + */ } void REveManager::Send(unsigned connid, const std::string &data) @@ -865,8 +884,7 @@ void REveManager::DestroyElementsOf(REveElement::List_t& els) nlohmann::json jels = nlohmann::json::array(); - for (auto & ep : els) - { + for (auto &ep : els) { jels.push_back(ep->GetElementId()); ep->DestroyElements(); @@ -880,8 +898,7 @@ void REveManager::DestroyElementsOf(REveElement::List_t& els) // XXXX Do we have broadcast? - for (auto && conn: fConnList) - { + for (auto &conn : fConnList) { fWebWindow->Send(conn.fId, msg); } } diff --git a/gui/browserv7/src/RBrowser.cxx b/gui/browserv7/src/RBrowser.cxx index acb0edab6c4ca130927dca282652eee63f4dab90..ac667048dd74819c30357a3ff433c3dc604ccd87 100644 --- a/gui/browserv7/src/RBrowser.cxx +++ b/gui/browserv7/src/RBrowser.cxx @@ -47,7 +47,8 @@ ROOT::Experimental::RBrowser::RBrowser() fWebWindow->SetDefaultPage("file:rootui5sys/browser/browser.html"); // this is call-back, invoked when message received via websocket - fWebWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { this->WebWindowCallback(connid, arg); }); + fWebWindow->SetCallBacks([this](unsigned connid) { fConnId = connid; }, + [this](unsigned connid, const std::string &arg) { WebWindowCallback(connid, arg); }); fWebWindow->SetGeometry(1200, 700); // configure predefined window geometry fWebWindow->SetConnLimit(1); // the only connection is allowed fWebWindow->SetMaxQueueLength(30); // number of allowed entries in the window queue @@ -279,11 +280,7 @@ void ROOT::Experimental::RBrowser::WebWindowCallback(unsigned connid, const std: { printf("Recv %s\n", arg.c_str()); - if (arg == "CONN_READY") { - - fConnId = connid; - - } else if (arg == "QUIT_ROOT") { + if (arg == "QUIT_ROOT") { fWebWindow->TerminateROOT(); diff --git a/gui/canvaspainter/v7/src/TCanvasPainter.cxx b/gui/canvaspainter/v7/src/TCanvasPainter.cxx index ecb4488b69aa9f888846d3c1622e79893d4d84da..3e314e5f9ef3660defe74d05e81eca538fe17ffc 100644 --- a/gui/canvaspainter/v7/src/TCanvasPainter.cxx +++ b/gui/canvaspainter/v7/src/TCanvasPainter.cxx @@ -443,39 +443,20 @@ void ROOT::Experimental::TCanvasPainter::DoWhenReady(const std::string &name, co void ROOT::Experimental::TCanvasPainter::ProcessData(unsigned connid, const std::string &arg) { - if (arg == "CONN_READY") { - // special argument from RWebWindow itself - // indication that new connection appeared - - fWebConn.emplace_back(connid); - - CheckDataToSend(); - return; - } - - auto check_header = [arg](const std::string &header) { - return arg.compare(0, header.length(), header) == 0; - }; - auto conn = std::find_if(fWebConn.begin(), fWebConn.end(), [connid](WebConn &item) { return item.fConnId == connid; }); if (conn == fWebConn.end()) return; // no connection found + auto check_header = [arg](const std::string &header) { + return arg.compare(0, header.length(), header) == 0; + }; + // R__DEBUG_HERE("CanvasPainter") << "from client " << connid << " got data len:" << arg.length() << " val:" << // arg.substr(0,30); - if (arg == "CONN_CLOSED") { - // special argument from RWebWindow itself - // connection is closed - - fWebConn.erase(conn); - - // if there are no other connections - cancel all submitted commands - CancelCommands(connid); - - } else if (check_header("READY")) { + if (check_header("READY")) { } else if (check_header("SNAPDONE:")) { std::string cdata = arg; @@ -544,7 +525,24 @@ void ROOT::Experimental::TCanvasPainter::CreateWindow() fWindow = RWebWindow::Create(); fWindow->SetConnLimit(0); // allow any number of connections fWindow->SetDefaultPage("file:rootui5sys/canv/canvas.html"); - fWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { ProcessData(connid, arg); }); + fWindow->SetCallBacks( + // connect + [this](unsigned connid) { + fWebConn.emplace_back(connid); + CheckDataToSend(); + }, + // data + [this](unsigned connid, const std::string &arg) { ProcessData(connid, arg); }, + // disconnect + [this](unsigned connid) { + auto conn = + std::find_if(fWebConn.begin(), fWebConn.end(), [connid](WebConn &item) { return item.fConnId == connid; }); + + if (conn != fWebConn.end()) { + fWebConn.erase(conn); + CancelCommands(connid); + } + }); // fWindow->SetGeometry(500,300); } diff --git a/gui/fitpanelv7/src/RFitPanel.cxx b/gui/fitpanelv7/src/RFitPanel.cxx index 54cb8af9e947c1becd255c4ec97b790304cb50a8..9227a54faed9478ed5d050762b4eb340b36b9818 100644 --- a/gui/fitpanelv7/src/RFitPanel.cxx +++ b/gui/fitpanelv7/src/RFitPanel.cxx @@ -107,7 +107,17 @@ std::shared_ptr<ROOT::Experimental::RWebWindow> ROOT::Experimental::RFitPanel::G fWindow->SetPanelName("rootui5.fitpanel.view.FitPanel"); - fWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { ProcessData(connid, arg); }); + fWindow->SetCallBacks( + [this](unsigned connid) + { + fConnId = connid; + fWindow->Send(fConnId, "INITDONE"); + if (!model().fInitialized) + SelectObject("$$$"); + SendModel(); + }, + [this](unsigned connid, const std::string &arg) { ProcessData(connid, arg); }, + [this](unsigned) { fConnId = 0; }); fWindow->SetGeometry(400, 650); // configure predefined geometry } @@ -384,21 +394,9 @@ void ROOT::Experimental::RFitPanel::SendModel() /// Process data from FitPanel /// OpenUI5-based FitPanel sends commands or status changes -void ROOT::Experimental::RFitPanel::ProcessData(unsigned connid, const std::string &arg) +void ROOT::Experimental::RFitPanel::ProcessData(unsigned, const std::string &arg) { - if (arg == "CONN_READY") { - fConnId = connid; - fWindow->Send(fConnId, "INITDONE"); - if (!model().fInitialized) - SelectObject("$$$"); - - SendModel(); - - } else if (arg == "CONN_CLOSED") { - - fConnId = 0; - - } else if (arg == "RELOAD") { + if (arg == "RELOAD") { GetFunctionsFromSystem(); diff --git a/gui/webgui6/src/TWebCanvas.cxx b/gui/webgui6/src/TWebCanvas.cxx index b564e66ba3ec326f7d8f5179d54eabad4e80175f..93dd4b6f38b7b107d6255121999750af954c5db3 100644 --- a/gui/webgui6/src/TWebCanvas.cxx +++ b/gui/webgui6/src/TWebCanvas.cxx @@ -44,6 +44,8 @@ #include <sstream> #include <iostream> +using namespace std::string_literals; + //////////////////////////////////////////////////////////////////////////////// /// Constructor @@ -536,10 +538,28 @@ void TWebCanvas::ShowWebWindow(const ROOT::Experimental::RWebDisplayArgs &args) fWindow->SetDefaultPage("file:rootui5sys/canv/canvas6.html"); - fWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { - ProcessData(connid, arg); - CheckDataToSend(connid); - }); + fWindow->SetCallBacks( + // connection + [this](unsigned connid) { + fWebConn.emplace_back(connid); + CheckDataToSend(connid); + }, + // data + [this](unsigned connid, const std::string &arg) { + ProcessData(connid, arg); + CheckDataToSend(connid); + }, + // disconnect + [this](unsigned connid) { + unsigned indx = 0; + for (auto &c : fWebConn) { + if (c.fConnId == connid) { + fWebConn.erase(fWebConn.begin() + indx); + break; + } + indx++; + } + }); } auto w = Canvas()->GetWw(), h = Canvas()->GetWh(); @@ -563,10 +583,7 @@ void TWebCanvas::Show() void TWebCanvas::ShowCmd(const std::string &arg, Bool_t show) { - std::string cmd = "SHOW:"; - cmd.append(arg); - cmd.append(show ? ":1" : ":0"); - if (AddToSendQueue(0, cmd)) + if (AddToSendQueue(0, "SHOW:"s + arg + (show ? ":1"s : ":0"s))) CheckDataToSend(); } @@ -579,7 +596,7 @@ void TWebCanvas::ActivateInEditor(TPad *pad, TObject *obj) UInt_t hash = TString::Hash(&obj, sizeof(obj)); - if (AddToSendQueue(0, Form("EDIT:%u", (unsigned) hash))) + if (AddToSendQueue(0, "EDIT:"s + std::to_string(hash))) CheckDataToSend(); } @@ -636,11 +653,6 @@ Bool_t TWebCanvas::ProcessData(unsigned connid, const std::string &arg) if (arg.empty()) return kTRUE; - if (arg == "CONN_READY") { - fWebConn.emplace_back(connid); - return kTRUE; - } - // try to identify connection for given WS request unsigned indx = 0; for (auto &c : fWebConn) { @@ -652,11 +664,7 @@ Bool_t TWebCanvas::ProcessData(unsigned connid, const std::string &arg) const char *cdata = arg.c_str(); - if (arg == "CONN_CLOSED") { - - fWebConn.erase(fWebConn.begin() + indx); - - } else if (arg == "KEEPALIVE") { + if (arg == "KEEPALIVE") { // do nothing } else if (arg == "QUIT") { diff --git a/tutorials/webgui/panel/server.cxx b/tutorials/webgui/panel/server.cxx index b86eb2bef7e1a4ae9d7689877c3200d29a3760f3..8869a67843ebcd0f42c1dbbf4f96c3ad9e0e0824 100644 --- a/tutorials/webgui/panel/server.cxx +++ b/tutorials/webgui/panel/server.cxx @@ -30,38 +30,34 @@ struct TestPanelModel { std::shared_ptr<ROOT::Experimental::RWebWindow> window; std::unique_ptr<TestPanelModel> model; -void ProcessData(unsigned connid, const std::string &arg) -{ - if (arg == "CONN_READY") { - printf("connection established %u\n", connid); - TString json = TBufferJSON::ToJSON(model.get()); - window->Send(connid, std::string("MODEL:") + json.Data()); - return; - } +void ProcessConnection(unsigned connid) +{ + printf("connection established %u\n", connid); + TString json = TBufferJSON::ToJSON(model.get()); + window->Send(connid, std::string("MODEL:") + json.Data()); +} - if (arg == "CONN_CLOSED") { - printf("connection closed\n"); - return; - } +void ProcessCloseConnection(unsigned connid) +{ + printf("connection closed %u\n", connid); +} +void ProcessData(unsigned connid, const std::string &arg) +{ if (arg == "REFRESH") { // send model to client again printf("Resend model\n"); TString json = TBufferJSON::ToJSON(model.get()); window->Send(connid, std::string("MODEL:") + json.Data()); - return; - } - - if (arg.find("MODEL:") == 0) { + } else if (arg.find("MODEL:") == 0) { printf("Decode model %s\n", arg.c_str()); auto m = TBufferJSON::FromJSON<TestPanelModel>(arg.substr(6)); if (m) { - printf("Selected %s\n", m->fSelectId.c_str()); + printf("New model, selected %s\n", m->fSelectId.c_str()); std::swap(model, m); } - return; } } @@ -77,12 +73,13 @@ void server() // create window window = ROOT::Experimental::RWebWindow::Create(); - // this is very important, it defines name of openui5 widget + // Important - defines name of openui5 widget // "localapp" prefix indicates that all files located in current directory + // "localapp.view.TestPanel" means file ./view/TestPanel.view.xml will be loaded window->SetPanelName("localapp.view.TestPanel"); - // this is call-back, invoked when message received via websocket - window->SetDataCallBack(ProcessData); + // these are different callbacks + window->SetCallBacks(ProcessConnection, ProcessData, ProcessCloseConnection); window->SetGeometry(400, 500); // configure window geometry diff --git a/tutorials/webgui/webwindow/server.cxx b/tutorials/webgui/webwindow/server.cxx index 794a2d7c5b3e27cd27b9859aa8ba55502940ccd4..edd272bf76f68e89d0aa07ef81960114b26bde73 100644 --- a/tutorials/webgui/webwindow/server.cxx +++ b/tutorials/webgui/webwindow/server.cxx @@ -16,16 +16,6 @@ int counter{0}; void ProcessData(unsigned connid, const std::string &arg) { - if (arg == "CONN_READY") { - printf("connection established %u\n", connid); - return; - } - - if (arg == "CONN_CLOSED") { - printf("connection closed\n"); - return; - } - printf("Get msg %s \n", arg.c_str()); counter++;