@@ -1133,6 +1133,7 @@ int doChild(int argc, char** argv, ServiceRegistry& serviceRegistry,
11331133 };
11341134
11351135 runner.AddHook <fair::mq::hooks::InstantiateDevice>(afterConfigParsingCallback);
1136+
11361137 auto result = runner.Run ();
11371138 serviceRegistry.preExitCallbacks ();
11381139 return result;
@@ -1242,29 +1243,30 @@ int runStateMachine(DataProcessorSpecs const& workflow,
12421243 decltype (debugGUI->getGUIDebugger (infos, runningWorkflow.devices , dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl)) debugGUICallback;
12431244
12441245 // An empty frameworkId means this is the driver, so we initialise the GUI
1245- if ((driverInfo.batch == false || getenv (" DPL_DRIVER_REMOTE_GUI" ) != nullptr ) && frameworkId.empty ()) {
1246- auto initDebugGUI = []() -> DebugGUI* {
1247- uv_lib_t supportLib;
1248- int result = 0 ;
1246+ auto initDebugGUI = []() -> DebugGUI* {
1247+ uv_lib_t supportLib;
1248+ int result = 0 ;
12491249#ifdef __APPLE__
1250- result = uv_dlopen (" libO2FrameworkGUISupport.dylib" , &supportLib);
1250+ result = uv_dlopen (" libO2FrameworkGUISupport.dylib" , &supportLib);
12511251#else
1252- result = uv_dlopen (" libO2FrameworkGUISupport.so" , &supportLib);
1252+ result = uv_dlopen (" libO2FrameworkGUISupport.so" , &supportLib);
12531253#endif
1254- if (result == -1 ) {
1255- LOG (error) << uv_dlerror (&supportLib);
1256- return nullptr ;
1257- }
1258- DPLPluginHandle* (*dpl_plugin_callback)(DPLPluginHandle*);
1254+ if (result == -1 ) {
1255+ LOG (error) << uv_dlerror (&supportLib);
1256+ return nullptr ;
1257+ }
1258+ DPLPluginHandle* (*dpl_plugin_callback)(DPLPluginHandle*);
12591259
1260- result = uv_dlsym (&supportLib, " dpl_plugin_callback" , (void **)&dpl_plugin_callback);
1261- if (result == -1 ) {
1262- LOG (error) << uv_dlerror (&supportLib);
1263- return nullptr ;
1264- }
1265- DPLPluginHandle* pluginInstance = dpl_plugin_callback (nullptr );
1266- return PluginManager::getByName<DebugGUI>(pluginInstance, " ImGUIDebugGUI" );
1267- };
1260+ result = uv_dlsym (&supportLib, " dpl_plugin_callback" , (void **)&dpl_plugin_callback);
1261+ if (result == -1 ) {
1262+ LOG (error) << uv_dlerror (&supportLib);
1263+ return nullptr ;
1264+ }
1265+ DPLPluginHandle* pluginInstance = dpl_plugin_callback (nullptr );
1266+ return PluginManager::getByName<DebugGUI>(pluginInstance, " ImGUIDebugGUI" );
1267+ };
1268+
1269+ if ((driverInfo.batch == false || getenv (" DPL_DRIVER_REMOTE_GUI" ) != nullptr ) && frameworkId.empty ()) {
12681270 debugGUI = initDebugGUI ();
12691271 if (debugGUI) {
12701272 if (driverInfo.batch == false ) {
@@ -1273,6 +1275,17 @@ int runStateMachine(DataProcessorSpecs const& workflow,
12731275 window = debugGUI->initGUI (nullptr );
12741276 }
12751277 }
1278+ } else if (getenv (" DPL_DEVICE_REMOTE_GUI" ) && !frameworkId.empty ()) {
1279+ debugGUI = initDebugGUI ();
1280+ // We never run the GUI on desktop for devices. All
1281+ // you can do is to connect to the remote version.
1282+ // this is done to avoid having a proliferation of
1283+ // GUIs popping up when the variable is set globally.
1284+ // FIXME: maybe this is not what we want, but it should
1285+ // be ok for now.
1286+ if (debugGUI) {
1287+ window = debugGUI->initGUI (nullptr );
1288+ }
12761289 }
12771290 if (driverInfo.batch == false && window == nullptr && frameworkId.empty ()) {
12781291 LOG (warn) << " Could not create GUI. Switching to batch mode. Do you have GLFW on your system?" ;
@@ -1317,7 +1330,6 @@ int runStateMachine(DataProcessorSpecs const& workflow,
13171330 guiContext.frameLatency = &driverInfo.frameLatency ;
13181331 guiContext.frameCost = &driverInfo.frameCost ;
13191332 guiContext.guiQuitRequested = &guiQuitRequested;
1320- auto inputProcessingLast = guiContext.frameLast ;
13211333
13221334 // This is to make sure we can process metrics, commands, configuration
13231335 // changes coming from websocket (or even via any standard uv_stream_t, I guess).
@@ -1331,11 +1343,27 @@ int runStateMachine(DataProcessorSpecs const& workflow,
13311343 serverContext.driver = &driverInfo;
13321344 serverContext.metricProcessingCallbacks = &metricProcessingCallbacks;
13331345 serverContext.gui = &guiContext;
1346+ serverContext.isDriver = frameworkId.empty ();
13341347
13351348 uv_tcp_t serverHandle;
13361349 serverHandle.data = &serverContext;
13371350 uv_tcp_init (loop, &serverHandle);
1351+
13381352 driverInfo.port = 8080 + (getpid () % 30000 );
1353+
1354+ if (getenv (" DPL_REMOTE_GUI_PORT" )) {
1355+ try {
1356+ driverInfo.port = stoi (std::string (getenv (" DPL_REMOTE_GUI_PORT" )));
1357+ } catch (std::invalid_argument) {
1358+ LOG (error) << " DPL_REMOTE_GUI_PORT not a valid integer" ;
1359+ } catch (std::out_of_range) {
1360+ LOG (error) << " DPL_REMOTE_GUI_PORT out of range (integer)" ;
1361+ }
1362+ if (driverInfo.port < 1024 || driverInfo.port > 65535 ) {
1363+ LOG (error) << " DPL_REMOTE_GUI_PORT out of range (1024-65535)" ;
1364+ }
1365+ }
1366+
13391367 int result = 0 ;
13401368 struct sockaddr_in * serverAddr = nullptr ;
13411369
@@ -1346,9 +1374,28 @@ int runStateMachine(DataProcessorSpecs const& workflow,
13461374 // the future to inspect them via some web based interface.
13471375 if (frameworkId.empty ()) {
13481376 do {
1349- if (serverAddr) {
1350- free (serverAddr);
1377+ free (serverAddr);
1378+ if (driverInfo.port > 64000 ) {
1379+ throw runtime_error_f (" Unable to find a free port for the driver. Last attempt returned %d" , result);
13511380 }
1381+ serverAddr = (sockaddr_in*)malloc (sizeof (sockaddr_in));
1382+ uv_ip4_addr (" 0.0.0.0" , driverInfo.port , serverAddr);
1383+ auto bindResult = uv_tcp_bind (&serverHandle, (const struct sockaddr *)serverAddr, 0 );
1384+ if (bindResult != 0 ) {
1385+ driverInfo.port ++;
1386+ usleep (1000 );
1387+ continue ;
1388+ }
1389+ result = uv_listen ((uv_stream_t *)&serverHandle, 100 , ws_connect_callback);
1390+ if (result != 0 ) {
1391+ driverInfo.port ++;
1392+ usleep (1000 );
1393+ continue ;
1394+ }
1395+ } while (result != 0 );
1396+ } else if (getenv (" DPL_DEVICE_REMOTE_GUI" ) && !frameworkId.empty ()) {
1397+ do {
1398+ free (serverAddr);
13521399 if (driverInfo.port > 64000 ) {
13531400 throw runtime_error_f (" Unable to find a free port for the driver. Last attempt returned %d" , result);
13541401 }
@@ -1366,6 +1413,7 @@ int runStateMachine(DataProcessorSpecs const& workflow,
13661413 usleep (1000 );
13671414 continue ;
13681415 }
1416+ LOG (info) << " Device GUI port: " << driverInfo.port << " " << frameworkId;
13691417 } while (result != 0 );
13701418 }
13711419
@@ -2719,7 +2767,7 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow,
27192767 // values are not filled into the vector, even if specifying `-b true`
27202768 // need to find out why the boost program options example is not working
27212769 // in our case. Might depend on the parser options
2722- // auto value = varmap["batch"].as<std::vector<std::string>>();
2770+ // auto value = varmap["batch"].as<std::vector<std::string>>();
27232771 return true ;
27242772 };
27252773 DriverInfo driverInfo{
0 commit comments