otsdaq  3.07.00
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 {
63  // WARNING: the names used in C++ MUST match the Table INFO //
65 }
66 
67 //==============================================================================
68 DesktopIconTable::~DesktopIconTable(void) {}
69 
70 //==============================================================================
72 {
73  // __COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << std::endl;
74  // __COUT__ << configManager->__SELF_NODE__ << std::endl;
75 
76  unsigned int intVal;
77 
78  auto childrenMap = configManager->__SELF_NODE__.getChildren();
79 
80  ConfigurationTree contextTableNode =
81  configManager->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
82  const XDAQContextTable* contextTable = configManager->getTable<XDAQContextTable>(
83  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
84 
85  // find gateway host origin string, to avoid modifying icons with same host
86  std::string gatewayContextUID = contextTable->getContextOfGateway(configManager);
87 
88  activeDesktopIcons_.clear();
89 
91  bool addedAppId;
92  bool numeric;
93  unsigned int i;
94  for(auto& child : childrenMap)
95  {
96  if(!child.second.getNode(COL_STATUS).getValue<bool>())
97  continue;
98  // __COUTV__(child.first);
99 
100  activeDesktopIcons_.push_back(DesktopIconTable::DesktopIcon());
101  icon = &(activeDesktopIcons_.back());
102 
103  icon->recordUID_ = child.first;
104  icon->caption_ = child.second.getNode(COL_CAPTION).getValue<std::string>();
105  icon->alternateText_ =
106  child.second.getNode(COL_ALTERNATE_TEXT).getValue<std::string>();
107  icon->enforceOneWindowInstance_ =
108  child.second.getNode(COL_FORCE_ONLY_ONE_INSTANCE).getValue<bool>();
110  child.second.getNode(COL_PERMISSIONS).getValueWithDefault<std::string>("1");
111  icon->imageURL_ = child.second.getNode(COL_IMAGE_URL).getValue<std::string>();
112  icon->windowContentURL_ =
113  child.second.getNode(COL_WINDOW_CONTENT_URL).getValue<std::string>();
114  icon->folderPath_ =
115  child.second.getNode(COL_FOLDER_PATH).getValueWithDefault<std::string>("");
116 
117  if(icon->windowContentURL_.size() == 0)
118  {
119  __SS__ << "Illegal empty URL in Desktop Icon '" << child.first << "'"
120  << __E__;
121  __SS_THROW__;
122  }
123 
124  numeric = true;
125  for(i = 0; i < icon->permissionThresholdString_.size(); ++i)
126  if(!(icon->permissionThresholdString_[i] >= '0' &&
127  icon->permissionThresholdString_[i] <= '9'))
128  {
129  numeric = false;
130  break;
131  }
132  // for backwards compatibility, if permissions threshold is a single number
133  // assume it is the threshold intended for the WebUsers::DEFAULT_USER_GROUP group
134  if(numeric)
136  WebUsers::DEFAULT_USER_GROUP + ":" + icon->permissionThresholdString_;
137 
138  // remove all commas from member strings because desktop icons are served to
139  // client in comma-separated string
140  icon->caption_ = removeCommas(
141  icon->caption_, false /*andHexReplace*/, true /*andHTMLReplace*/);
142  icon->alternateText_ = removeCommas(
143  icon->alternateText_, false /*andHexReplace*/, true /*andHTMLReplace*/);
144  icon->imageURL_ = removeCommas(icon->imageURL_, true /*andHexReplace*/);
145  icon->windowContentURL_ =
146  removeCommas(icon->windowContentURL_, true /*andHexReplace*/);
147  icon->folderPath_ = removeCommas(
148  icon->folderPath_, false /*andHexReplace*/, true /*andHTMLReplace*/);
149 
150  // add application origin and URN/LID to windowContentURL_, if link is given
151  addedAppId = false;
152  ConfigurationTree appLink = child.second.getNode(COL_APP_LINK);
153  if(!appLink.isDisconnected())
154  {
155  // first check app origin
156  if(icon->windowContentURL_.size() && icon->windowContentURL_[0] == '/')
157  {
158  // if starting with opening slash, then assume app should come from
159  // appLink context's origin (to avoid cross-origin issues communicating
160  // with app/supervisor)
161  try
162  {
163  std::string contextUID = contextTable->getContextOfApplication(
164  configManager,
165  appLink.getValueAsString(),
166  true /* allowOffContexts */);
167 
168  if(!appLink
169  .isEnabled()) //demoting off apps, from exception to error, to make it less annoying for users that are disabling apps
170  __COUT_WARN__
171  << "Warning! The target app '" << appLink.getValueAsString()
172  << "' is disabled, which will likely break the behavior of "
173  "the Desktop Icon '"
174  << child.first << ".' To fix, reenable the target app."
175  << __E__;
176 
177  // only prepend address if not same as gateway
178  if(contextUID != gatewayContextUID)
179  {
180  // __COUTV__(contextUID);
181  ConfigurationTree contextNode =
182  contextTableNode.getNode(contextUID);
183 
184  if(!contextNode
185  .isEnabled()) //demoting off apps, from exception to error, to make it less annoying for users that are disabling apps
186  __COUT_WARN__
187  << "Warning! The parent context '" << contextUID
188  << "' of the target app '" << appLink.getValueAsString()
189  << "' is disabled, which will likely break the behavior "
190  "of the Desktop Icon '"
191  << child.first
192  << ".' To fix, reenable the target app's parent context."
193  << __E__;
194 
195  std::string contextAddress =
196  contextNode.getNode(XDAQContextTable::colContext_.colAddress_)
197  .getValue<std::string>();
198  unsigned int contextPort =
199  contextNode.getNode(XDAQContextTable::colContext_.colPort_)
200  .getValue<unsigned int>();
201 
202  //__COUTV__(contextAddress);
203  icon->windowContentURL_ = contextAddress + ":" +
204  std::to_string(contextPort) +
205  icon->windowContentURL_;
206  //__COUTV__(icon->windowContentURL_);
207  }
208  }
209  catch(const std::runtime_error& e)
210  {
211  __SS__ << "Error finding XDAQ Application origin which was linked to "
212  "Desktop Icon '"
213  << child.first << "': " << e.what() << __E__;
214  ss << "\n\nPlease fix by disabling the Icon, enabling the App or "
215  "fixing the link in the Configurate Tree."
216  << __E__;
217  __SS_THROW__;
218  }
219  } // end app origin check
220 
221  // if last character is not '='
222  // then assume need to add "?urn="
223  if(icon->windowContentURL_[icon->windowContentURL_.size() - 1] != '=')
224  {
225  if(icon->windowContentURL_.find('?') ==
226  std::string::npos) //if no ? already
227  icon->windowContentURL_ += "?urn=";
228  else
229  icon->windowContentURL_ += "&urn=";
230  }
231 
232  // __COUT__ << "Following Application link." << std::endl;
233  appLink.getNode(COL_APP_ID).getValue(intVal);
234  icon->windowContentURL_ += std::to_string(intVal);
235 
236  // __COUT__ << "URN/LID=" << intVal << std::endl;
237  addedAppId = true;
238  }
239  // __COUTV__(icon->windowContentURL_);
240 
241  // add parameters if link is given
242  if(!child.second.getNode(COL_PARAMETER_LINK).isDisconnected())
243  {
244  // if there is no '?' found
245  // then assume need to add "?"
246  if(icon->windowContentURL_.find('?') == std::string::npos)
247  icon->windowContentURL_ += '?';
248  else if(addedAppId ||
249  icon->windowContentURL_[icon->windowContentURL_.size() - 1] !=
250  '?') // if not first parameter, add &
251  icon->windowContentURL_ += '&';
252 
253  // now add each paramter separated by &
254  auto paramGroupMap = child.second.getNode(COL_PARAMETER_LINK).getChildren();
255  bool notFirst = false;
256  for(const auto& param : paramGroupMap)
257  {
258  if(!param.second.isEnabled())
259  continue;
260 
261  if(notFirst)
262  icon->windowContentURL_ += '&';
263  else
264  notFirst = true;
265  icon->windowContentURL_ +=
266  StringMacros::encodeURIComponent(
267  param.second.getNode(COL_PARAMETER_KEY).getValue<std::string>()) +
268  "=" +
269  StringMacros::encodeURIComponent(
270  param.second.getNode(COL_PARAMETER_VALUE)
271  .getValue<std::string>());
272  }
273  }
274  } // end main icon extraction loop
275 
276 } // end init()
277 
278 //==============================================================================
281  const std::string& localURL,
282  bool doForWizMode /* = false */) const
283 {
284  std::string contextAddress;
285  { //get context address of gateway to use as origin for remote icons
286  ConfigurationTree contextTableNode =
287  configManager->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
288  const XDAQContextTable* contextTable = configManager->getTable<XDAQContextTable>(
289  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
290 
291  std::string gatewayContextUID = contextTable->getContextOfGateway(configManager);
292  ConfigurationTree contextNode = contextTableNode.getNode(gatewayContextUID);
293 
294  contextAddress = contextNode.getNode(XDAQContextTable::colContext_.colAddress_)
295  .getValue<std::string>();
296  unsigned int contextPort =
297  contextNode.getNode(XDAQContextTable::colContext_.colPort_)
298  .getValue<unsigned int>();
299 
300  try
301  {
302  if(__ENV__(
303  "OTS_REMOTE_ICONS_NO_PORT_FOWARDING")) //define this environment variable to not use localhost port forwarding to browser
304  contextAddress += ":" + std::to_string(contextPort);
305  else
306  contextAddress = std::string("http://") + "localhost" + ":" +
307  std::to_string(contextPort);
308  }
309  catch(...)
310  {
311  __COUTT__ << "Ignoring missing environment variable "
312  "OTS_REMOTE_ICONS_NO_PORT_FOWARDING, and assuming localhost "
313  "port forwarding to web browser."
314  << __E__;
315  contextAddress =
316  std::string("http://") + "localhost" + ":" + std::to_string(contextPort);
317  }
318  } //end context address retrieval block
319 
320  std::string retURL;
321  {
322  __COUTTV__(localURL);
323  if(localURL.size() && localURL[0] == '/')
324  retURL = contextAddress + localURL;
325  else //if no starting '/' assume URL is already complete
326  retURL = localURL;
327  }
328 
329  __COUTTV__(retURL);
330  //now add get parameters for remoteGateway
331  // if there is no '?' found
332  // then assume need to add "?"
333  if(retURL.find('?') == std::string::npos)
334  retURL += '?';
335  else if(retURL[retURL.size() - 1] != '?') // if not first parameter, add &
336  retURL += '&';
337  retURL +=
338  "remoteServerOrigin=" + StringMacros::encodeURIComponent(contextAddress) +
339  "&remoteServerUrnLid=" +
340  std::to_string(doForWizMode ? XDAQContextTable::XDAQApplication::WIZMODE_APP_ID
341  : XDAQContextTable::XDAQApplication::GATEWAY_APP_ID);
342 
343  if(doForWizMode)
344  retURL += "&forcedWizMode=1";
345 
346  __COUTTV__(retURL);
347  return retURL;
348 } // end getRemoteURL()
349 
350 //==============================================================================
351 std::string DesktopIconTable::removeCommas(const std::string& str,
352  bool andHexReplace,
353  bool andHTMLReplace)
354 {
355  std::string retStr = "";
356  retStr.reserve(str.length());
357 
358  for(unsigned int i = 0; i < str.length(); ++i)
359  if(str[i] != ',')
360  retStr += str[i];
361  else if(andHexReplace)
362  retStr += "%2C";
363  else if(andHTMLReplace)
364  retStr += "&#44;";
365 
366  return retStr;
367 } // end removeCommas()
368 
369 //==============================================================================
371  const std::vector<DesktopIconTable::DesktopIcon>& newIcons)
372 {
373  activeDesktopIcons_.clear();
374  for(const auto& newIcon : newIcons)
375  activeDesktopIcons_.push_back(newIcon);
376 
377 } // end setAllDesktopIcons
378 
379 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, bool doForWizMode=false) 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 getContextOfApplication(ConfigurationManager *configManager, const std::string &appUID, bool allowOffContexts=false) const
only considers ON contexts and applications, unless off contexts allows
std::string getContextOfGateway(ConfigurationManager *configManager) const
only considers ON contexts and applications
defines used also by OtsConfigurationWizardSupervisor