tdaq-develop-2025-02-12
DesktopIconTableImpl.cc
1 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
2 #include "otsdaq/Macros/TablePluginMacros.h"
3 #include "otsdaq/TablePlugins/DesktopIconTable.h"
4 #include "otsdaq/TablePlugins/XDAQContextTable/XDAQContextTable.h"
5 
6 #include "otsdaq/WebUsersUtilities/WebUsers.h"
7 
8 #include <stdio.h>
9 #include <fstream> // std::fstream
10 #include <iostream>
11 using namespace ots;
12 
13 #define DESKTOP_ICONS_FILE \
14  std::string(__ENV__("SERVICE_DATA_PATH")) + "/OtsWizardData/iconList.dat"
15 
18 const std::string DesktopIconTable::COL_NAME = "IconName";
19 const std::string DesktopIconTable::COL_STATUS = TableViewColumnInfo::COL_NAME_STATUS;
20 const std::string DesktopIconTable::COL_CAPTION = "Caption";
21 const std::string DesktopIconTable::COL_ALTERNATE_TEXT = "AlternateText";
22 const std::string DesktopIconTable::COL_FORCE_ONLY_ONE_INSTANCE = "ForceOnlyOneInstance";
23 const std::string DesktopIconTable::COL_PERMISSIONS = "RequiredPermissionLevel";
24 const std::string DesktopIconTable::COL_IMAGE_URL = "ImageURL";
25 const std::string DesktopIconTable::COL_WINDOW_CONTENT_URL = "WindowContentURL";
26 const std::string DesktopIconTable::COL_APP_LINK = "LinkToApplicationTable";
27 const std::string DesktopIconTable::COL_APP_LINK_UID = "LinkToApplicationUID";
28 
29 const std::string DesktopIconTable::COL_PARAMETER_LINK = "LinkToParameterTable";
30 const std::string DesktopIconTable::COL_PARAMETER_LINK_GID = "LinkToParameterGroupID";
31 const std::string DesktopIconTable::COL_FOLDER_PATH = "FolderPath";
32 
33 const std::string DesktopIconTable::COL_PARAMETER_GID = "windowParameterGroupID";
34 const std::string DesktopIconTable::COL_PARAMETER_KEY = "windowParameterKey";
35 const std::string DesktopIconTable::COL_PARAMETER_VALUE = "windowParameterValue";
36 
37 const std::string DesktopIconTable::ICON_TABLE =
38  ConfigurationManager::DESKTOP_ICON_TABLE_NAME;
39 const std::string DesktopIconTable::PARAMETER_TABLE = "DesktopWindowParameterTable";
40 
41 // #define COL_NAME "IconName"
42 // #define COL_STATUS TableViewColumnInfo::COL_NAME_STATUS
43 // #define COL_CAPTION "Caption"
44 // #define COL_ALTERNATE_TEXT "AlternateText"
45 // #define COL_FORCE_ONLY_ONE_INSTANCE "ForceOnlyOneInstance"
46 // #define COL_REQUIRED_PERMISSION_LEVEL "RequiredPermissionLevel"
47 // #define COL_IMAGE_URL "ImageURL"
48 // #define COL_WINDOW_CONTENT_URL "WindowContentURL"
49 // #define COL_APP_LINK "LinkToApplicationTable"
50 // #define COL_PARAMETER_LINK "LinkToParameterTable"
51 // #define COL_PARAMETER_KEY "windowParameterKey"
52 // #define COL_PARAMETER_VALUE "windowParameterValue"
53 // #define COL_FOLDER_PATH "FolderPath"
54 
56 const std::string DesktopIconTable::COL_APP_ID = "Id";
57 // #define COL_APP_ID "Id"
58 
59 //==============================================================================
60 DesktopIconTable::DesktopIconTable(void) : TableBase(DesktopIconTable::ICON_TABLE)
61 {
62  // Icon list no longer passes through file! so delete it from user's $USER_DATA
63  std::system(("rm -rf " + (std::string)DESKTOP_ICONS_FILE).c_str());
64 
66  // WARNING: the names used in C++ MUST match the Table INFO //
68 }
69 
70 //==============================================================================
71 DesktopIconTable::~DesktopIconTable(void) {}
72 
73 //==============================================================================
75 {
76  // __COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << std::endl;
77  // __COUT__ << configManager->__SELF_NODE__ << std::endl;
78 
79  unsigned int intVal;
80 
81  auto childrenMap = configManager->__SELF_NODE__.getChildren();
82 
83  ConfigurationTree contextTableNode =
84  configManager->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
85  const XDAQContextTable* contextTable = configManager->getTable<XDAQContextTable>(
86  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
87 
88  // find gateway host origin string, to avoid modifying icons with same host
89  std::string gatewayContextUID = contextTable->getContextOfGateway(configManager);
90 
91  activeDesktopIcons_.clear();
92 
94  bool addedAppId;
95  bool numeric;
96  unsigned int i;
97  for(auto& child : childrenMap)
98  {
99  if(!child.second.getNode(COL_STATUS).getValue<bool>())
100  continue;
101  // __COUTV__(child.first);
102 
103  activeDesktopIcons_.push_back(DesktopIconTable::DesktopIcon());
104  icon = &(activeDesktopIcons_.back());
105 
106  icon->recordUID_ = child.first;
107  icon->caption_ = child.second.getNode(COL_CAPTION).getValue<std::string>();
108  icon->alternateText_ =
109  child.second.getNode(COL_ALTERNATE_TEXT).getValue<std::string>();
110  icon->enforceOneWindowInstance_ =
111  child.second.getNode(COL_FORCE_ONLY_ONE_INSTANCE).getValue<bool>();
113  child.second.getNode(COL_PERMISSIONS).getValue<std::string>();
114  icon->imageURL_ = child.second.getNode(COL_IMAGE_URL).getValue<std::string>();
115  icon->windowContentURL_ =
116  child.second.getNode(COL_WINDOW_CONTENT_URL).getValue<std::string>();
117  icon->folderPath_ = child.second.getNode(COL_FOLDER_PATH).getValue<std::string>();
118 
119  if(icon->windowContentURL_.size() == 0)
120  {
121  __SS__ << "Illegal empty URL in Desktop Icon '" << child.first << "'"
122  << __E__;
123  __SS_THROW__;
124  }
125 
126  if(icon->folderPath_ == TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
127  icon->folderPath_ = ""; // convert DEFAULT to empty string
128 
129  if(icon->permissionThresholdString_ ==
130  TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
132  "1"; // convert DEFAULT to standard user allow
133 
134  numeric = true;
135  for(i = 0; i < icon->permissionThresholdString_.size(); ++i)
136  if(!(icon->permissionThresholdString_[i] >= '0' &&
137  icon->permissionThresholdString_[i] <= '9'))
138  {
139  numeric = false;
140  break;
141  }
142  // for backwards compatibility, if permissions threshold is a single number
143  // assume it is the threshold intended for the WebUsers::DEFAULT_USER_GROUP group
144  if(numeric)
146  WebUsers::DEFAULT_USER_GROUP + ":" + icon->permissionThresholdString_;
147 
148  // remove all commas from member strings because desktop icons are served to
149  // client in comma-separated string
150  icon->caption_ = removeCommas(
151  icon->caption_, false /*andHexReplace*/, true /*andHTMLReplace*/);
152  icon->alternateText_ = removeCommas(
153  icon->alternateText_, false /*andHexReplace*/, true /*andHTMLReplace*/);
154  icon->imageURL_ = removeCommas(icon->imageURL_, true /*andHexReplace*/);
155  icon->windowContentURL_ =
156  removeCommas(icon->windowContentURL_, true /*andHexReplace*/);
157  icon->folderPath_ = removeCommas(
158  icon->folderPath_, false /*andHexReplace*/, true /*andHTMLReplace*/);
159 
160  // add application origin and URN/LID to windowContentURL_, if link is given
161  addedAppId = false;
162  ConfigurationTree appLink = child.second.getNode(COL_APP_LINK);
163  if(!appLink.isDisconnected())
164  {
165  // first check app origin
166  if(icon->windowContentURL_.size() && icon->windowContentURL_[0] == '/')
167  {
168  // if starting with opening slash, then assume app should come from
169  // appLink context's origin (to avoid cross-origin issues communicating
170  // with app/supervisor)
171  try
172  {
173  std::string contextUID = contextTable->getContextOfApplication(
174  configManager, appLink.getValueAsString());
175 
176  // only prepend address if not same as gateway
177  if(contextUID != gatewayContextUID)
178  {
179  // __COUTV__(contextUID);
180  ConfigurationTree contextNode =
181  contextTableNode.getNode(contextUID);
182 
183  std::string contextAddress =
184  contextNode.getNode(XDAQContextTable::colContext_.colAddress_)
185  .getValue<std::string>();
186  unsigned int contextPort =
187  contextNode.getNode(XDAQContextTable::colContext_.colPort_)
188  .getValue<unsigned int>();
189 
190  //__COUTV__(contextAddress);
191  icon->windowContentURL_ = contextAddress + ":" +
192  std::to_string(contextPort) +
193  icon->windowContentURL_;
194  //__COUTV__(icon->windowContentURL_);
195  }
196  }
197  catch(const std::runtime_error& e)
198  {
199  __SS__ << "Error finding XDAQ Application origin which was linked to "
200  "Desktop Icon '"
201  << child.first << "': " << e.what() << __E__;
202  ss << "\n\nPlease fix by disabling the Icon, enabling the App or "
203  "fixing the link in the Configurate Tree."
204  << __E__;
205  __SS_THROW__;
206  }
207  } // end app origin check
208 
209  // if last character is not '='
210  // then assume need to add "?urn="
211  if(icon->windowContentURL_[icon->windowContentURL_.size() - 1] != '=')
212  {
213  if(icon->windowContentURL_.find('?') ==
214  std::string::npos) //if no ? already
215  icon->windowContentURL_ += "?urn=";
216  else
217  icon->windowContentURL_ += "&urn=";
218  }
219 
220  // __COUT__ << "Following Application link." << std::endl;
221  appLink.getNode(COL_APP_ID).getValue(intVal);
222  icon->windowContentURL_ += std::to_string(intVal);
223 
224  // __COUT__ << "URN/LID=" << intVal << std::endl;
225  addedAppId = true;
226  }
227  // __COUTV__(icon->windowContentURL_);
228 
229  // add parameters if link is given
230  if(!child.second.getNode(COL_PARAMETER_LINK).isDisconnected())
231  {
232  // if there is no '?' found
233  // then assume need to add "?"
234  if(icon->windowContentURL_.find('?') == std::string::npos)
235  icon->windowContentURL_ += '?';
236  else if(addedAppId ||
237  icon->windowContentURL_[icon->windowContentURL_.size() - 1] !=
238  '?') // if not first parameter, add &
239  icon->windowContentURL_ += '&';
240 
241  // now add each paramter separated by &
242  auto paramGroupMap = child.second.getNode(COL_PARAMETER_LINK).getChildren();
243  bool notFirst = false;
244  for(const auto& param : paramGroupMap)
245  {
246  if(!param.second.isEnabled())
247  continue;
248 
249  if(notFirst)
250  icon->windowContentURL_ += '&';
251  else
252  notFirst = true;
253  icon->windowContentURL_ +=
254  StringMacros::encodeURIComponent(
255  param.second.getNode(COL_PARAMETER_KEY).getValue<std::string>()) +
256  "=" +
257  StringMacros::encodeURIComponent(
258  param.second.getNode(COL_PARAMETER_VALUE)
259  .getValue<std::string>());
260  }
261  }
262  } // end main icon extraction loop
263 
264 } // end init()
265 
266 //==============================================================================
269  const std::string& localURL) const
270 {
271  std::string retURL;
272  std::string contextAddress;
273 
274  if(localURL.size() && localURL[0] == '/')
275  {
276  ConfigurationTree contextTableNode =
277  configManager->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
278  const XDAQContextTable* contextTable = configManager->getTable<XDAQContextTable>(
279  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
280 
281  std::string gatewayContextUID = contextTable->getContextOfGateway(configManager);
282  ConfigurationTree contextNode = contextTableNode.getNode(gatewayContextUID);
283 
284  contextAddress = contextNode.getNode(XDAQContextTable::colContext_.colAddress_)
285  .getValue<std::string>();
286  unsigned int contextPort =
287  contextNode.getNode(XDAQContextTable::colContext_.colPort_)
288  .getValue<unsigned int>();
289 
290  try
291  {
292  if(__ENV__(
293  "OTS_REMOTE_ICONS_NO_PORT_FOWARDING")) //define this environment variable to not use localhost port forwarding to browser
294  contextAddress += ":" + std::to_string(contextPort);
295  else
296  contextAddress = std::string("http://") + "localhost" + ":" +
297  std::to_string(contextPort);
298  }
299  catch(...)
300  {
301  __COUTT__ << "Ignoring missing environment variable "
302  "OTS_REMOTE_ICONS_NO_PORT_FOWARDING, and assuming localhost "
303  "port forwarding to web browser."
304  << __E__;
305  contextAddress =
306  std::string("http://") + "localhost" + ":" + std::to_string(contextPort);
307  }
308  retURL = contextAddress + localURL;
309  }
310  else //if no starting '/' assume URL is already complete
311  retURL = localURL;
312 
313  //now add get parameters for remoteGateway
314  // if there is no '?' found
315  // then assume need to add "?"
316  if(retURL.find('?') == std::string::npos)
317  retURL += '?';
318  else if(retURL[retURL.size() - 1] != '?') // if not first parameter, add &
319  retURL += '&';
320  retURL += "remoteServerOrigin=" + StringMacros::encodeURIComponent(contextAddress) +
321  "&remoteServerUrnLid=" +
322  std::to_string(XDAQContextTable::XDAQApplication::GATEWAY_APP_ID);
323 
324  return retURL;
325 } // end getRemoteURL()
326 
327 //==============================================================================
328 std::string DesktopIconTable::removeCommas(const std::string& str,
329  bool andHexReplace,
330  bool andHTMLReplace)
331 {
332  std::string retStr = "";
333  retStr.reserve(str.length());
334 
335  for(unsigned int i = 0; i < str.length(); ++i)
336  if(str[i] != ',')
337  retStr += str[i];
338  else if(andHexReplace)
339  retStr += "%2C";
340  else if(andHTMLReplace)
341  retStr += "&#44;";
342 
343  return retStr;
344 } // end removeCommas()
345 
346 //==============================================================================
348  const std::vector<DesktopIconTable::DesktopIcon>& newIcons)
349 {
350  activeDesktopIcons_.clear();
351  for(const auto& newIcon : newIcons)
352  activeDesktopIcons_.push_back(newIcon);
353 
354 } // end setAllDesktopIcons
355 
356 DEFINE_OTS_TABLE(DesktopIconTable)
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
const T * getTable(const std::string &tableName) const
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, TableVersion > *memberMap=0, std::string *accumulatedTreeErrors=0) const
bool isDisconnected(void) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
const std::string & getValueAsString(bool returnLinkTableValue=false) const
void getValue(T &value) const
std::string getRemoteURL(ConfigurationManager *configManager, const std::string &localURL) const
Convert to remote URL assuming port forwarding to primary Gateway Port.
void init(ConfigurationManager *configManager)
Methods.
void setAllDesktopIcons(const std::vector< DesktopIconTable::DesktopIcon > &newIcons)
overwrite dynamically the init result
static const std::string COL_APP_ID
XDAQ App Column names.
static const std::string COL_NAME
std::string getContextOfGateway(ConfigurationManager *configManager) const
only considers ON contexts and applications
std::string getContextOfApplication(ConfigurationManager *configManager, const std::string &appUID) const
only considers ON contexts and applications