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