otsdaq-utilities  3.02.00
MacroMakerSupervisor.cc
1 #include "otsdaq-utilities/MacroMaker/MacroMakerSupervisor.h"
2 
3 #include "otsdaq/CodeEditor/CodeEditor.h"
4 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
5 #include "otsdaq/FECore/FEVInterface.h"
6 
7 #include "otsdaq/NetworkUtilities/TransceiverSocket.h" // for UDP remote control
8 
9 #include <dirent.h> //for DIR
10 #include <stdio.h> //for file rename
11 #include <sys/stat.h> //for mkdir
12 #include <cstdio>
13 #include <filesystem> //for std::filesytem
14 #include <fstream>
15 #include <thread> //for std::thread
16 #include "otsdaq/TableCore/TableGroupKey.h"
17 
18 #define MACROS_DB_PATH std::string(__ENV__("SERVICE_DATA_PATH")) + "/MacroData/"
19 #define MACROS_HIST_PATH std::string(__ENV__("SERVICE_DATA_PATH")) + "/MacroHistory/"
20 #define MACROS_SEQUENCE_PATH std::string(__ENV__("SERVICE_DATA_PATH")) + "/MacroSequence/"
21 #define MACROS_EXPORT_PATH std::string("/MacroExport/")
22 
23 #define SEQUENCE_FILE_NAME \
24  std::string(__ENV__("SERVICE_DATA_PATH")) + "/OtsWizardData/sequence.dat"
25 #define SEQUENCE_OUT_FILE_NAME \
26  std::string(__ENV__("SERVICE_DATA_PATH")) + "/OtsWizardData/sequence.out"
27 
28 using namespace ots;
29 
30 #undef __MF_SUBJECT__
31 #define __MF_SUBJECT__ "MacroMaker"
32 
33 XDAQ_INSTANTIATOR_IMPL(MacroMakerSupervisor)
34 
35 //==============================================================================
36 MacroMakerSupervisor::MacroMakerSupervisor(xdaq::ApplicationStub* stub)
37  : CoreSupervisorBase(stub)
38 {
39  __SUP_COUT__ << "Constructing..." << __E__;
40 
41  INIT_MF("." /*directory used is USER_DATA/LOG/.*/);
42 
43  // make macro directories in case they don't exist
44  mkdir(((std::string)MACROS_DB_PATH).c_str(), 0755);
45  mkdir(((std::string)MACROS_HIST_PATH).c_str(), 0755);
46  mkdir(((std::string)MACROS_SEQUENCE_PATH).c_str(), 0755);
47  mkdir((__ENV__("SERVICE_DATA_PATH") + MACROS_EXPORT_PATH).c_str(), 0755);
48 
49  xoap::bind(this,
50  &MacroMakerSupervisor::frontEndCommunicationRequest,
51  "FECommunication",
52  XDAQ_NS_URI);
53 
54  // start requests for MacroMaker only mode
55  if(CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
56  {
57  __SUP_COUT__ << "Starting constructor for Macro Maker mode." << __E__;
58 
59  xgi::bind(this, &MacroMakerSupervisor::requestIcons, "requestIcons");
60  xgi::bind(this, &MacroMakerSupervisor::verification, "Verify");
61  xgi::bind(this, &MacroMakerSupervisor::tooltipRequest, "TooltipRequest");
62  xgi::bind(this, &MacroMakerSupervisor::requestWrapper, "Request");
63  xoap::bind(this,
64  &MacroMakerSupervisor::supervisorSequenceCheck,
65  "SupervisorSequenceCheck",
66  XDAQ_NS_URI);
67  generateURL();
68  __SUP_COUT__ << "Completed constructor for Macro Maker mode." << __E__;
69  }
70  else
71  __SUP_COUT__ << "Not Macro Maker only mode." << __E__;
72  // end requests for MacroMaker only mode
73 
74  init();
75 
76  // initFElist for Macro Maker mode
77  if(CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
78  {
79  // const SupervisorInfoMap& feTypeSupervisors =
80  // CorePropertySupervisorBase::allSupervisorInfo_.getAllFETypeSupervisorInfo();
81 
82  ConfigurationTree appsNode = theConfigurationManager_->getNode(
83  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME);
84 
85  // __SUP_COUT__ << "Number of FE Supervisors found = " << feTypeSupervisors.size()
86  // << __E__;
87 
88  FEPluginTypetoFEsMap_.clear(); // reset
89  FEtoSupervisorMap_.clear(); // reset
90  FEtoPluginTypeMap_.clear(); // reset
91  // for(auto& feApp : feTypeSupervisors)
92  // {
93  __SUP_COUT__ << "FEs for app MacroMakerFESupervisor"
94  << __E__; // << feApp.first << ":" << feApp.second.getName()
95  // << __E__;
96 
97  auto feChildren =
98  appsNode
99  .getNode("MacroMakerFESupervisor") // feApp.second.getName())
100  .getNode("LinkToSupervisorTable")
101  .getNode("LinkToFEInterfaceTable")
102  .getChildren();
103 
104  for(auto& fe : feChildren)
105  {
106  if(!fe.second.status())
107  continue; // skip disabled FEs
108 
109  __SUP_COUTV__(fe.first);
110  FEtoSupervisorMap_[fe.first] =
111  atoi(__ENV__("FE_SUPERVISOR_ID")); // feApp.first;
112 
113  std::string pluginType =
114  fe.second.getNode("FEInterfacePluginName").getValue();
115  FEPluginTypetoFEsMap_[pluginType].emplace(fe.first);
116  FEtoPluginTypeMap_[fe.first] = pluginType;
117  }
118  // }
119 
120  __SUP_COUTV__(StringMacros::mapToString(FEtoSupervisorMap_));
121  __SUP_COUTV__(StringMacros::mapToString(FEPluginTypetoFEsMap_));
122  __SUP_COUTV__(StringMacros::mapToString(FEtoPluginTypeMap_));
123  }
124 
125  //setup UDP interface thread if env variable set for port
126  {
127  bool enableRemoteControl = false;
128  try
129  {
130  __ENV__("OTS_MACROMAKER_UDP_PORT");
131  __ENV__("OTS_MACROMAKER_UDP_IP");
132  enableRemoteControl = true;
133  }
134  catch(...)
135  {
136  ;
137  } // ignore errors
138 
139  if(enableRemoteControl)
140  {
141  __SUP_COUT__ << "Enabling remote control over UDP..." << __E__;
142  // start state changer UDP listener thread
143  std::thread(
144  [](MacroMakerSupervisor* s) {
145  MacroMakerSupervisor::RemoteControlWorkLoop(s);
146  },
147  this)
148  .detach();
149  }
150  else
151  __SUP_COUT__ << "Remote control over UDP is disabled." << __E__;
152  } // end setting up thread for UDP drive of state machine
153 
154  __SUP_COUT__ << "Constructed." << __E__;
155 } // end constructor
156 
157 //==============================================================================
158 MacroMakerSupervisor::~MacroMakerSupervisor(void) { destroy(); }
159 
160 //==============================================================================
161 void MacroMakerSupervisor::init(void)
162 {
163  // called by constructor
164 
165  // MacroMaker should consider all FE compatible types..
166  allFESupervisorInfo_ =
167  SupervisorInfoMap(allSupervisorInfo_.getAllFETypeSupervisorInfo());
168 
169 } // end init()
170 
171 //==============================================================================
172 void MacroMakerSupervisor::destroy(void)
173 {
174  // called by destructor
175 }
176 
177 //==============================================================================
181 } // end forceSupervisorPropertyValues()
182 
183 //==============================================================================
184 void MacroMakerSupervisor::tooltipRequest(xgi::Input* in, xgi::Output* out)
185 {
186  cgicc::Cgicc cgi(in);
187 
188  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
189  //__COUT__ << "Command = " << Command << __E__;
190 
191  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
192 
193  // SECURITY CHECK START ****
194  if(securityCode_.compare(submittedSequence) != 0)
195  {
196  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
197  << __E__;
198  return;
199  }
200  // else
201  // {
202  // __COUT__ << "***Successfully authenticated security sequence." << __E__;
203  // }
204  // SECURITY CHECK END ****
205 
206  HttpXmlDocument xmldoc;
207 
208  if(Command == "check")
209  {
210  WebUsers::tooltipCheckForUsername(WebUsers::DEFAULT_ADMIN_USERNAME,
211  &xmldoc,
212  CgiDataUtilities::getData(cgi, "srcFile"),
213  CgiDataUtilities::getData(cgi, "srcFunc"),
214  CgiDataUtilities::getData(cgi, "srcId"));
215  }
216  else if(Command == "setNeverShow")
217  {
219  WebUsers::DEFAULT_ADMIN_USERNAME,
220  &xmldoc,
221  CgiDataUtilities::getData(cgi, "srcFile"),
222  CgiDataUtilities::getData(cgi, "srcFunc"),
223  CgiDataUtilities::getData(cgi, "srcId"),
224  CgiDataUtilities::getData(cgi, "doNeverShow") == "1" ? true : false,
225  CgiDataUtilities::getData(cgi, "temporarySilence") == "1" ? true : false);
226  }
227  else
228  __COUT__ << "Command Request, " << Command << ", not recognized." << __E__;
229 
230  xmldoc.outputXmlDocument((std::ostringstream*)out, false, true);
231 } // end tooltipRequest()
232 
233 //==============================================================================
234 void MacroMakerSupervisor::verification(xgi::Input* in, xgi::Output* out)
235 {
236  cgicc::Cgicc cgi(in);
237  std::string submittedSequence = CgiDataUtilities::getData(cgi, "code");
238  __COUT__ << "submittedSequence=" << submittedSequence << " " << time(0) << __E__;
239 
240  std::string securityWarning = "";
241 
242  if(securityCode_.compare(submittedSequence) != 0)
243  {
244  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
245  << __E__;
246  *out << "Invalid code.";
247  return;
248  }
249  else
250  {
251  // defaultSequence_ = false;
252  __COUT__ << "*** Successfully authenticated security sequence "
253  << "@ " << time(0) << __E__;
254 
255  if(defaultSequence_)
256  {
257  //__COUT__ << " UNSECURE!!!" << __E__;
258  securityWarning = "&secure=False";
259  }
260  }
261 
262  *out << "<!DOCTYPE HTML><html lang='en'><head><title>ots MacroMaker mode</title>" <<
263  // show ots icon
264  // from http://www.favicon-generator.org/
265  "<link rel='apple-touch-icon' sizes='57x57' href='/WebPath/images/otsdaqIcons/apple-icon-57x57.png'>\
266  <link rel='apple-touch-icon' sizes='60x60' href='/WebPath/images/otsdaqIcons/apple-icon-60x60.png'>\
267  <link rel='apple-touch-icon' sizes='72x72' href='/WebPath/images/otsdaqIcons/apple-icon-72x72.png'>\
268  <link rel='apple-touch-icon' sizes='76x76' href='/WebPath/images/otsdaqIcons/apple-icon-76x76.png'>\
269  <link rel='apple-touch-icon' sizes='114x114' href='/WebPath/images/otsdaqIcons/apple-icon-114x114.png'>\
270  <link rel='apple-touch-icon' sizes='120x120' href='/WebPath/images/otsdaqIcons/apple-icon-120x120.png'>\
271  <link rel='apple-touch-icon' sizes='144x144' href='/WebPath/images/otsdaqIcons/apple-icon-144x144.png'>\
272  <link rel='apple-touch-icon' sizes='152x152' href='/WebPath/images/otsdaqIcons/apple-icon-152x152.png'>\
273  <link rel='apple-touch-icon' sizes='180x180' href='/WebPath/images/otsdaqIcons/apple-icon-180x180.png'>\
274  <link rel='icon' type='image/png' sizes='192x192' href='/WebPath/images/otsdaqIcons/android-icon-192x192.png'>\
275  <link rel='icon' type='image/png' sizes='32x32' href='/WebPath/images/otsdaqIcons/favicon-32x32.png'>\
276  <link rel='icon' type='image/png' sizes='96x96' href='/WebPath/images/otsdaqIcons/favicon-96x96.png'>\
277  <link rel='icon' type='image/png' sizes='16x16' href='/WebPath/images/otsdaqIcons/favicon-16x16.png'>\
278  <link rel='manifest' href='/WebPath/images/otsdaqIcons/manifest.json'>\
279  <meta name='msapplication-TileColor' content='#ffffff'>\
280  <meta name='msapplication-TileImage' content='/ms-icon-144x144.png'>\
281  <meta name='theme-color' content='#ffffff'>"
282  <<
283  // end show ots icon
284  "</head>"
285  << "<frameset col='100%' row='100%'><frame "
286  "src='/WebPath/html/MacroMakerSupervisor.html?urn="
287  << this->getApplicationDescriptor()->getLocalId() << securityWarning
288  << "'></frameset></html>";
289 } // end verification()
290 
291 //==============================================================================
292 void MacroMakerSupervisor::generateURL()
293 {
294  defaultSequence_ = true;
295 
296  int length = 4;
297  FILE* fp = fopen((SEQUENCE_FILE_NAME).c_str(), "r");
298  if(fp)
299  {
300  __SUP_COUT_INFO__ << "Sequence length file found: " << SEQUENCE_FILE_NAME
301  << __E__;
302  char line[100];
303  fgets(line, 100, fp);
304  sscanf(line, "%d", &length);
305  fclose(fp);
306  if(length < 4)
307  length = 4; // don't allow shorter than 4
308  else
309  defaultSequence_ = false;
310  srand(time(0)); // randomize differently each "time"
311  }
312  else
313  {
314  __SUP_COUT_INFO__
315  << "(Reverting to default wiz security) Sequence length file NOT found: "
316  << SEQUENCE_FILE_NAME << __E__;
317  srand(0); // use same seed for convenience if file not found
318  }
319 
320  __SUP_COUT__ << "Sequence length = " << length << __E__;
321 
322  securityCode_ = "";
323 
324  const char alphanum[] =
325  "0123456789"
326  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
327  "abcdefghijklmnopqrstuvwxyz";
328 
329  for(int i = 0; i < length; ++i)
330  {
331  securityCode_ += alphanum[rand() % (sizeof(alphanum) - 1)];
332  }
333 
334  __SUP_COUT__ << __ENV__("HOSTNAME") << ":" << __ENV__("PORT")
335  << "/urn:xdaq-application:lid="
336  << this->getApplicationDescriptor()->getLocalId()
337  << "/Verify?code=" << securityCode_ << __E__;
338 
339  // Note: print out handled by start ots script now
340  // std::thread([&](WizardSupervisor *ptr, std::string securityCode)
341  // {printURL(ptr,securityCode);},this,securityCode_).detach();
342 
343  fp = fopen((SEQUENCE_OUT_FILE_NAME).c_str(), "w");
344  if(fp)
345  {
346  fprintf(fp, "%s", securityCode_.c_str());
347  fclose(fp);
348  }
349  else
350  __SUP_COUT_ERR__ << "Sequence output file NOT found: " << SEQUENCE_OUT_FILE_NAME
351  << __E__;
352 
353  return;
354 } // end generateURL()
355 
356 //==============================================================================
357 void MacroMakerSupervisor::requestIcons(xgi::Input* in, xgi::Output* out)
358 {
359  cgicc::Cgicc cgi(in);
360 
361  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
362 
363  // SECURITY CHECK START ****
364  if(securityCode_.compare(submittedSequence) != 0)
365  {
366  __COUT__ << "Unauthorized Request made, security sequence doesn't match! "
367  << time(0) << __E__;
368  return;
369  }
370  else
371  {
372  __COUT__ << "***Successfully authenticated security sequence. " << time(0)
373  << __E__;
374  }
375  // SECURITY CHECK END ****
376 
377  // an icon is 7 fields.. give comma-separated
378  // 0 - subtext = text below icon
379  // 1 - altText = text for icon if image set to 0
380  // 2 - uniqueWin = if true, only one window is allowed, else multiple instances of
381  // window 3 - permissions = security level needed to see icon 4 - picfn = icon image
382  // filename, 0 for no image 5 - linkurl = url of the window to open 6 - folderPath =
383  // folder and subfolder location
384 
385  *out << "Macro Maker "
386  ",MM,0,1,icon-MacroMaker.png,/WebPath/html/"
387  "MacroMaker.html?urn=290,/"
388  ",FE Macros"
389  ",CFG,0,1,icon-Configure.png,/WebPath/html/"
390  "FEMacroTest.html?urn=290,/"
391  // << ",Console,C,1,1,icon-Console.png,/urn:xdaq-application:lid=260/,/"
392  << ",Code Editor,CODE,0,1,icon-CodeEditor.png,/urn:xdaq-application:lid=240/,/"
393  << "";
394 
395  // if there is a file of more icons, add to end of output
396  std::string iconFile = std::string(__ENV__("USER_DATA")) + "/MacroMakerModeIcons.dat";
397  __COUT__ << "Macro Maker mode user icons file: " << iconFile << __E__;
398  FILE* fp = fopen(iconFile.c_str(), "r");
399  if(fp)
400  {
401  __COUT__ << "Macro Maker mode user icons loading from " << iconFile << __E__;
402  fseek(fp, 0, SEEK_END);
403  const unsigned long fileSize = ftell(fp);
404  std::string fileString(fileSize, 0);
405  rewind(fp);
406  if(fread(&fileString[0], 1, fileSize, fp) != fileSize)
407  {
408  __COUT_ERR__ << "Unable to read proper size string from icons file!" << __E__;
409  return;
410  }
411 
412  fclose(fp);
413  __COUTV__(fileString);
414  *out << fileString;
415  }
416  else
417  __COUT__ << "Macro Maker mode user icons file not found: " << iconFile << __E__;
418  return;
419 } // end requestIcons()
420 
421 //==============================================================================
424 xoap::MessageReference MacroMakerSupervisor::supervisorSequenceCheck(
425  xoap::MessageReference message)
426 {
427  // SOAPUtilities::receive request parameters
428  SOAPParameters parameters;
429  parameters.addParameter("sequence");
430  SOAPUtilities::receive(message, parameters);
431 
432  std::string submittedSequence = parameters.getValue("sequence");
433 
434  // If submittedSequence matches securityCode_ then return full permissions (255)
435  // else, return permissions 0
436  std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> permissionMap;
437 
438  if(securityCode_ == submittedSequence)
439  permissionMap.emplace(
440  std::pair<std::string /*groupName*/, WebUsers::permissionLevel_t>(
441  WebUsers::DEFAULT_USER_GROUP, WebUsers::PERMISSION_LEVEL_ADMIN));
442  else
443  {
444  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
445  << std::endl;
446 
447  permissionMap.emplace(
448  std::pair<std::string /*groupName*/, WebUsers::permissionLevel_t>(
449  WebUsers::DEFAULT_USER_GROUP, WebUsers::PERMISSION_LEVEL_INACTIVE));
450  }
451 
452  // fill return parameters
453  SOAPParameters retParameters;
454  retParameters.addParameter("Permissions", StringMacros::mapToString(permissionMap));
455 
456  return SOAPUtilities::makeSOAPMessageReference("SequenceResponse", retParameters);
457 } //end supervisorSequenceCheck()
458 
459 //==============================================================================
462 void MacroMakerSupervisor::RemoteControlWorkLoop(MacroMakerSupervisor* theSupervisor)
463 {
464  // ConfigurationTree configLinkNode = theSupervisor->CorePropertySupervisorBase::getSupervisorTableNode();
465 
466  std::string ipAddressForRemoteControlOverUDP = __ENV__(
467  "OTS_MACROMAKER_UDP_IP"); //configLinkNode.getNode("IPAddressForStateChangesOverUDP").getValue<std::string>();
468  int portForRemoteControlOverUDP = atoi(__ENV__(
469  "OTS_MACROMAKER_UDP_PORT")); //configLinkNode.getNode("PortForStateChangesOverUDP").getValue<int>();
470  bool acknowledgementEnabled =
471  true; //configLinkNode.getNode("EnableAckForStateChangesOverUDP").getValue<bool>();
472 
473  __COUTV__(ipAddressForRemoteControlOverUDP);
474  __COUTV__(portForRemoteControlOverUDP);
475  __COUTV__(acknowledgementEnabled);
476 
477  TransceiverSocket sock(ipAddressForRemoteControlOverUDP,
478  portForRemoteControlOverUDP); // Take Port from Table
479  try
480  {
481  sock.initialize();
482  }
483  catch(...)
484  {
485  // generate special message to indicate failed socket
486  __SS__ << "FATAL Console error. Could not initialize socket at ip '"
487  << ipAddressForRemoteControlOverUDP << "' and port "
488  << portForRemoteControlOverUDP
489  << ". Perhaps it is already in use? Exiting Remote Control "
490  "SOAPUtilities::receive loop."
491  << __E__;
492  __SS_THROW__;
493  return;
494  }
495 
496  std::string buffer;
497  __COUT__ << "UDP Remote Control workloop starting..." << __E__;
498  while(1)
499  {
500  // workloop procedure
501  // if SOAPUtilities::receive a UDP command
502  // execute command
503  // else
504  // sleep
505 
506  if(sock.receive(
507  buffer, 0 /*timeoutSeconds*/, 1 /*timeoutUSeconds*/, false /*verbose*/) !=
508  -1)
509  {
510  __COUT__ << "UDP Remote Control packet received of size = " << buffer.size()
511  << __E__;
512  __COUTV__(buffer);
513 
514  try
515  {
516  if(buffer == "GetFrontendMacroInfo")
517  {
518  HttpXmlDocument xmldoc;
519  theSupervisor->getFEMacroList(xmldoc, "NO-USER");
520 
521  std::stringstream out;
522  xmldoc.outputXmlDocument((std::ostringstream*)&out,
523  false /*dispStdOut*/,
524  false /*allowWhiteSpace*/);
525  __COUT__ << "out: " << out.str();
526  sock.acknowledge(out.str(), true /* verbose */);
527  }
528  else if(buffer.find("RunFrontendMacro") == 0)
529  {
530  HttpXmlDocument xmldoc;
531  __COUTV__(buffer);
532  std::vector<std::string> bufferFields =
533  StringMacros::getVectorFromString(buffer, {';'});
534  if(bufferFields.size() < 8)
535  {
536  __SS__ << "Missing input arguments for running FE Macro: "
537  << bufferFields.size() << " vs 8 expected" << __E__;
538  __SS_THROW__;
539  }
540 
541  std::string feClassSelected = bufferFields[1];
542  std::string feUIDSelected =
543  bufferFields[2]; // allow CSV multi-selection
544  std::string macroType = bufferFields[3]; // "fe", "public", "private"
545  std::string macroName =
546  StringMacros::decodeURIComponent(bufferFields[4]);
547  std::string inputArgs = StringMacros::decodeURIComponent(
548  bufferFields[5]); //two level ;- and ,- separated
549  std::string outputArgs =
550  StringMacros::decodeURIComponent(bufferFields[6]); //,- separated
551  bool saveOutputs = bufferFields[7] == "1";
552  std::string username = "NO-USER";
553  std::string userGroupPermission = "allUsers: 255";
554 
555  theSupervisor->runFEMacro(xmldoc,
556  feClassSelected,
557  feUIDSelected,
558  macroType,
559  macroName,
560  inputArgs,
561  outputArgs,
562  saveOutputs,
563  username,
564  userGroupPermission);
565 
566  std::stringstream out;
567  xmldoc.outputXmlDocument((std::ostringstream*)&out,
568  false /*dispStdOut*/,
569  true /*allowWhiteSpace*/);
570  __COUT__ << "out: " << out.str();
571  sock.acknowledge(out.str(), true /* verbose */);
572  }
573  else
574  {
575  __SS__ << "Unrecognized UDP command received: " << buffer << __E__;
576  __SS_THROW__;
577  }
578  }
579  catch(const std::runtime_error& e)
580  {
581  __COUT_ERR__ << "Error during UDP command handling: " << e.what()
582  << __E__;
583  sock.acknowledge(std::string("Error: ") + e.what(), true /* verbose */);
584  }
585  catch(...)
586  {
587  __COUT_ERR__ << "Unknown error caught during UDP command handling - "
588  "check the logs."
589  << __E__;
590  sock.acknowledge(std::string("Error: ") + "unknown error caught",
591  true /* verbose */);
592  }
593 
594  __COUT__ << "Done handling command '" << buffer << "'" << __E__;
595  }
596  else
597  usleep(1000);
598  }
599 } // end RemoteControlWorkLoop()
600 
601 //==============================================================================
604 void MacroMakerSupervisor::requestWrapper(xgi::Input* in, xgi::Output* out)
605 {
606  // use default wrapper if not Macro Maker mode
607  if(!CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
608  {
609  __SUP_COUTT__ << "Default request wrapper" << __E__;
610  return CoreSupervisorBase::requestWrapper(in, out);
611  }
612  // else very specialized Macro Maker mode!
613 
614  __SUP_COUTT__ << "MacroMaker mode request handler!" << __E__;
615 
616  // checkSupervisorPropertySetup();
617 
618  cgicc::Cgicc cgiIn(in);
619 
620  std::string submittedSequence = CgiDataUtilities::postData(cgiIn, "sequence");
621 
622  // SECURITY CHECK START ****
623  if(securityCode_.compare(submittedSequence) != 0)
624  {
625  __COUT__ << "Unauthorized Request made, security sequence doesn't match! "
626  << time(0) << __E__;
627  return;
628  }
629  else
630  {
631  __COUT__ << "***Successfully authenticated security sequence. " << time(0)
632  << __E__;
633  }
634  // SECURITY CHECK END ****
635 
636  std::string requestType = CgiDataUtilities::getData(cgiIn, "RequestType");
637 
638  __SUP_COUT_TYPE__(TLVL_DEBUG + 10) << __COUT_HDR__ << "requestType " << requestType
639  << " files: " << cgiIn.getFiles().size() << __E__;
640 
641  HttpXmlDocument xmlOut;
642  WebUsers::RequestUserInfo userInfo(
643  requestType, CgiDataUtilities::getOrPostData(cgiIn, "CookieCode"));
644 
646 
647  // copied from WebUsers::checkRequestAccess
648  userInfo.username_ = "admin";
649  userInfo.displayName_ = "Admin";
650  userInfo.usernameWithLock_ = "admin";
651  userInfo.userSessionIndex_ = 0;
652  std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> initPermissions = {
653  {WebUsers::DEFAULT_USER_GROUP, WebUsers::PERMISSION_LEVEL_ADMIN}};
654  userInfo.setGroupPermissionLevels(StringMacros::mapToString(initPermissions));
655 
656  if(1 || !userInfo.automatedCommand_)
657  __SUP_COUT__ << "requestType: " << requestType << __E__;
658 
659  if(userInfo.NonXMLRequestType_)
660  {
661  try
662  {
663  nonXmlRequest(requestType, cgiIn, *out, userInfo);
664  }
665  catch(const std::runtime_error& e)
666  {
667  __SUP_SS__ << "An error was encountered handling requestType '" << requestType
668  << "':" << e.what() << __E__;
669  __SUP_COUT_ERR__ << "\n" << ss.str();
670  }
671  catch(...)
672  {
673  __SUP_SS__ << "An unknown error was encountered handling requestType '"
674  << requestType << ".' "
675  << "Please check the printouts to debug." << __E__;
676  try
677  {
678  throw;
679  } //one more try to printout extra info
680  catch(const std::exception& e)
681  {
682  ss << "Exception message: " << e.what();
683  }
684  catch(...)
685  {
686  }
687  __SUP_COUT_ERR__ << "\n" << ss.str();
688  }
689  return;
690  }
691  // else xml request type
692 
693  try
694  {
695  // call derived class' request()
696  request(requestType, cgiIn, xmlOut, userInfo);
697  __SUP_COUTT__ << "Request '" << requestType << "' complete." << __E__;
698  }
699  catch(const std::runtime_error& e)
700  {
701  __SUP_SS__ << "An error was encountered handling requestType '" << requestType
702  << "':" << e.what() << __E__;
703  __SUP_COUT_ERR__ << "\n" << ss.str();
704  xmlOut.addTextElementToData("Error", ss.str());
705  }
706  catch(...)
707  {
708  __SUP_SS__ << "An unknown error was encountered handling requestType '"
709  << requestType << ".' "
710  << "Please check the printouts to debug." << __E__;
711  try
712  {
713  throw;
714  } //one more try to printout extra info
715  catch(const std::exception& e)
716  {
717  ss << "Exception message: " << e.what();
718  }
719  catch(...)
720  {
721  }
722  __SUP_COUT_ERR__ << "\n" << ss.str();
723  xmlOut.addTextElementToData("Error", ss.str());
724  }
725 
726  // report any errors encountered
727  {
728  unsigned int occurance = 0;
729  std::string err = xmlOut.getMatchingValue("Error", occurance++);
730  while(err != "")
731  {
732  __SUP_COUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err
733  << __E__;
734  err = xmlOut.getMatchingValue("Error", occurance++);
735  }
736  }
737 
738  __SUP_COUTVS__(10, userInfo.NoXmlWhiteSpace_);
739 
740  // return xml doc holding server response
741  xmlOut.outputXmlDocument((std::ostringstream*)out,
742  false /*print to cout*/,
743  !userInfo.NoXmlWhiteSpace_ /*allow whitespace*/);
744 } // end requestWrapper()
745 
746 //==============================================================================
747 void MacroMakerSupervisor::request(const std::string& requestType,
748  cgicc::Cgicc& cgiIn,
749  HttpXmlDocument& xmlOut,
750  const WebUsers::RequestUserInfo& userInfo)
751 try
752 {
753  std::chrono::steady_clock::time_point requestStart = std::chrono::steady_clock::now();
754  time_t requestStartTime = time(0);
755 
756  // sanitize username
757  std::string username = "";
758  for(unsigned int i = 0; i < userInfo.username_.size(); ++i)
759  if((userInfo.username_[i] >= 'a' && userInfo.username_[i] <= 'z') ||
760  (userInfo.username_[i] >= 'A' && userInfo.username_[i] <= 'Z') ||
761  (userInfo.username_[i] >= '0' && userInfo.username_[i] <= '9') ||
762  userInfo.username_[i] >= '-' || userInfo.username_[i] <= '_')
763  username += userInfo.username_[i];
764 
765  if(username.size() < 2)
766  {
767  __SUP_SS__ << "Illegal username '" << userInfo.username_ << "' received."
768  << __E__;
769  __SUP_SS_THROW__;
770  }
771 
772  __SUP_COUT__ << "User name is " << userInfo.username_ << "." << __E__;
773  __SUP_COUT__ << "User permission level for request '" << requestType << "' is "
774  << unsigned(userInfo.permissionLevel_) << "." << __E__;
775 
776  // handle request per requestType
777 
778  if(requestType == "loadFEHistory")
779  {
780  std::string histPath = (std::string)MACROS_HIST_PATH + userInfo.username_ + "/";
781  mkdir(histPath.c_str(), 0755);
782  }
783 
784  if(requestType == "loadFEMacroSequences")
785  {
786  std::string seqPath =
787  (std::string)MACROS_SEQUENCE_PATH + userInfo.username_ + "/";
788  mkdir(seqPath.c_str(), 0755);
789  }
790 
791  if(requestType == "getPermission")
792  {
793  xmlOut.addTextElementToData("Permission",
794  std::to_string(unsigned(userInfo.permissionLevel_)));
795  // create macro maker folders for the user (the first time a user authenticates
796  // with macro maker)
797  std::string publicPath = (std::string)MACROS_DB_PATH + "publicMacros/";
798  mkdir(publicPath.c_str(), 0755);
799  std::string exportPath =
800  __ENV__("SERVICE_DATA_PATH") + MACROS_EXPORT_PATH + userInfo.username_ + "/";
801  mkdir(exportPath.c_str(), 0755);
802  }
803  else
804  handleRequest(requestType, xmlOut, cgiIn, userInfo);
805 
806  __SUP_COUTT__ << "Total MacroMaker request time: "
807  << artdaq::TimeUtils::GetElapsedTime(requestStart) << " = "
808  << time(0) - requestStartTime << " seconds" << __E__;
809 } // end request()
810 catch(const std::runtime_error& e)
811 {
812  __SS__ << "Error occurred handling request '" << requestType << "': " << e.what()
813  << __E__;
814  __SUP_COUT__ << ss.str();
815  xmlOut.addTextElementToData("Error", ss.str());
816 }
817 catch(...)
818 {
819  __SS__ << "Unknown error occurred handling request '" << requestType << "!'" << __E__;
820  try
821  {
822  throw;
823  } //one more try to printout extra info
824  catch(const std::exception& e)
825  {
826  ss << "Exception message: " << e.what();
827  }
828  catch(...)
829  {
830  }
831  __SUP_COUT__ << ss.str();
832  xmlOut.addTextElementToData("Error", ss.str());
833 } // end request() error handling
834 
835 //==============================================================================
836 
837 void MacroMakerSupervisor::handleRequest(const std::string Command,
838  HttpXmlDocument& xmldoc,
839  cgicc::Cgicc& cgi,
840  const WebUsers::RequestUserInfo& userInfo)
841 {
842  if(Command == "FElist") // called by MacroMaker GUI
843  {
844  //make user directories if needed
845  std::string macroPath = (std::string)MACROS_DB_PATH + userInfo.username_ + "/";
846  mkdir(macroPath.c_str(), 0755);
847  std::string histPath = (std::string)MACROS_HIST_PATH + userInfo.username_ + "/";
848  mkdir(histPath.c_str(), 0755);
849 
850  getFElist(xmldoc);
851  }
852  else if(Command == "writeData") // called by MacroMaker GUI
853  writeData(xmldoc, cgi, userInfo.username_);
854  else if(Command == "readData") // called by MacroMaker GUI
855  readData(xmldoc, cgi, userInfo.username_);
856  else if(Command == "createMacro") // called by MacroMaker GUI
857  createMacro(xmldoc, cgi, userInfo.username_);
858  else if(Command == "loadMacros") // called by MacroMaker GUI
859  loadMacros(xmldoc, userInfo.username_);
860  else if(Command == "loadHistory") // called by MacroMaker GUI
861  loadHistory(xmldoc, userInfo.username_);
862  else if(Command == "deleteMacro") // called by MacroMaker GUI
863  deleteMacro(xmldoc, cgi, userInfo.username_);
864  else if(Command == "editMacro") // called by MacroMaker GUI
865  editMacro(xmldoc, cgi, userInfo.username_);
866  else if(Command == "clearHistory") // called by MacroMaker GUI
867  clearHistory(userInfo.username_);
868  else if(Command == "exportMacro") // called by MacroMaker GUI
869  exportMacro(xmldoc, cgi, userInfo.username_);
870  else if(Command == "exportFEMacro") // called by MacroMaker GUI
871  exportFEMacro(xmldoc, cgi, userInfo.username_);
872  else if(Command == "getFEMacroList") // called by FE Macro Test and returns FE Macros
873  // and Macro Maker Macros
874  {
875  //make user directories if needed
876  std::string macroPath = (std::string)MACROS_DB_PATH + userInfo.username_ + "/";
877  mkdir(macroPath.c_str(), 0755);
878  std::string histPath = (std::string)MACROS_HIST_PATH + userInfo.username_ + "/";
879  mkdir(histPath.c_str(), 0755);
880 
881  getFEMacroList(xmldoc, userInfo.username_);
882  }
883  else if(Command == "runFEMacro") // called by FE Macro Test returns FE Macros and
884  // Macro Maker Macros
885  runFEMacro(xmldoc, cgi, userInfo);
886  else if(Command == "loadFEHistory") // called by FE Macro Test and returns FE Macros
887  // and Macro Maker Macros
888  loadFEHistory(xmldoc, userInfo.username_);
889  else if(Command == "clearFEHistory") // called by FE Macro Test returns FE Macros and
890  // Macro Maker Macros
891  clearFEHistory(userInfo.username_);
892  else if(Command == "loadFEMacroSequences")
893  loadFEMacroSequences(xmldoc, userInfo.username_);
894  else if(Command == "saveFEMacroSequence")
895  saveFEMacroSequence(cgi, userInfo.username_);
896  else if(Command == "getFEMacroSequence")
897  getFEMacroSequence(xmldoc, cgi, userInfo.username_);
898  else if(Command == "deleteFEMacroSequence")
899  deleteFEMacroSequence(cgi, userInfo.username_);
900  else if(Command == "makeSequencePublic")
901  makeSequencePublic(cgi, userInfo.username_);
902  else
903  xmldoc.addTextElementToData("Error",
904  "Command '" + Command +
905  "' not recognized by the Macro Maker Supervisor "
906  "(was it intended for another Supervisor?).");
907 } // end handleRequest()
908 
909 //==============================================================================
910 xoap::MessageReference MacroMakerSupervisor::frontEndCommunicationRequest(
911  xoap::MessageReference message)
912 try
913 {
914  __COUTT__; //mark for debugging
915  __SUP_COUT__ << "FE Request received: " << SOAPUtilities::translate(message) << __E__;
916 
917  SOAPParameters typeParameter, rxParameters; // params for xoap to recv
918  typeParameter.addParameter("type");
919  SOAPUtilities::receive(message, typeParameter);
920 
921  std::string type = typeParameter.getValue("type");
922 
923  std::string error = "";
924 
925  if(type == "initFElist") // gateway initializes during configure
926  {
927  __SUP_COUTV__(type);
928 
929  rxParameters.addParameter("groupName");
930  rxParameters.addParameter("groupKey");
931  SOAPUtilities::receive(message, rxParameters);
932 
933  std::string groupName = rxParameters.getValue("groupName");
934  std::string groupKey = rxParameters.getValue("groupKey");
935 
936  __SUP_COUTV__(groupName);
937  __SUP_COUTV__(groupKey);
938 
939  ConfigurationManager cfgMgr;
940  cfgMgr.loadTableGroup(groupName, TableGroupKey(groupKey), true);
941 
942  // for each FESupervisor
943  // get all front end children
944 
945  const SupervisorInfoMap& feTypeSupervisors =
946  CorePropertySupervisorBase::allSupervisorInfo_.getAllFETypeSupervisorInfo();
947 
948  ConfigurationTree appsNode =
949  cfgMgr.getNode(ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME);
950 
951  __SUP_COUT__ << "Number of FE Supervisors found = " << feTypeSupervisors.size()
952  << __E__;
953 
954  FEPluginTypetoFEsMap_.clear(); // reset
955  FEtoSupervisorMap_.clear(); // reset
956  FEtoPluginTypeMap_.clear(); // reset
957  for(auto& feApp : feTypeSupervisors)
958  {
959  __SUP_COUT__ << "FEs for app " << feApp.first << ":" << feApp.second.getName()
960  << __E__;
961 
962  auto feChildren = appsNode.getNode(feApp.second.getName())
963  .getNode("LinkToSupervisorTable")
964  .getNode("LinkToFEInterfaceTable")
965  .getChildren();
966 
967  for(auto& fe : feChildren)
968  {
969  if(!fe.second.status())
970  continue; // skip disabled FEs
971 
972  __SUP_COUTV__(fe.first);
973  FEtoSupervisorMap_[fe.first] = feApp.first;
974 
975  std::string pluginType =
976  fe.second.getNode("FEInterfacePluginName").getValue();
977  FEPluginTypetoFEsMap_[pluginType].emplace(fe.first);
978  FEtoPluginTypeMap_[fe.first] = pluginType;
979  }
980  }
981 
982  __SUP_COUTV__(StringMacros::mapToString(FEtoSupervisorMap_));
983  __SUP_COUTV__(StringMacros::mapToString(FEPluginTypetoFEsMap_));
984  __SUP_COUTV__(StringMacros::mapToString(FEtoPluginTypeMap_));
985  }
986  else if(type == "feSend" || // from front-ends
987  type == "feMacro" || // from front-ends
988  type == "feMacroMultiDimensionalStart" || // from iterator
989  type == "feMacroMultiDimensionalCheck" || // from iterator
990  type == "macroMultiDimensionalStart" || // from iterator
991  type == "macroMultiDimensionalCheck") // from iterator
992  {
993  __SUP_COUTV__(type);
994 
995  rxParameters.addParameter("targetInterfaceID");
996  SOAPUtilities::receive(message, rxParameters);
997 
998  std::string targetInterfaceID = rxParameters.getValue("targetInterfaceID");
999 
1000  __SUP_COUTV__(targetInterfaceID);
1001 
1002  auto feIt = FEtoSupervisorMap_.find(targetInterfaceID);
1003  if(feIt == FEtoSupervisorMap_.end())
1004  {
1005  __SUP_SS__ << "Destination front end interface ID '" << targetInterfaceID
1006  << "' was not found in the list of front ends." << __E__;
1007  __SUP_SS_THROW__;
1008  }
1009 
1010  unsigned int FESupervisorIndex = feIt->second;
1011  __SUP_COUT__ << "Found supervisor index: " << FESupervisorIndex << __E__;
1012 
1013  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
1014  if(it == allFESupervisorInfo_.end())
1015  {
1016  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1017  << targetInterfaceID << ":" << FESupervisorIndex << ".' \n\n"
1018  << "The FE Supervisor Index does not exist. Have you configured "
1019  "the state machine properly?"
1020  << __E__;
1021  __SUP_SS_THROW__;
1022  }
1023 
1024  if(type == "macroMultiDimensionalStart")
1025  {
1026  // add Macro sequence (and check macro exists)
1027 
1028  SOAPParameters rxParameters;
1029  rxParameters.addParameter("macroName");
1030  SOAPUtilities::receive(message, rxParameters);
1031  std::string macroName = rxParameters.getValue("macroName");
1032  __SUP_COUTV__(macroName);
1033 
1034  std::string macroString;
1035  loadMacro(macroName, macroString);
1036 
1037  SOAPParameters parameters;
1038  parameters.addParameter("macroString", macroString);
1039  SOAPUtilities::addParameters(message, parameters);
1040  }
1041 
1042  try
1043  {
1044  __SUP_COUT__ << "Forwarding request: " << SOAPUtilities::translate(message)
1045  << __E__;
1046 
1047  xoap::MessageReference replyMessage =
1048  SOAPMessenger::sendWithSOAPReply(it->second.getDescriptor(), message);
1049 
1050  if(type != "feSend")
1051  {
1052  __SUP_COUT__ << "Forwarding FE Macro response: "
1053  << SOAPUtilities::translate(replyMessage) << __E__;
1054 
1055  return replyMessage;
1056  }
1057  }
1058  catch(const xdaq::exception::Exception& e)
1059  {
1060  __SUP_SS__ << "Error forwarding FE Communication request to FE Supervisor '"
1061  << targetInterfaceID << ":" << FESupervisorIndex << ".' "
1062  << "Have you configured the state machine properly?\n\n"
1063  << e.what() << __E__;
1064  __SUP_SS_THROW__;
1065  }
1066  }
1067  else
1068  {
1069  __SUP_SS__ << "Unrecognized FE Communication type: " << type << __E__;
1070  __SUP_SS_THROW__;
1071  }
1072 
1073  return SOAPUtilities::makeSOAPMessageReference("Received");
1074 } // end frontEndCommunicationRequest()
1075 catch(const std::runtime_error& e)
1076 {
1077  __SUP_SS__ << "Error processing FE communication request: " << e.what() << __E__;
1078  __SUP_COUT_ERR__ << ss.str();
1079 
1080  xoap::MessageReference returnMessage =
1081  SOAPUtilities::makeSOAPMessageReference("Error");
1082 
1083  SOAPParameters parameters;
1084  parameters.addParameter("Error", ss.str());
1085  SOAPUtilities::addParameters(returnMessage, parameters);
1086  return returnMessage;
1087 }
1088 catch(...)
1089 {
1090  xoap::MessageReference returnMessage =
1091  SOAPUtilities::makeSOAPMessageReference("Error");
1092 
1093  __SUP_SS__ << "Unknown error processing FE communication request." << __E__;
1094  try
1095  {
1096  throw;
1097  } //one more try to printout extra info
1098  catch(const std::exception& e)
1099  {
1100  ss << "Exception message: " << e.what();
1101  }
1102  catch(...)
1103  {
1104  }
1105  __SUP_COUT_ERR__ << ss.str();
1106 
1107  SOAPParameters parameters;
1108  parameters.addParameter("Error", ss.str());
1109  SOAPUtilities::addParameters(returnMessage, parameters);
1110  return returnMessage;
1111 } // end frontEndCommunicationRequest() catch
1112 
1113 //==============================================================================
1114 void MacroMakerSupervisor::getFElist(HttpXmlDocument& xmldoc)
1115 {
1116  __SUP_COUT__ << "Getting FE list!!!!!!!!!" << __E__;
1117 
1118  SOAPParameters txParameters; // params for xoap to send
1119  txParameters.addParameter("Request", "GetInterfaces");
1120 
1121  SOAPParameters rxParameters; // params for xoap to recv
1122  rxParameters.addParameter("Command");
1123  rxParameters.addParameter("FEList");
1124  rxParameters.addParameter("frontEndError"); // if there were errors recorded (during
1125  // configuration, e.g. in Macro Maker
1126  // only mode)
1127 
1128  SupervisorInfoMap::const_iterator it;
1129  std::string oneInterface;
1130  std::string rxFEList;
1131  std::string rxFrontEndError;
1132 
1133  size_t lastColonIndex;
1134 
1135  // for each list of FE Supervisors,
1136  // loop through each FE Supervisors and get FE interfaces list
1137  for(auto& appInfo : allFESupervisorInfo_)
1138  {
1139  // __SUP_COUT__ << "Number of " << listPair.first << " = " <<
1140  // listPair.second.size() << __E__;
1141  //
1142  // for (it = listPair.second.begin(); it != listPair.second.end(); it++)
1143  // {
1144 
1145  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId()
1146  << " name = " << appInfo.second.getName() << __E__;
1147 
1148  try
1149  {
1150  xoap::MessageReference retMsg =
1151  SOAPMessenger::sendWithSOAPReply(appInfo.second.getDescriptor(),
1152  "MacroMakerSupervisorRequest",
1153  txParameters);
1154  SOAPUtilities::receive(retMsg, rxParameters);
1155 
1156  __SUP_COUT__ << "Received MacroMaker response: "
1157  << SOAPUtilities::translate(retMsg).getCommand() << "==>"
1158  << SOAPUtilities::translate(retMsg) << __E__;
1159 
1160  if(SOAPUtilities::translate(retMsg).getCommand() == "Fault")
1161  {
1162  __SUP_SS__ << "Unrecognized command received!" << __E__;
1163  __SUP_SS_THROW__;
1164  }
1165  }
1166  catch(const xdaq::exception::Exception& e)
1167  {
1168  __SUP_SS__ << "Error transmitting request to FE Supervisor LID = "
1169  << appInfo.second.getId() << " name = " << appInfo.second.getName()
1170  << ". \n\n"
1171  << e.what() << __E__;
1172  __SUP_SS_THROW__;
1173  }
1174 
1175  rxFEList = rxParameters.getValue("FEList");
1176  rxFrontEndError = rxParameters.getValue("frontEndError");
1177 
1178  __SUP_COUT__ << "FE List received: \n" << rxFEList << __E__;
1179 
1180  if(rxFrontEndError != "")
1181  {
1182  __SUP_SS__ << "FE Errors received: \n" << rxFrontEndError << __E__;
1183  __SUP_SS_THROW__;
1184  }
1185 
1186  std::istringstream allInterfaces(rxFEList);
1187  while(std::getline(allInterfaces, oneInterface))
1188  {
1189  __SUP_COUTV__(oneInterface);
1190  xmldoc.addTextElementToData("FE", oneInterface);
1191 
1192  lastColonIndex = oneInterface.rfind(':');
1193  if(lastColonIndex == std::string::npos)
1194  {
1195  __SUP_SS__ << "Last colon could not be found in " << oneInterface
1196  << __E__;
1197  __SUP_SS_THROW__;
1198  }
1199  oneInterface = oneInterface.substr(lastColonIndex);
1200 
1201  __SUP_COUTV__(oneInterface);
1202  } // end FE extract loop
1203 
1204  } // end ask Supervisors for their FE list loop
1205 
1206 } // end getFEList()
1207 
1208 //==============================================================================
1209 void MacroMakerSupervisor::writeData(HttpXmlDocument& /*xmldoc*/,
1210  cgicc::Cgicc& cgi,
1211  const std::string& username)
1212 {
1213  __SUP_COUT__ << "MacroMaker writing..." << __E__;
1214 
1215  std::string Address = CgiDataUtilities::getData(cgi, "Address");
1216  std::string Data = CgiDataUtilities::getData(cgi, "Data");
1217  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
1218  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
1219  std::string time =
1221  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
1222  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
1223 
1224  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
1225 
1226  __SUP_COUT__ << "Write Address: " << Address << " Data: " << Data << __E__;
1227  __SUP_COUTV__(interfaces);
1228 
1229  std::string command = "w:" + Address + ":" + Data;
1230  std::string format = addressFormatStr + ":" + dataFormatStr;
1231  appendCommandToHistory(command, format, time, interfaces, username);
1232 
1233  SOAPParameters txParameters; // params for xoap to send
1234  txParameters.addParameter("Request", "UniversalWrite");
1235  txParameters.addParameter("Address", Address);
1236  txParameters.addParameter("Data", Data);
1237 
1238  __SUP_COUT__ << "Here comes the array from multiselect box for WRITE, behold: \n"
1239  << supervisorIndexArray << "\n"
1240  << interfaceIndexArray << __E__;
1241 
1244  std::vector<std::string> interfaceIndices;
1245  std::istringstream f(interfaceIndexArray);
1246  std::string s;
1247  while(getline(f, s, ','))
1248  interfaceIndices.push_back(s);
1249  std::vector<int> supervisorIndices;
1250  std::istringstream g(supervisorIndexArray);
1251  std::string t;
1252  while(getline(g, t, ','))
1253  supervisorIndices.push_back(std::stoi(t));
1254 
1255  for(unsigned int i = 0; i < supervisorIndices.size(); i++)
1256  {
1257  unsigned int FESupervisorIndex = supervisorIndices[i];
1258  std::string interfaceIndex = interfaceIndices[i];
1259 
1260  txParameters.addParameter("InterfaceID", interfaceIndex);
1261 
1262  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex
1263  << __E__;
1264  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
1265 
1266  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
1267  if(it == allFESupervisorInfo_.end())
1268  {
1269  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1270  << interfaceIndex << ":" << FESupervisorIndex << ".' \n\n"
1271  << "The FE Index doesn't exist. Have you configured the state "
1272  "machine properly?"
1273  << __E__;
1274  __SUP_SS_THROW__;
1275  }
1276 
1277  try
1278  {
1279  xoap::MessageReference replyMessage = SOAPMessenger::sendWithSOAPReply(
1280  it->second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
1281 
1282  __SUP_COUT__ << "Response received: "
1283  << SOAPUtilities::translate(replyMessage) << __E__;
1284 
1285  SOAPParameters rxParameters;
1286  rxParameters.addParameter("Error");
1287  SOAPUtilities::receive(replyMessage, rxParameters);
1288 
1289  std::string error = rxParameters.getValue("Error");
1290  __SUP_COUTV__(error);
1291 
1292  if(error != "")
1293  {
1294  // error occurred!
1295  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1296  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1297  << "Have you configured the state machine properly?\n\n"
1298  << error << __E__;
1299  __SUP_SS_THROW__;
1300  }
1301  }
1302  catch(const xdaq::exception::Exception& e)
1303  {
1304  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1305  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1306  << "Have you configured the state machine properly?\n\n"
1307  << e.what() << __E__;
1308  __SUP_SS_THROW__;
1309  }
1310 
1311  } // end FE Supervisor loop
1312 } // end writeData()
1313 
1314 //==============================================================================
1315 void MacroMakerSupervisor::readData(HttpXmlDocument& xmldoc,
1316  cgicc::Cgicc& cgi,
1317  const std::string& username)
1318 {
1319  __SUP_COUT__ << "@@@@@@@ MacroMaker wants to read data @@@@@@@@" << __E__;
1320  std::string Address = CgiDataUtilities::getData(cgi, "Address");
1321  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
1322  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
1323  std::string time =
1325  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
1326  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
1327 
1328  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
1329 
1330  __SUP_COUT__ << "Read Address: " << Address << __E__;
1331  __SUP_COUTV__(interfaces);
1332 
1333  SOAPParameters txParameters; // params for xoap to send
1334  txParameters.addParameter("Request", "UniversalRead");
1335  txParameters.addParameter("Address", Address);
1336 
1337  SOAPParameters rxParameters;
1338  rxParameters.addParameter("dataResult");
1339  rxParameters.addParameter("Error");
1340  __SUP_COUT__ << "Here comes the array from multiselect box for READ, behold: "
1341  << supervisorIndexArray << "," << interfaceIndexArray << __E__;
1342 
1345  std::vector<std::string> interfaceIndices;
1346  std::istringstream f(interfaceIndexArray);
1347  std::string s;
1348  while(getline(f, s, ','))
1349  interfaceIndices.push_back(s);
1350  std::vector<int> supervisorIndices;
1351  std::istringstream g(supervisorIndexArray);
1352  std::string t;
1353  while(getline(g, t, ','))
1354  supervisorIndices.push_back(std::stoi(t));
1355 
1356  for(unsigned int i = 0; i < supervisorIndices.size(); i++)
1357  {
1358  unsigned int FESupervisorIndex = supervisorIndices[i];
1359  std::string interfaceIndex = interfaceIndices[i];
1360 
1361  txParameters.addParameter("InterfaceID", interfaceIndex);
1362 
1363  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex
1364  << __E__;
1365  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
1366 
1367  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
1368  if(it == allFESupervisorInfo_.end())
1369  {
1370  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1371  << interfaceIndex << ":" << FESupervisorIndex << ".' \n\n"
1372  << "The FE Index doesn't exist. Have you configured the state "
1373  "machine properly?"
1374  << __E__;
1375  __SUP_SS_THROW__;
1376  }
1377 
1378  try
1379  {
1380  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
1381  it->second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
1382 
1383  __SUP_COUT__ << "Response received: " << SOAPUtilities::translate(retMsg)
1384  << __E__;
1385 
1386  // SOAPParameters rxParameters;
1387  // rxParameters.addParameter("Error");
1388  SOAPUtilities::receive(retMsg, rxParameters);
1389 
1390  std::string error = rxParameters.getValue("Error");
1391  __SUP_COUTV__(error);
1392 
1393  if(error != "")
1394  {
1395  // error occurred!
1396  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1397  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1398  << "Have you configured the state machine properly?\n\n"
1399  << error << __E__;
1400  __SUP_SS_THROW__;
1401  }
1402  }
1403  catch(const xdaq::exception::Exception& e)
1404  {
1405  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1406  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1407  << "Have you configured the state machine properly?\n\n"
1408  << e.what() << __E__;
1409  __SUP_SS_THROW__;
1410  }
1411 
1412  std::string dataReadResult = rxParameters.getValue("dataResult");
1413  __SUP_COUT__ << "Data reading result received: " << dataReadResult << __E__;
1414  xmldoc.addTextElementToData("readData", dataReadResult);
1415  std::string command = "r:" + Address + ":" + dataReadResult;
1416  std::string format = addressFormatStr + ":" + dataFormatStr;
1417  appendCommandToHistory(command, format, time, interfaces, username);
1418  }
1419 } //end readData()
1420 
1421 //==============================================================================
1422 void MacroMakerSupervisor::createMacro(HttpXmlDocument& /*xmldoc*/,
1423  cgicc::Cgicc& cgi,
1424  const std::string& username)
1425 {
1426  __SUP_COUT__ << "MacroMaker wants to create a macro!!!!!!!!!" << __E__;
1427  std::string Name = CgiDataUtilities::postData(cgi, "Name");
1428  std::string Sequence = CgiDataUtilities::postData(cgi, "Sequence");
1429  std::string Time = CgiDataUtilities::postData(cgi, "Time");
1430  std::string Notes =
1432  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
1433  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
1434 
1435  __SUP_COUTV__(Name);
1436  __SUP_COUTV__(Sequence);
1437  __SUP_COUTV__(Notes);
1438  __SUP_COUTV__(Time);
1439  __SUP_COUTV__(isMacroPublic);
1440  __SUP_COUTV__(isMacroLSBF);
1441 
1442  __SUP_COUTV__(MACROS_DB_PATH);
1443 
1444  std::string fileName = Name + ".dat";
1445  std::string fullPath;
1446  if(isMacroPublic == "true")
1447  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
1448  else
1449  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
1450 
1451  __SUP_COUTV__(fullPath);
1452 
1453  std::ofstream macrofile(fullPath.c_str());
1454  if(macrofile.is_open())
1455  {
1456  macrofile << "{\n";
1457  macrofile << "\"name\":\"" << Name << "\",\n";
1458  macrofile << "\"sequence\":\"" << Sequence << "\",\n";
1459  macrofile << "\"time\":\"" << Time << "\",\n";
1460  macrofile << "\"notes\":\"" << Notes << "\",\n";
1461  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
1462  macrofile << "}@" << __E__;
1463  macrofile.close();
1464  }
1465  else
1466  {
1467  __SUP_SS__ << "Unable to open file" << __E__;
1468  __SUP_SS_THROW__;
1469  }
1470 } // end createMacro()
1471 
1472 //==============================================================================
1480 void MacroMakerSupervisor::loadMacro(const std::string& macroName,
1481  std::string& macroString,
1482  const std::string& username /*=""*/)
1483 {
1484  __SUP_COUTV__(macroName);
1485 
1486  // first check public folder, then user
1487  std::string fullPath, line;
1488  macroString = "";
1489  for(unsigned int i = 0; i < 2; ++i)
1490  {
1491  if(i == 1)
1492  fullPath = (std::string)MACROS_DB_PATH + username + "/";
1493  else
1494  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1495 
1496  fullPath += macroName;
1497  if(macroName.find(".dat") != macroName.size() - 4)
1498  fullPath += ".dat";
1499  __SUP_COUTV__(fullPath);
1500 
1501  std::ifstream read(fullPath.c_str()); // reading a file
1502  if(read.is_open())
1503  {
1504  while(!read.eof())
1505  {
1506  getline(read, line);
1507  macroString += line;
1508  }
1509 
1510  read.close();
1511  }
1512  else // file does not exist
1513  {
1514  __SUP_COUT__ << "Unable to open file: " << fullPath << __E__;
1515  continue;
1516  }
1517 
1518  if(macroString != "")
1519  break; // macro has been found!
1520  } // end load from path loop
1521 
1522  if(macroString == "")
1523  {
1524  __SUP_SS__ << "Unable to locate file for macro '" << macroName
1525  << "'... does it exist?" << __E__;
1526  if(username != "")
1527  ss << " Attempted username was '" << username << ".'" << __E__;
1528  __SUP_SS_THROW__;
1529  }
1530 
1531  __SUP_COUTV__(macroString);
1532 } // end loadMacro()
1533 
1534 //==============================================================================
1535 void MacroMakerSupervisor::loadMacroNames(
1536  const std::string& username,
1537  std::pair<std::vector<std::string> /*public macros*/,
1538  std::vector<std::string> /*private macros*/>& returnMacroNames)
1539 {
1540  DIR* dir;
1541  struct dirent* ent;
1542  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
1543  if((dir = opendir(fullPath.c_str())) != NULL)
1544  {
1545  /* print all the files and directories within directory */
1546  while((ent = readdir(dir)) != NULL)
1547  {
1548  /* File name validation check */
1549  if((unsigned)strlen(ent->d_name) > 4)
1550  {
1551  std::string line;
1552  std::ifstream read(
1553  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1554  if(read.is_open())
1555  {
1556  read.close();
1557  // private macro found
1558  returnMacroNames.second.push_back(ent->d_name);
1559  }
1560  else
1561  __SUP_COUT__ << "Unable to open file" << __E__;
1562  }
1563  }
1564  closedir(dir);
1565  }
1566  else
1567  {
1568  __SUP_COUT__ << "Looping through privateMacros folder failed! Wrong directory"
1569  << __E__;
1570  }
1571  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1572  if((dir = opendir(fullPath.c_str())) != NULL)
1573  {
1574  /* print all the files and directories within directory */
1575  while((ent = readdir(dir)) != NULL)
1576  {
1577  /* File name validation check */
1578  if((unsigned)strlen(ent->d_name) > 4)
1579  {
1580  std::string line;
1581  std::ifstream read(
1582  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1583  if(read.is_open())
1584  {
1585  // public macro found
1586  returnMacroNames.first.push_back(ent->d_name);
1587  read.close();
1588  }
1589  else
1590  __SUP_COUT__ << "Unable to open file" << __E__;
1591  }
1592  }
1593  closedir(dir);
1594  }
1595  else
1596  {
1597  __SUP_COUT__ << fullPath << __E__;
1598  __SUP_COUT__ << "Looping through MacroData folder failed! Wrong directory"
1599  << __E__;
1600  }
1601 
1602 } // end loadMacroNames
1603 
1604 //==============================================================================
1605 void MacroMakerSupervisor::loadMacros(HttpXmlDocument& xmldoc,
1606  const std::string& username)
1607 {
1608  DIR* dir;
1609  struct dirent* ent;
1610  std::string returnStr = "";
1611  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
1612  if((dir = opendir(fullPath.c_str())) != NULL)
1613  {
1614  /* print all the files and directories within directory */
1615  while((ent = readdir(dir)) != NULL)
1616  {
1617  /* File name validation check */
1618  if((unsigned)strlen(ent->d_name) > 4)
1619  {
1620  std::string line;
1621  std::ifstream read(
1622  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1623  if(read.is_open())
1624  {
1625  std::stringstream buffer;
1626  while(!read.eof())
1627  {
1628  getline(read, line);
1629  buffer << line;
1630  //__SUP_COUT__ << line << __E__;
1631  }
1632  returnStr += buffer.str();
1633 
1634  read.close();
1635  }
1636  else
1637  __SUP_COUT__ << "Unable to open file" << __E__;
1638  }
1639  }
1640  std::string returnMacroStr = returnStr.substr(0, returnStr.size() - 1);
1641 
1642  __SUP_COUT__ << "Loading existing macros! " << returnMacroStr << __E__;
1643 
1644  closedir(dir);
1645  xmldoc.addTextElementToData("returnMacroStr", returnMacroStr);
1646  }
1647  else
1648  {
1649  __SUP_COUT__ << "Looping through privateMacros folder failed! Wrong directory"
1650  << __E__;
1651  }
1652  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1653  returnStr = "";
1654  if((dir = opendir(fullPath.c_str())) != NULL)
1655  {
1656  /* print all the files and directories within directory */
1657  while((ent = readdir(dir)) != NULL)
1658  {
1659  /* File name validation check */
1660  if((unsigned)strlen(ent->d_name) > 4)
1661  {
1662  std::string line;
1663  std::ifstream read(
1664  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1665  if(read.is_open())
1666  {
1667  std::stringstream buffer;
1668  while(!read.eof())
1669  {
1670  getline(read, line);
1671  buffer << line;
1672  //__SUP_COUT__ << line << __E__;
1673  }
1674  returnStr += buffer.str();
1675  read.close();
1676  }
1677  else
1678  __SUP_COUT__ << "Unable to open file" << __E__;
1679  }
1680  }
1681  std::string returnPublicStr = returnStr.substr(0, returnStr.size() - 1);
1682  __SUP_COUT__ << "Loading existing public macros: " << returnPublicStr << __E__;
1683  closedir(dir);
1684  xmldoc.addTextElementToData("returnPublicStr", returnPublicStr);
1685  }
1686  else
1687  {
1688  __SUP_COUT__ << fullPath << __E__;
1689  __SUP_COUT__ << "Looping through MacroData folder failed! Wrong directory"
1690  << __E__;
1691  }
1692 } // end loadMacros()
1693 
1694 //==============================================================================
1695 void MacroMakerSupervisor::appendCommandToHistory(std::string Command,
1696  std::string Format,
1697  std::string Time,
1698  std::string Interfaces,
1699  const std::string& username)
1700 {
1701  std::string fileName = "history.hist";
1702  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
1703  __SUP_COUT__ << fullPath << __E__;
1704  std::ofstream histfile(fullPath.c_str(), std::ios::app);
1705  if(histfile.is_open())
1706  {
1707  histfile << "{\n";
1708  histfile << "\"Command\":\"" << Command << "\",\n";
1709  histfile << "\"Format\":\"" << Format << "\",\n";
1710  histfile << "\"Time\":\"" << Time << "\",\n";
1711  histfile << "\"Interfaces\":\"" << Interfaces << "\"\n";
1712  histfile << "}#" << __E__;
1713  histfile.close();
1714  }
1715  else
1716  {
1717  __SUP_SS__ << "Unable to open history.hist at " << fullPath << __E__;
1718  __SUP_SS_THROW__;
1719  }
1720 } //end appendCommandToHistory()
1721 
1722 //==============================================================================
1723 void MacroMakerSupervisor::appendCommandToHistory(std::string feClass,
1724  std::string feUID,
1725  std::string macroType,
1726  std::string macroName,
1727  std::string inputArgs,
1728  std::string outputArgs,
1729  bool saveOutputs,
1730  const std::string& username)
1731 {
1732  //prevent repeats to FE command history (otherwise live view can overwhelm history)
1733  auto feHistoryIt = lastFeCommandToHistory_.find(username);
1734  if(feHistoryIt != lastFeCommandToHistory_.end() && feHistoryIt->second.size() == 7 &&
1735  feHistoryIt->second[0] == feClass && feHistoryIt->second[1] == feUID &&
1736  feHistoryIt->second[2] == macroType && feHistoryIt->second[3] == macroName &&
1737  feHistoryIt->second[4] == inputArgs && feHistoryIt->second[5] == outputArgs &&
1738  feHistoryIt->second[6] == (saveOutputs ? "1" : "0"))
1739  {
1740  __SUP_COUTT__ << "Not saving repeat command to history from user " << username
1741  << __E__;
1742  return;
1743  }
1744 
1745  std::string fileName = "FEhistory.hist";
1746  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
1747  __SUP_COUT__ << fullPath << __E__;
1748  std::ofstream histfile(fullPath.c_str(), std::ios::app);
1749  if(histfile.is_open())
1750  {
1751  histfile << "{\n";
1752  histfile << "\"feClass\":\"" << feClass << "\",\n";
1753  histfile << "\"feUID\":\"" << feUID << "\",\n";
1754  histfile << "\"macroType\":\"" << macroType << "\",\n";
1755  histfile << "\"macroName\":\"" << macroName << "\",\n";
1756  histfile << "\"inputArgs\":\"" << inputArgs << "\",\n";
1757  histfile << "\"outputArgs\":\"" << outputArgs << "\",\n";
1758  if(saveOutputs)
1759  histfile << "\"saveOutputs\":\"" << 1 << "\"\n";
1760  else
1761  histfile << "\"saveOutputs\":\"" << 0 << "\"\n";
1762  histfile << "}#" << __E__;
1763  histfile.close();
1764 
1765  lastFeCommandToHistory_[username].clear(); //create instance and/or clear
1766  feHistoryIt = lastFeCommandToHistory_.find(username);
1767  feHistoryIt->second.push_back(feClass);
1768  feHistoryIt->second.push_back(feUID);
1769  feHistoryIt->second.push_back(macroType);
1770  feHistoryIt->second.push_back(macroName);
1771  feHistoryIt->second.push_back(inputArgs);
1772  feHistoryIt->second.push_back(outputArgs);
1773  feHistoryIt->second.push_back((saveOutputs ? "1" : "0"));
1774  }
1775  else
1776  {
1777  __SUP_SS__ << "Unable to open FEhistory.hist at " << fullPath << __E__;
1778  __SUP_SS_THROW__;
1779  }
1780 
1781 } //end appendCommandToHistory()
1782 
1783 //==============================================================================
1784 void MacroMakerSupervisor::loadFEMacroSequences(HttpXmlDocument& xmldoc,
1785  const std::string& username)
1786 {
1787  __SUP_COUT__ << "loadFEMacroSequences for " << username << __E__;
1788  DIR* dir;
1789  struct dirent* ent;
1790  std::string fullPath = (std::string)MACROS_SEQUENCE_PATH + username + "/";
1791  std::string sequences = "";
1792  __SUP_COUTV__(fullPath);
1793  if((dir = opendir(fullPath.c_str())) != NULL)
1794  {
1795  /* print all the files and directories within directory */
1796  while((ent = readdir(dir)) != NULL)
1797  {
1798  std::string line;
1799  std::ifstream read(
1800  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1801  if(read.is_open())
1802  {
1803  read.close();
1804  sequences += ent->d_name + std::string(";");
1805  }
1806  else
1807  __SUP_COUT__ << "Unable to open file" << __E__;
1808  }
1809  closedir(dir);
1810  }
1811  else
1812  {
1813  __SUP_COUT__ << "Looping through MacroSequence/" + username +
1814  " folder failed! Invalid directory."
1815  << __E__;
1816  }
1817 
1818  if(username == WebUsers::DEFAULT_ADMIN_USERNAME)
1819  {
1820  // already have admin list, return the list of sequences
1821  xmldoc.addTextElementToData("FEsequences", sequences);
1822  return;
1823  }
1824 
1825  //always add admin sequences (as "public")
1826  fullPath = (std::string)MACROS_SEQUENCE_PATH + WebUsers::DEFAULT_ADMIN_USERNAME + "/";
1827 
1828  if((dir = opendir(fullPath.c_str())) != NULL)
1829  {
1830  /* print all the files and directories within directory */
1831  while((ent = readdir(dir)) != NULL)
1832  {
1833  std::string line;
1834  std::ifstream read(
1835  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1836  if(read.is_open())
1837  {
1838  read.close();
1839  sequences += std::string("public/") + ent->d_name + std::string(";");
1840  }
1841  else
1842  __SUP_COUT__ << "Unable to open file" << __E__;
1843  }
1844  closedir(dir);
1845  }
1846  else
1847  {
1848  __SUP_COUT__ << "Looping through MacroSequence/" +
1849  WebUsers::DEFAULT_ADMIN_USERNAME +
1850  " folder failed! Invalid directory."
1851  << __E__;
1852  }
1853 
1854  // return the list of sequences
1855  xmldoc.addTextElementToData("FEsequences", sequences);
1856 } //end loadFEMacroSequences()
1857 
1858 //==============================================================================
1859 void MacroMakerSupervisor::saveFEMacroSequence(cgicc::Cgicc& cgi,
1860  const std::string& username)
1861 {
1862  // get data from the http request
1863  std::string name =
1865  std::string FEsequence =
1867  bool overwrite = CgiDataUtilities::getDataAsInt(cgi, "overwrite");
1868 
1869  __SUP_COUTV__(overwrite);
1870  __SUP_COUTV__(name);
1871  __SUP_COUTV__(FEsequence);
1872 
1873  //reject illegal characters (only alphanumeric, spaces, dash, underscores)
1874  std::string fixedName = "";
1875  for(size_t i = 0; i < name.size(); ++i)
1876  if(!(name[i] == ' ' || name[i] == '-' || name[i] == '_' ||
1877  (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') ||
1878  (name[i] >= 'a' && name[i] <= 'z')))
1879  {
1880  __SUP_SS__
1881  << "Illegal character in Sequence name (position " << i
1882  << ") - only alphanumeric, spaces, dashes, and underscores allowed!"
1883  << __E__;
1884  __SUP_SS_THROW__;
1885  }
1886  else
1887  fixedName += name[i];
1888  __SUP_COUTV__(fixedName);
1889 
1890  std::string fullPath =
1891  (std::string)MACROS_SEQUENCE_PATH + username + "/" + fixedName + ".dat";
1892  __SUP_COUTV__(fullPath);
1893 
1894  //do not allow overwrite
1895  if(!overwrite && std::filesystem::exists(fullPath))
1896  {
1897  __SUP_SS__ << "Please choose another Sequence name! A sequence with the same "
1898  "resulting filename already exists at "
1899  << fullPath << __E__;
1900  __SUP_SS_THROW__;
1901  }
1902 
1903  std::ofstream seqfile(fullPath.c_str());
1904  if(seqfile.is_open())
1905  {
1906  seqfile << FEsequence << __E__;
1907  seqfile.close();
1908  }
1909  else
1910  {
1911  __SUP_SS__ << "Unable to open file to save FE Macro Sequence at " << fullPath
1912  << __E__;
1913  __SUP_SS_THROW__;
1914  }
1915 } //end saveFEMacroSequence()
1916 
1917 //==============================================================================
1918 void MacroMakerSupervisor::getFEMacroSequence(HttpXmlDocument& xmldoc,
1919  cgicc::Cgicc& cgi,
1920  const std::string& username)
1921 {
1922  std::string name =
1924  __SUP_COUTV__(name);
1925 
1926  bool isPublic = (name.find("public/") == 0 ? true : false);
1927  __SUP_COUTV__(isPublic);
1928 
1929  //reject illegal characters (only alphanumeric, spaces, dash, underscores)
1930  std::string fixedName = "";
1931  for(size_t i = (isPublic ? std::string("public/").size() : 0); i < name.size(); ++i)
1932  if(!(name[i] == ' ' || name[i] == '-' || name[i] == '_' ||
1933  (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') ||
1934  (name[i] >= 'a' && name[i] <= 'z')))
1935  {
1936  __COUT__ << "Illegal character in Sequence name (position " << i
1937  << ") - only alphanumeric, spaces, dashes, and underscores allowed!"
1938  << __E__;
1939  }
1940  else
1941  fixedName += name[i];
1942  __SUP_COUTV__(fixedName);
1943 
1944  // access to the file
1945  std::string fullPath =
1946  (std::string)MACROS_SEQUENCE_PATH + username + "/" + fixedName + ".dat";
1947  __SUP_COUT__ << fullPath << __E__;
1948 
1949  std::ifstream read(fullPath.c_str()); // reading the file
1950  char* response;
1951  unsigned long long fileSize;
1952 
1953  if(!isPublic && read.is_open())
1954  {
1955  read.seekg(0, std::ios::end);
1956  fileSize = read.tellg();
1957  response = new char[fileSize + 1];
1958  response[fileSize] = '\0';
1959  read.seekg(0, std::ios::beg);
1960 
1961  // read data as a block:
1962  read.read(response, fileSize);
1963  read.close();
1964 
1965  xmldoc.addTextElementToData("FEsequence", &response[0]);
1966 
1967  delete[] response;
1968  }
1969  else
1970  {
1971  if(!isPublic)
1972  __SUP_COUT__ << "Unable to open " << fullPath << "! Trying public area..."
1973  << __E__;
1974 
1975  //attempt to load from admin "public" area
1976  std::string publicFullPath = (std::string)MACROS_SEQUENCE_PATH +
1977  WebUsers::DEFAULT_ADMIN_USERNAME + "/" + fixedName +
1978  ".dat";
1979  __SUP_COUT__ << publicFullPath << __E__;
1980 
1981  std::ifstream read(publicFullPath.c_str()); // reading the file
1982  char* response;
1983  unsigned long long fileSize;
1984 
1985  if(read.is_open())
1986  {
1987  read.seekg(0, std::ios::end);
1988  fileSize = read.tellg();
1989  response = new char[fileSize + 1];
1990  response[fileSize] = '\0';
1991  read.seekg(0, std::ios::beg);
1992 
1993  // read data as a block:
1994  read.read(response, fileSize);
1995  read.close();
1996 
1997  xmldoc.addTextElementToData("FEsequence", &response[0]);
1998 
1999  delete[] response;
2000  }
2001  else
2002  {
2003  __SUP_SS__ << "Unable to open FE Macro Sequence at " << fullPath << " or "
2004  << publicFullPath << __E__;
2005  __SUP_SS_THROW__;
2006  }
2007  }
2008 } //end getFEMacroSequence()
2009 
2010 //==============================================================================
2011 void MacroMakerSupervisor::deleteFEMacroSequence(cgicc::Cgicc& cgi,
2012  const std::string& username)
2013 {
2014  std::string name =
2016  __SUP_COUTV__(name);
2017 
2018  bool isPublic = (name.find("public/") == 0 ? true : false);
2019  __SUP_COUTV__(isPublic);
2020 
2021  //reject illegal characters (only alphanumeric, spaces, dash, underscores)
2022  std::string fixedName = "";
2023  for(size_t i = (isPublic ? std::string("public/").size() : 0); i < name.size(); ++i)
2024  if(!(name[i] == ' ' || name[i] == '-' || name[i] == '_' ||
2025  (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') ||
2026  (name[i] >= 'a' && name[i] <= 'z')))
2027  {
2028  __COUT__ << "Illegal character in Sequence name (position " << i
2029  << ") - only alphanumeric, spaces, dashes, and underscores allowed!"
2030  << __E__;
2031  }
2032  else
2033  fixedName += name[i];
2034  __SUP_COUTV__(fixedName);
2035 
2036  // access to the file
2037  std::string fullPath =
2038  (std::string)MACROS_SEQUENCE_PATH + username + "/" + fixedName + ".dat";
2039  if(isPublic)
2040  fullPath = (std::string)MACROS_SEQUENCE_PATH + WebUsers::DEFAULT_ADMIN_USERNAME +
2041  "/" + fixedName + ".dat";
2042  __SUP_COUT__ << fullPath << __E__;
2043 
2044  //do not allow overwrite
2045  if(!std::filesystem::exists(fullPath))
2046  {
2047  __SUP_SS__
2048  << "The specified Sequence name does not exist! Looking for sequence file at "
2049  << fullPath << __E__;
2050  __SUP_SS_THROW__;
2051  }
2052 
2053  std::remove(fullPath.c_str());
2054  __SUP_COUT__ << "Successfully deleted " << fullPath << __E__;
2055 } //end deleteFEMacroSequence()
2056 
2057 //==============================================================================
2058 void MacroMakerSupervisor::makeSequencePublic(cgicc::Cgicc& cgi,
2059  const std::string& username)
2060 {
2061  std::string name =
2063  __SUP_COUTV__(name);
2064 
2065  bool isPublic = (name.find("public/") == 0 ? true : false);
2066  __SUP_COUTV__(isPublic);
2067  if(isPublic)
2068  {
2069  __SUP_SS__ << "The specified Sequence name is already designated as public."
2070  << __E__;
2071  __SUP_SS_THROW__;
2072  }
2073 
2074  //reject illegal characters (only alphanumeric, spaces, dash, underscores)
2075  std::string fixedName = "";
2076  for(size_t i = 0; i < name.size(); ++i)
2077  if(!(name[i] == ' ' || name[i] == '-' || name[i] == '_' ||
2078  (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') ||
2079  (name[i] >= 'a' && name[i] <= 'z')))
2080  {
2081  __COUT__ << "Illegal character in Sequence name (position " << i
2082  << ") - only alphanumeric, spaces, dashes, and underscores allowed!"
2083  << __E__;
2084  }
2085  else
2086  fixedName += name[i];
2087  __SUP_COUTV__(fixedName);
2088 
2089  // access to the file
2090  std::string source =
2091  (std::string)MACROS_SEQUENCE_PATH + username + "/" + fixedName + ".dat";
2092  __SUP_COUT__ << source << __E__;
2093  std::string destination = (std::string)MACROS_SEQUENCE_PATH +
2094  WebUsers::DEFAULT_ADMIN_USERNAME + "/" + fixedName + ".dat";
2095  __SUP_COUT__ << destination << __E__;
2096 
2097  if(std::filesystem::exists(destination))
2098  {
2099  __SUP_SS__ << "The sequence name '" << fixedName
2100  << "' already exists in the admin/public location: " << destination
2101  << __E__;
2102  __SUP_SS_THROW__;
2103  }
2104 
2105  //copy if file does not already exist
2106  std::filesystem::copy_file(
2107  source, destination, std::filesystem::copy_options::skip_existing);
2108  __SUP_COUT__ << "Successfully made " << fixedName
2109  << " public at path: " << destination << __E__;
2110 } //end deleteFEMacroSequence()
2111 
2112 //==============================================================================
2113 void MacroMakerSupervisor::loadHistory(HttpXmlDocument& xmldoc,
2114  const std::string& username)
2115 {
2116  std::string fileName = MACROS_HIST_PATH + username + "/" + "history.hist";
2117 
2118  std::ifstream read(fileName.c_str()); // reading a file
2119  __SUP_COUT__ << fileName << __E__;
2120 
2121  if(read.is_open())
2122  {
2123  std::string line;
2124  char* returnStr;
2125  unsigned long long fileSz, i = 0, MAX_HISTORY_SIZE = 100000;
2126 
2127  // get length of file to reserve the string size
2128  // and to cap history size
2129  read.seekg(0, std::ios::end);
2130  fileSz = read.tellg();
2131  returnStr = new char[fileSz + 1];
2132  returnStr[fileSz] = '\0';
2133  read.seekg(0, std::ios::beg);
2134 
2135  // read data as a block:
2136  read.read(returnStr, fileSz);
2137  read.close();
2138 
2139  // find i such that new string size is less than
2140  if(fileSz > MAX_HISTORY_SIZE)
2141  {
2142  i = fileSz - MAX_HISTORY_SIZE;
2143  for(; i < fileSz; ++i)
2144  if(returnStr[i] == '#')
2145  {
2146  i += 2;
2147  break; // skip new line character also to get to next record
2148  }
2149  if(i > fileSz)
2150  i = fileSz;
2151 
2152  // write back to file truncated history
2153  FILE* fp = fopen(fileName.c_str(), "w");
2154  if(!fp)
2155  {
2156  delete[] returnStr;
2157  __SS__ << "Big problem with macromaker history file: " << fileName
2158  << __E__;
2159  __SS_THROW__;
2160  }
2161  fwrite(&returnStr[i], fileSz - i, 1, fp);
2162  fclose(fp);
2163  }
2164 
2165  __SUP_COUT__ << "Loading user history! " << __E__;
2166 
2167  if(fileSz > 1)
2168  returnStr[fileSz - 2] = '\0'; // remove final newline and last #
2169 
2170  xmldoc.addTextElementToData("returnHistStr", &returnStr[i]);
2171 
2172  delete[] returnStr;
2173  }
2174  else
2175  __SUP_COUT__ << "Unable to open history.hist" << __E__;
2176 
2177 } //end loadHistory()
2178 
2179 //==============================================================================
2180 void MacroMakerSupervisor::loadFEHistory(HttpXmlDocument& xmldoc,
2181  const std::string& username)
2182 {
2183  std::string fileName = MACROS_HIST_PATH + username + "/" + "FEhistory.hist";
2184 
2185  std::ifstream read(fileName.c_str());
2186  __SUP_COUT__ << fileName << __E__;
2187 
2188  if(!read.is_open() && username != WebUsers::DEFAULT_ADMIN_USERNAME)
2189  {
2190  __SUP_COUT__ << "Unable to open FE history.hist.. Defaulting to admin's FE "
2191  "history as starting point."
2192  << __E__;
2193 
2194  fileName =
2195  MACROS_HIST_PATH + WebUsers::DEFAULT_ADMIN_USERNAME + "/" + "FEhistory.hist";
2196  read.open(fileName.c_str());
2197  }
2198 
2199  if(read.is_open())
2200  {
2201  std::string line;
2202  char* returnStr;
2203  unsigned long long fileSize;
2204  unsigned long long i = 0;
2205  unsigned long long MAX_HISTORY_SIZE = 100000;
2206 
2207  // get the length of the file
2208  read.seekg(0, std::ios::end);
2209  fileSize = read.tellg();
2210  returnStr = new char[fileSize + 1];
2211  returnStr[fileSize] = '\0';
2212  read.seekg(0, std::ios::beg);
2213 
2214  // read data as block
2215  read.read(returnStr, fileSize);
2216  read.close();
2217 
2218  // find i such that new string size is less than
2219  if(fileSize > MAX_HISTORY_SIZE)
2220  {
2221  i = fileSize - MAX_HISTORY_SIZE;
2222  for(; i < fileSize; ++i)
2223  {
2224  if(returnStr[i] == '#') // skip the new line char
2225  {
2226  i += 2;
2227  break;
2228  }
2229  }
2230  if(i > fileSize)
2231  i = fileSize;
2232 
2233  // write back to file truncated history
2234  FILE* fp = fopen(fileName.c_str(), "w");
2235  if(!fp)
2236  {
2237  delete[] returnStr;
2238  __SS__ << "Big problem with FE history file: " << fileName << __E__;
2239  __SS_THROW__;
2240  }
2241  fwrite(&returnStr[i], fileSize - i, 1, fp);
2242  fclose(fp);
2243  }
2244 
2245  __SUP_COUT__ << "Loading user history! " << __E__;
2246 
2247  if(fileSize > 1)
2248  returnStr[fileSize - 2] = '\0'; // remove final newline and last #
2249 
2250  xmldoc.addTextElementToData("returnHistStr", &returnStr[i]);
2251 
2252  delete[] returnStr;
2253  }
2254  else
2255  __SUP_COUT__ << "Unable to open FE history.hist" << __E__;
2256 
2257 } //end loadFEHistory()
2258 
2259 //==============================================================================
2260 void MacroMakerSupervisor::deleteMacro(HttpXmlDocument& xmldoc,
2261  cgicc::Cgicc& cgi,
2262  const std::string& username)
2263 {
2264  std::string MacroName = CgiDataUtilities::getData(cgi, "MacroName");
2265  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
2266 
2267  std::string fileName = MacroName + ".dat";
2268  std::string fullPath;
2269  if(isMacroPublic == "true")
2270  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
2271  else
2272  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
2273 
2274  __SUP_COUT__ << fullPath << __E__;
2275 
2276  std::remove(fullPath.c_str());
2277  __SUP_COUT__ << "Successfully deleted " << MacroName;
2278  xmldoc.addTextElementToData("deletedMacroName", MacroName);
2279 } //end deleteMacro()
2280 
2281 //==============================================================================
2282 void MacroMakerSupervisor::editMacro(HttpXmlDocument& xmldoc,
2283  cgicc::Cgicc& cgi,
2284  const std::string& username)
2285 {
2286  std::string oldMacroName = CgiDataUtilities::postData(cgi, "oldMacroName");
2287  std::string newMacroName = CgiDataUtilities::postData(cgi, "newMacroName");
2288  std::string FESequence = CgiDataUtilities::postData(cgi, "FEsequence");
2289  std::string Time = CgiDataUtilities::postData(cgi, "Time");
2290  std::string Notes =
2292 
2293  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
2294  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
2295 
2296  __SUP_COUTV__(oldMacroName);
2297  __SUP_COUTV__(newMacroName);
2298  __SUP_COUTV__(FESequence);
2299  __SUP_COUTV__(Notes);
2300  __SUP_COUTV__(Time);
2301  __SUP_COUTV__(isMacroPublic);
2302  __SUP_COUTV__(isMacroLSBF);
2303 
2304  __SUP_COUTV__(MACROS_DB_PATH);
2305 
2306  std::string fileName = oldMacroName + ".dat";
2307  std::string fullPath;
2308  if(isMacroPublic == "true")
2309  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
2310  else
2311  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
2312 
2313  __SUP_COUTV__(fullPath);
2314 
2315  std::ofstream macrofile(fullPath.c_str());
2316  if(macrofile.is_open())
2317  {
2318  macrofile << "{\n";
2319  macrofile << "\"name\":\"" << newMacroName << "\",\n";
2320  macrofile << "\"FEsequence\":\"" << FESequence << "\",\n";
2321  macrofile << "\"time\":\"" << Time << "\",\n";
2322  macrofile << "\"notes\":\"" << Notes << "\",\n";
2323  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
2324  macrofile << "}@" << __E__;
2325  macrofile.close();
2326  }
2327  else
2328  __SUP_COUT__ << "Unable to open file" << __E__;
2329 
2330  if(oldMacroName != newMacroName) // renaming macro
2331  {
2332  int result;
2333  result =
2334  rename((MACROS_DB_PATH + username + "/" + oldMacroName + ".dat").c_str(),
2335  (MACROS_DB_PATH + username + "/" + newMacroName + ".dat").c_str());
2336  if(result == 0)
2337  xmldoc.addTextElementToData("newMacroName", newMacroName);
2338  else
2339  xmldoc.addTextElementToData("newMacroName", "ERROR");
2340  }
2341 } //end editMacro()
2342 
2343 //==============================================================================
2344 void MacroMakerSupervisor::clearHistory(const std::string& username)
2345 {
2346  std::string fileName = "history.hist";
2347  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
2348 
2349  std::remove(fullPath.c_str());
2350  __SUP_COUT__ << "Successfully deleted " << fullPath;
2351 } //end clearHistory()
2352 
2353 //==============================================================================
2354 void MacroMakerSupervisor::clearFEHistory(const std::string& username)
2355 {
2356  std::string fileName = "FEhistory.hist";
2357  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
2358 
2359  std::remove(fullPath.c_str());
2360  __SUP_COUT__ << "Successfully deleted " << fullPath;
2361 } //end clearFEHistory()
2362 
2363 //==============================================================================
2364 void MacroMakerSupervisor::exportFEMacro(HttpXmlDocument& xmldoc,
2365  cgicc::Cgicc& cgi,
2366  const std::string& username)
2367 {
2368  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
2369  std::string pluginName = CgiDataUtilities::getData(cgi, "PluginName");
2370  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
2371  std::string macroNotes =
2373 
2374  __SUP_COUTV__(pluginName);
2375  __SUP_COUTV__(macroName);
2376  __SUP_COUTV__(macroSequence);
2377 
2378  // replace all special characters with white space
2379  for(unsigned int i = 0; i < macroNotes.length(); ++i)
2380  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
2381  macroNotes[i] = ' ';
2382  __SUP_COUTV__(macroNotes);
2383 
2384  std::stringstream ss(macroSequence);
2385  std::string command;
2386  std::vector<std::string> commands;
2387 
2388  while(getline(ss, command, ','))
2389  commands.push_back(command);
2390 
2391  __SUP_COUTV__(StringMacros::vectorToString(commands));
2392 
2393  std::map<std::string /*special type*/, std::set<std::string> /*special file paths*/>
2394  specialsCodeMap = CodeEditor::getSpecialsMap();
2395 
2396  //__SUP_COUTV__(StringMacros::mapToString(specialsCodeMap));
2397  auto specialsCodeMapIt = specialsCodeMap.find(CodeEditor::SPECIAL_TYPE_FEInterface);
2398  if(specialsCodeMapIt == specialsCodeMap.end())
2399  {
2400  __SS__
2401  << "Could not find any FE Interface plugins in source code. Does MacroMaker "
2402  << "have access to the source code? Check that the Supervisor context places "
2403  "MacroMaker in a "
2404  << "location with access to the source code." << __E__;
2405  __SS_THROW__;
2406  }
2407 
2408  // find first .h and .cc with the plugin name
2409  std::string headerFile = pluginName + ".h";
2410  std::string sourceFile = pluginName + "_interface.cc";
2411  bool foundHeaderFile = false;
2412  bool foundSourceFile = false;
2413  for(const auto& filePath : specialsCodeMapIt->second)
2414  {
2415  if(!foundHeaderFile && filePath.find(headerFile) != std::string::npos)
2416  {
2417  foundHeaderFile = true;
2418  headerFile = filePath;
2419  __SUP_COUT__ << "found headerFile=" << filePath << __E__;
2420  }
2421  if(!foundSourceFile && filePath.find(sourceFile) != std::string::npos)
2422  {
2423  foundSourceFile = true;
2424  sourceFile = filePath;
2425  __SUP_COUT__ << "found sourceFile=" << filePath << __E__;
2426  }
2427 
2428  if(foundSourceFile && foundHeaderFile)
2429  break;
2430  } // end file search loop
2431 
2432  if(!foundHeaderFile)
2433  {
2434  __SS__ << "Could not find the header file for the FE Interface plugins at '"
2435  << headerFile << ".' Does MacroMaker "
2436  << "have access to the source code? Check that the Supervisor context "
2437  "places MacroMaker in a "
2438  << "location with access to the source code." << __E__;
2439  __SS_THROW__;
2440  }
2441  if(!foundSourceFile)
2442  {
2443  __SS__ << "Could not find the source file for the FE Interface plugins at '"
2444  << sourceFile << ".' Does MacroMaker "
2445  << "have access to the source code? Check that the Supervisor context "
2446  "places MacroMaker in a "
2447  << "location with access to the source code." << __E__;
2448  __SS_THROW__;
2449  }
2450 
2451  // at this point have header and source file, now add FE Macro
2452  // Steps for each file:
2453  // - read current file
2454  // - find insert point
2455  // - open file for writing
2456  // - write original file up to insert point
2457  // - insert new code
2458  // - write remaining original file
2459 
2460  char timeBuffer[100];
2461  { // get time string
2462  time_t rawtime;
2463  struct tm* timeinfo;
2464 
2465  time(&rawtime);
2466  timeinfo = localtime(&rawtime);
2467 
2468  strftime(timeBuffer, 100, "%b-%d-%Y %I:%M:%S", timeinfo);
2469  }
2470 
2471  std::string contents;
2472  std::string insert;
2473 
2475  // handle source file modifications
2476  CodeEditor::readFile(CodeEditor::SOURCE_BASE_PATH, sourceFile, contents);
2477  //__SUP_COUTV__(contents);
2478 
2479  // return file locations, for the user to inspect on error
2480  xmldoc.addTextElementToData("sourceFile", sourceFile);
2481  xmldoc.addTextElementToData("headerFile", headerFile);
2482 
2483  // check for duplicate functions
2484  if(contents.find(pluginName + "::" + macroName) != std::string::npos)
2485  {
2486  __SS__ << "The function definition '" << (pluginName + "::" + macroName)
2487  << "(...)' already exists in the source file '" << sourceFile
2488  << ".' Duplicate functions are not allowed - please rename the macro or "
2489  "modify the source file."
2490  << __E__;
2491  __SS_THROW__;
2492  }
2493 
2494  std::stringstream codess;
2495  std::set<std::string> inArgNames, outArgNames;
2496  createCode(codess,
2497  commands,
2498  "\t" /*tabOffset*/,
2499  true /*forFeMacro*/,
2500  &inArgNames,
2501  &outArgNames);
2502  __SUP_COUTV__(StringMacros::setToString(inArgNames));
2503  __SUP_COUTV__(StringMacros::setToString(outArgNames));
2504 
2505  // find start of constructor and register macro
2506  {
2507  auto insertPos = contents.find(pluginName + "::" + pluginName);
2508  if(insertPos == std::string::npos)
2509  {
2510  __SS__ << "Could not find the code insert position in the source file '"
2511  << sourceFile << ".' The FE plugin class constructor must be '"
2512  << pluginName << ":" << pluginName << "' - is this the case?" << __E__;
2513  __SS_THROW__;
2514  }
2515  __SUP_COUTV__(insertPos);
2516  // find opening bracket after constructor name
2517  insertPos = contents.find("{", insertPos);
2518  if(insertPos == std::string::npos)
2519  {
2520  __SS__ << "Could not find the code insert position in the source file '"
2521  << sourceFile
2522  << ".' The FE plugin class constructor must begin with '{"
2523  << "' - is this the case?" << __E__;
2524  __SS_THROW__;
2525  }
2526  ++insertPos; // go past {
2527  __SUP_COUTV__(insertPos);
2528 
2529  insert = "\n\t//registration of FEMacro '" + macroName + "' generated, " +
2530  timeBuffer + ", by '" + username + "' using MacroMaker.\n\t" +
2531  "FEVInterface::registerFEMacroFunction(\"" + macroName +
2532  "\",//feMacroName \n\t\t" +
2533  "static_cast<FEVInterface::frontEndMacroFunction_t>(&" + pluginName +
2534  "::" + macroName + "), //feMacroFunction \n\t\t" +
2535  "std::vector<std::string>{";
2536  { // insert input argument names
2537  bool first = true;
2538  for(const auto& inArg : inArgNames)
2539  {
2540  if(first)
2541  first = false;
2542  else
2543  insert += ",";
2544  insert += "\"" + inArg + "\"";
2545  }
2546  }
2547  insert += "}, //namesOfInputArgs \n\t\t";
2548  insert += "std::vector<std::string>{";
2549  { // insert output argument names
2550  bool first = true;
2551  for(const auto& outArg : outArgNames)
2552  {
2553  if(first)
2554  first = false;
2555  else
2556  insert += ",";
2557  insert += "\"" + outArg + "\"";
2558  }
2559  }
2560  insert += "}, //namesOfOutputArgs \n\t\t";
2561  insert += "1); //requiredUserPermissions \n\n";
2562 
2563  __SUP_COUTV__(insert);
2564  contents = contents.substr(0, insertPos) + insert + contents.substr(insertPos);
2565  }
2566 
2567  // find end of source to append FE Macro function
2568  {
2569  auto insertPos = contents.rfind("DEFINE_OTS_INTERFACE");
2570  if(insertPos == std::string::npos)
2571  {
2572  __SS__ << "Could not find the code insert position in the source file '"
2573  << sourceFile
2574  << ".' The FE plugin class must end with a 'DEFINE_OTS_INTERFACE("
2575  << pluginName << ")' - is this the case?" << __E__;
2576  __SS_THROW__;
2577  }
2578  __SUP_COUTV__(insertPos);
2579 
2580  insert =
2581  "\n//"
2582  "============================================================================"
2583  "============================================\n//" +
2584  macroName + "\n" + "//\tFEMacro '" + macroName + "' generated, " +
2585  timeBuffer + ", by '" + username + "' using MacroMaker.\n" +
2586  "//\tMacro Notes: " + macroNotes + "\n" + "void " + pluginName +
2587  "::" + macroName + "(__ARGS__)\n{\n\t" +
2588  "__CFG_COUT__ << \"# of input args = \" << argsIn.size() << __E__; \n\t" +
2589  "__CFG_COUT__ << \"# of output args = \" << argsOut.size() << __E__; \n\t" +
2590  "for(auto &argIn:argsIn) \n\t\t" +
2591  "__CFG_COUT__ << argIn.first << \": \" << argIn.second << __E__; \n\n\t" +
2592  "//macro commands section \n" + codess.str() + "\n\n\t" +
2593  "for(auto &argOut:argsOut) \n\t\t" +
2594  "__CFG_COUT__ << argOut.first << \": \" << argOut.second << __E__; \n\n" +
2595  "} //end " + macroName + "()\n\n";
2596 
2597  //__SUP_COUTV__(insert);
2598  CodeEditor::writeFile(CodeEditor::SOURCE_BASE_PATH,
2599  sourceFile,
2600  contents,
2601  "MacroMaker-" + username,
2602  insertPos,
2603  insert);
2604  }
2605 
2607  // handle include file insertions
2608  CodeEditor::readFile(CodeEditor::SOURCE_BASE_PATH, headerFile, contents);
2609  //__SUP_COUTV__(contents);
2610 
2611  // find end of class by looking for last };
2612  {
2613  auto insertPos = contents.rfind("};");
2614  if(insertPos == std::string::npos)
2615  {
2616  __SS__ << "Could not find the code insert position in the header file '"
2617  << headerFile
2618  << ".' The FE plugin class must end with a '};' - is this the case?"
2619  << __E__;
2620  __SS_THROW__;
2621  }
2622 
2623  __SUP_COUTV__(insertPos);
2624 
2625  insert = "\npublic: // FEMacro '" + macroName + "' generated, " + timeBuffer +
2626  ", by '" + username + "' using MacroMaker.\n\t" + "void " + macroName +
2627  "\t(__ARGS__);\n";
2628 
2629  __SUP_COUTV__(insert);
2630  CodeEditor::writeFile(CodeEditor::SOURCE_BASE_PATH,
2631  headerFile,
2632  contents,
2633  "MacroMaker-" + username,
2634  insertPos,
2635  insert);
2636  }
2637 
2638 } // end exportFEMacro()
2639 
2640 //==============================================================================
2641 void MacroMakerSupervisor::exportMacro(HttpXmlDocument& xmldoc,
2642  cgicc::Cgicc& cgi,
2643  const std::string& username)
2644 {
2645  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
2646  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
2647  std::string macroNotes =
2649 
2650  __SUP_COUTV__(macroName);
2651  __SUP_COUTV__(macroSequence);
2652 
2653  // replace all special characters with white space
2654  for(unsigned int i = 0; i < macroNotes.length(); ++i)
2655  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
2656  macroNotes[i] = ' ';
2657  __SUP_COUTV__(macroNotes);
2658 
2659  std::stringstream ss(macroSequence);
2660  std::string command;
2661  std::vector<std::string> commands;
2662 
2663  while(getline(ss, command, ','))
2664  commands.push_back(command);
2665 
2666  std::string fileName = macroName + ".cc";
2667 
2668  std::string fullPath =
2669  __ENV__("SERVICE_DATA_PATH") + MACROS_EXPORT_PATH + username + "/" + fileName;
2670  __SUP_COUT__ << fullPath << __E__;
2671  std::ofstream exportFile(fullPath.c_str(), std::ios::trunc);
2672  if(exportFile.is_open())
2673  {
2674  exportFile << "//Generated Macro Name:\t" << macroName << "\n";
2675  exportFile << "//Macro Notes: " << macroNotes << "\n";
2676 
2677  {
2678  time_t rawtime;
2679  struct tm* timeinfo;
2680  char buffer[100];
2681 
2682  time(&rawtime);
2683  timeinfo = localtime(&rawtime);
2684 
2685  strftime(buffer, 100, "%b-%d-%Y %I:%M:%S", timeinfo);
2686  exportFile << "//Generated Time: \t\t" << buffer << "\n";
2687  }
2688 
2689  exportFile << "//Paste this whole file into an interface to transfer Macro "
2690  "functionality.\n";
2691 
2692  createCode(exportFile, commands);
2693 
2694  exportFile.close();
2695 
2696  xmldoc.addTextElementToData(
2697  "ExportFile",
2698  "$USER_DATA/ServiceData/" + MACROS_EXPORT_PATH + username + "/" + fileName);
2699  }
2700  else
2701  __SUP_COUT__ << "Unable to open file" << __E__;
2702 } // end exportMacro()
2703 
2704 //==============================================================================
2706 void MacroMakerSupervisor::createCode(std::ostream& out,
2707  const std::vector<std::string>& commands,
2708  const std::string& tabOffset,
2709  bool forFeMacro,
2710  std::set<std::string>* inArgNames,
2711  std::set<std::string>* outArgNames)
2712 {
2713  // int numOfHexBytes;
2714  std::set<std::string /*argInName*/> argInHasBeenInitializedSet;
2715  bool addressIsVariable, dataIsVariable;
2716 
2717  out << tabOffset << "{";
2718 
2719  out << "\n"
2720  << tabOffset << "\t"
2721  << "char *address \t= new char[universalAddressSize_]{0}; //create address "
2722  "buffer of interface size and init to all 0";
2723  out << "\n"
2724  << tabOffset << "\t"
2725  << "char *data \t\t= new char[universalDataSize_]{0}; //create data buffer "
2726  "of interface size and init to all 0";
2727 
2728  out << "\n"
2729  << tabOffset << "\t"
2730  << "uint64_t macroAddress; //create macro address buffer (size 8 bytes)";
2731  out << "\n"
2732  << tabOffset << "\t"
2733  << "uint64_t macroData; //create macro address buffer (size 8 bytes)";
2734 
2735  out << "\n"
2736  << tabOffset << "\t"
2737  << "std::map<std::string /*arg name*/,uint64_t /*arg val*/> macroArgs; //create "
2738  "map from arg name to 64-bit number";
2739 
2740  // loop through each macro command
2741  for(unsigned int i = 0; i < commands.size(); i++)
2742  {
2743  std::stringstream sst(commands[i]);
2744  std::string tokens;
2745  std::vector<std::string>
2746  oneCommand; // 4 fields: cmd index | cmd type | addr | data
2747  while(getline(sst, tokens, ':'))
2748  oneCommand.push_back(tokens);
2749  while(oneCommand.size() < 4)
2750  oneCommand.push_back(""); // fill out the 4 fields
2751 
2752  __SUP_COUTV__(StringMacros::vectorToString(oneCommand));
2753 
2754  // make this:
2755  // std::map<std::string,uint64_t> macroArgs;
2756  // {
2757  // uint64_t address = 0x1001; //create address buffer
2758  // uint64_t data = 0x100203; //create data buffer
2759  //
2760  // universalWrite(address,data);
2761  // universalRead(address,data);
2762  // }
2763  //
2764  // //if variable, first time init
2765  // {
2766  // address =
2767  // theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode("variableName").getValue<uint64_t>();
2768  // or
2769  // address = __GET_ARG_IN__("variableName",uint64_t);
2770  // }
2771  //
2772  // //if variable, second time use macroArgs
2773  // {
2774  // address = macroArgs["variableName"];
2775  // data = macroArgs["variableName"];
2776  // }
2777 
2778  addressIsVariable = isArgumentVariable(oneCommand[2]);
2779  dataIsVariable = isArgumentVariable(oneCommand[3]);
2780 
2781  __SUP_COUTV__(addressIsVariable);
2782  __SUP_COUTV__(dataIsVariable);
2783 
2784  out << "\n\n" << tabOffset << "\t// command-#" << i << ": ";
2785 
2786  if(oneCommand[1][0] == 'w' || oneCommand[1][0] == 'r')
2787  {
2788  if(oneCommand[1][0] == 'w')
2789  out << "Write(";
2790  else if(oneCommand[1][0] == 'r')
2791  out << "Read(";
2792 
2793  if(addressIsVariable)
2794  out << oneCommand[2];
2795  else // literal hex address
2796  out << "0x" << oneCommand[2];
2797  out << " /*address*/,";
2798 
2799  if(dataIsVariable) // read or write can have variable data, sink or source
2800  // respectively
2801  out << oneCommand[3] << " /*data*/";
2802  else if(oneCommand[1][0] == 'w') // literal hex data
2803  out << "0x" << oneCommand[3] << " /*data*/";
2804  else if(oneCommand[1][0] == 'r') // just reading to buffer
2805  out << "data";
2806  out << ");\n";
2807  }
2808  else if(oneCommand[1][0] == 'd')
2809  {
2810  out << "delay(" << oneCommand[2] << ");\n";
2811  out << tabOffset << "\t"
2812  << "__CFG_COUT__ << \"Sleeping for... \" << " << oneCommand[2]
2813  << " << \" milliseconds \" << __E__;\n";
2814  out << tabOffset << "\t"
2815  << "usleep(" << oneCommand[2] << "*1000 /* microseconds */);\n";
2816  continue;
2817  }
2818  else
2819  {
2820  __SS__ << "FATAL ERROR: Unknown command '" << oneCommand[1]
2821  << "'... command is not w, r or d" << __E__;
2822  __SS_THROW__;
2823  }
2824 
2826  // handle address
2827  if(addressIsVariable) // handle address as variable
2828  {
2829  if(argInHasBeenInitializedSet.find(oneCommand[2]) ==
2830  argInHasBeenInitializedSet.end()) // only initialize input argument once
2831  {
2832  argInHasBeenInitializedSet.emplace(oneCommand[2]);
2833 
2834  if(!forFeMacro)
2835  {
2836  // get address from configuration Tree
2837  out << tabOffset << "\t"
2838  << "macroArgs[\"" << oneCommand[2]
2839  << "\"] = "
2840  "theXDAQContextConfigTree_.getNode(theConfigurationPath_)."
2841  "getNode("
2842  << "\n"
2843  << tabOffset << "\t\t\"" << oneCommand[2]
2844  << "\").getValue<uint64_t>();";
2845  }
2846  else
2847  {
2848  if(inArgNames)
2849  inArgNames->emplace(oneCommand[2]);
2850 
2851  // get address from arguments
2852  out << tabOffset << "\t"
2853  << "macroArgs[\"" << oneCommand[2] << "\"] = __GET_ARG_IN__(\""
2854  << oneCommand[2] << "\", uint64_t);";
2855  }
2856  }
2857  out << "\t//get macro address argument";
2858  out << "\n"
2859  << tabOffset << "\tmemcpy(address,&macroArgs[\"" << oneCommand[2]
2860  << "\"],8); //copy macro address argument to buffer";
2861  }
2862  else // handle address as literal
2863  {
2864  out << tabOffset << "\t"
2865  << "macroAddress = 0x" << oneCommand[2]
2866  << "; memcpy(address,&macroAddress,8);"
2867  << "\t//copy macro address to buffer";
2868  }
2869 
2871  // handle data
2872  if(oneCommand[1] == "w") // if write, handle data too
2873  {
2874  if(dataIsVariable) // handle data as variable
2875  {
2876  if(argInHasBeenInitializedSet.find(oneCommand[3]) ==
2877  argInHasBeenInitializedSet
2878  .end()) // only initialize input argument once
2879  {
2880  argInHasBeenInitializedSet.emplace(oneCommand[3]);
2881 
2882  if(forFeMacro)
2883  {
2884  if(inArgNames)
2885  inArgNames->emplace(oneCommand[3]);
2886 
2887  // get data from arguments
2888  out << "\n"
2889  << tabOffset << "\t"
2890  << "macroArgs[\"" << oneCommand[3]
2891  << "\"] = __GET_ARG_IN__(\"" << oneCommand[3]
2892  << "\", uint64_t); //initialize from input arguments";
2893  }
2894  else
2895  {
2896  // get data from configuration Tree
2897  out << "\n"
2898  << tabOffset << "\t"
2899  << "macroArgs[\"" << oneCommand[3]
2900  << "\"] = "
2901  "theXDAQContextConfigTree_.getNode(theConfigurationPath_)."
2902  "getNode("
2903  << "\n"
2904  << tabOffset << "\t\t\"" << oneCommand[3]
2905  << "\").getValue<uint64_t>(); //initialize from "
2906  "configuration tree";
2907  }
2908  }
2909  out << "\t//get macro data argument";
2910  out << "\n"
2911  << tabOffset << "\tmemcpy(data,&macroArgs[\"" << oneCommand[3]
2912  << "\"],8); //copy macro data argument to buffer";
2913  }
2914  else // handle data as literal
2915  {
2916  out << "\n"
2917  << tabOffset << "\t"
2918  << "macroData = 0x" << oneCommand[3] << "; memcpy(data,&macroData,8);"
2919  << "\t//copy macro data to buffer";
2920  }
2921  out << "\n"
2922  << tabOffset << "\t"
2923  << "universalWrite(address,data);";
2924  }
2925  else
2926  {
2927  out << "\n"
2928  << tabOffset << "\t"
2929  << "universalRead(address,data);";
2930 
2931  std::string outputArgName;
2932 
2933  if(dataIsVariable) // handle data as variable
2934  outputArgName = oneCommand[3];
2935  else // give each read data a unique argument name
2936  {
2937  char str[20];
2938  sprintf(str, "outArg%d", i);
2939  outputArgName = str; // use command index for uniqueness
2940  }
2941  __SUP_COUTV__(outputArgName);
2942 
2943  out << tabOffset << "\t"
2944  << "memcpy(&macroArgs[\"" << outputArgName
2945  << "\"],data,8); //copy buffer to argument map";
2946 
2947  // copy read data to output args
2948  if(forFeMacro)
2949  out << "\n"
2950  << tabOffset << "\t"
2951  << "__SET_ARG_OUT__(\"" << outputArgName << "\",macroArgs[\""
2952  << outputArgName << "\"]); //update output argument result";
2953 
2954  if(outArgNames)
2955  outArgNames->emplace(outputArgName);
2956  argInHasBeenInitializedSet.emplace(
2957  outputArgName); // mark initialized since value has been read
2958  }
2959  } // end command loop
2960 
2961  out << "\n\n" << tabOffset << "\tdelete[] address; //free the memory";
2962  out << "\n" << tabOffset << "\tdelete[] data; //free the memory";
2963  out << "\n" << tabOffset << "}";
2964 
2965  __SUP_COUT__ << "Done with code generation." << __E__;
2966 } // end createCode()
2967 
2968 //==============================================================================
2971 bool MacroMakerSupervisor::isArgumentVariable(const std::string& argumentString)
2972 {
2973  for(unsigned int i = 0; i < argumentString.length(); ++i)
2974  {
2975  // detect non-hex
2976  if(!((argumentString[i] >= '0' && argumentString[i] <= '9') ||
2977  (argumentString[i] >= 'a' && argumentString[i] <= 'f') ||
2978  (argumentString[i] >= 'A' && argumentString[i] <= 'F')))
2979  return true;
2980  }
2981  return false;
2982 } // end isArgumentVariable()
2983 //==============================================================================
2993 std::string MacroMakerSupervisor::generateHexArray(const std::string& sourceHexString,
2994  int& numOfBytes)
2995 {
2996  std::stringstream retSs;
2997 
2998  std::string srcHexStr = sourceHexString;
2999  __SUP_COUT__ << "Translating: \n";
3000  __SUP_COUT__ << srcHexStr << __E__;
3001 
3002  if(srcHexStr.size() % 2) // if odd, make even
3003  srcHexStr = "0" + srcHexStr;
3004 
3005  numOfBytes = srcHexStr.size() / 2;
3006  retSs << "[" << numOfBytes << "] = {";
3007 
3008  for(int i = 0; i < numOfBytes * 2; i += 2)
3009  {
3010  // detect non-hex
3011  if(!((srcHexStr[i] >= '0' && srcHexStr[i] <= '9') ||
3012  (srcHexStr[i] >= 'a' && srcHexStr[i] <= 'f') ||
3013  (srcHexStr[i] >= 'A' && srcHexStr[i] <= 'F')) ||
3014  !((srcHexStr[i + 1] >= '0' && srcHexStr[i + 1] <= '9') ||
3015  (srcHexStr[i + 1] >= 'a' && srcHexStr[i + 1] <= 'f') ||
3016  (srcHexStr[i + 1] >= 'A' && srcHexStr[i + 1] <= 'F')))
3017  {
3018  numOfBytes = -1;
3019  return srcHexStr;
3020  }
3021 
3022  if(i != 0)
3023  retSs << ", ";
3024  retSs << "0x" << srcHexStr[srcHexStr.size() - 1 - i - 1]
3025  << srcHexStr[srcHexStr.size() - 1 - i];
3026  }
3027  retSs << "};";
3028 
3029  __SUP_COUT__ << retSs.str() << __E__;
3030 
3031  return retSs.str();
3032 } //end generateHexArray()
3033 
3034 //==============================================================================
3035 void MacroMakerSupervisor::runFEMacro(HttpXmlDocument& xmldoc,
3036  cgicc::Cgicc& cgi,
3037  const WebUsers::RequestUserInfo& userInfo)
3038 try
3039 {
3040  __SUP_COUTT__ << __E__;
3041 
3042  uint64_t NotDoneID = CgiDataUtilities::getDataAsUint64_t(cgi, "NotDoneID");
3043  if(NotDoneID)
3044  {
3045  __SUP_COUT__ << "Checking if recent FE macro run has completed for NotDoneID = "
3046  << NotDoneID << __E__;
3047 
3048  for(const auto& feMacroRunThreadStruct : feMacroRunThreadStruct_)
3049  __SUP_COUTT__ << "[] threadID_ = "
3050  << feMacroRunThreadStruct.parameters_.threadID_ << __E__;
3051 
3052  time_t now = time(0);
3053  size_t target_i = -1;
3054  for(size_t i = 0; i < feMacroRunThreadStruct_.size(); ++i)
3055  {
3056  if(feMacroRunThreadStruct_[i].parameters_.threadID_ == NotDoneID)
3057  {
3058  //found
3059  __SUP_COUTT__ << "Found NotDoneID = " << NotDoneID << __E__;
3060  target_i = i;
3061  }
3062  else if(feMacroRunThreadStruct_[i].feMacroRunDone_ &&
3063  now - feMacroRunThreadStruct_[i].parameters_.doneTime_ >
3064  5 * 60 * 60 /* 5 minutes*/)
3065  {
3066  __SUP_COUTT__ << "Cleaning up completed NotDoneID = " << NotDoneID
3067  << __E__;
3068  //clean up old structs
3069  feMacroRunThreadStruct_.erase(feMacroRunThreadStruct_.begin() + i);
3070  --i; //rewind
3071  }
3072  else if(now - feMacroRunThreadStruct_[i].parameters_.startTime_ >
3073  5 * 60 * 60 /* 5 minutes*/)
3074  {
3075  __SUP_COUT_WARN__
3076  << "Found old FE Macro exectution of '"
3077  << feMacroRunThreadStruct_[i].parameters_.macroName_ << "' at '"
3078  << feMacroRunThreadStruct_[i].parameters_.feUIDSelected_ << ".'"
3079  << __E__;
3080  }
3081  }
3082 
3083  if(target_i >= feMacroRunThreadStruct_.size())
3084  {
3085  __SUP_SS__
3086  << "Attempted to check recent FE Macro run completion with invalid ID="
3087  << NotDoneID
3088  << ". Perhaps this FE Macro completed more than 5 minutes ago?" << __E__;
3089  __SUP_SS_THROW__;
3090  }
3091 
3092  if(feMacroRunThreadStruct_[target_i].feMacroRunDone_)
3093  {
3094  __SUP_COUT__ << "Found done for NotDoneID = " << NotDoneID << __E__;
3095 
3096  if(feMacroRunThreadStruct_[target_i].parameters_.feMacroRunError_ != "")
3097  {
3098  __SUP_SS__
3099  << feMacroRunThreadStruct_[target_i].parameters_.feMacroRunError_;
3100  __SUP_SS_THROW__;
3101  }
3102  //copy result back to user
3103  if(TTEST(1))
3104  {
3105  std::ostringstream oss;
3106  feMacroRunThreadStruct_.back().parameters_.xmldoc_.outputXmlDocument(
3107  &oss);
3108  __SUP_COUTT__ << "xmldoc: " << oss.str() << __E__;
3109  }
3110  xmldoc.copyDataChildren(
3111  feMacroRunThreadStruct_[target_i].parameters_.xmldoc_);
3112  __SUP_COUT__ << "FE macro complete." << __E__;
3113  }
3114  else
3115  {
3116  __SUP_COUT__ << "Found still going for NotDoneID = " << NotDoneID << __E__;
3117  //return same NotDoneID to user for future check
3118  xmldoc.addNumberElementToData("NotDoneID", NotDoneID);
3119  }
3120 
3121  return;
3122  } //end done checking for done long duration FE Macro
3123 
3124  std::string feClassSelected = CgiDataUtilities::getData(cgi, "feClassSelected");
3125  std::string feUIDSelected =
3126  CgiDataUtilities::getData(cgi, "feUIDSelected"); // allow CSV multi-selection
3127  std::string macroType = CgiDataUtilities::getData(cgi, "macroType");
3128  std::string macroName =
3130  std::string inputArgs = CgiDataUtilities::postData(cgi, "inputArgs");
3131  std::string outputArgs = CgiDataUtilities::postData(cgi, "outputArgs");
3132  bool saveOutputs = CgiDataUtilities::getDataAsInt(cgi, "saveOutputs") == 1;
3133 
3134  __SUP_COUTTV__(feClassSelected);
3135  __SUP_COUTTV__(feUIDSelected);
3136  __SUP_COUTTV__(macroType);
3137  __SUP_COUTTV__(macroName);
3138  __SUP_COUTTV__(inputArgs);
3139  __SUP_COUTTV__(outputArgs);
3140  __SUP_COUTTV__(saveOutputs);
3141  __SUP_COUTTV__(userInfo.username_);
3142  __SUP_COUTTV__(StringMacros::mapToString(userInfo.getGroupPermissionLevels()));
3143 
3144  feMacroRunThreadStruct_.emplace_back( //runFEMacroStruct constructor
3145  xmldoc,
3146  feClassSelected,
3147  feUIDSelected,
3148  macroType,
3149  macroName,
3150  inputArgs,
3151  outputArgs,
3152  saveOutputs,
3153  userInfo.username_,
3154  StringMacros::mapToString(userInfo.getGroupPermissionLevels()));
3155 
3156  // Old single-threaded call:
3157  // runFEMacro(
3158  // xmldoc,
3159  // feClassSelected,
3160  // feUIDSelected,
3161  // macroType,
3162  // macroName,
3163  // inputArgs,
3164  // outputArgs,
3165  // saveOutputs,
3166  // userInfo.username_,
3167  // StringMacros::mapToString(userInfo.getGroupPermissionLevels()));
3168 
3169  std::thread t(
3170  [](runFEMacroStruct* s, MacroMakerSupervisor* mm) {
3171  MacroMakerSupervisor::runFEMacroThread(s, mm);
3172  },
3173  &feMacroRunThreadStruct_.back(),
3174  this);
3175 
3176  size_t sleepTime = 10 * 1000; //10ms
3177  usleep(sleepTime);
3178  //if not done in 5 seconds, track in "not-done" queue
3179  for(int i = 0; i < 6; ++i)
3180  {
3181  if(feMacroRunThreadStruct_.back().feMacroRunDone_)
3182  {
3183  __SUP_COUTT__ << "FE macro marked done" << __E__;
3184  break;
3185  }
3186  else
3187  {
3188  __SUP_COUTT__ << "FE macro not done, sleeping..." << __E__;
3189  sleepTime *= 5; //50ms, 250ms, 1s
3190  if(sleepTime > 1000 * 1000 /* seconds*/)
3191  sleepTime = 1000 * 1000; //max 1 sec
3192  usleep(sleepTime);
3193  }
3194  } //end wait loop
3195 
3196  if(!feMacroRunThreadStruct_.back().feMacroRunDone_) //macro not done...
3197  {
3198  if(t.get_id() == std::thread::id())
3199  {
3200  __SUP_SS__ << "Invalid thread ID. Contact system admins!" << __E__;
3201  __SUP_SS_THROW__;
3202  }
3203  feMacroRunThreadStruct_.back().parameters_.threadID_ =
3204  std::hash<std::thread::id>{}(t.get_id());
3205 
3206  if(feMacroRunThreadStruct_.back().parameters_.threadID_ == 0)
3207  {
3208  __SUP_SS__ << "Invalid thread ID hash. Contact system admins!" << __E__;
3209  __SUP_SS_THROW__;
3210  }
3211 
3212  __SUP_COUT__ << "FE macro not done, detaching thread="
3213  << feMacroRunThreadStruct_.back().parameters_.threadID_ << __E__;
3214  t.detach();
3215  xmldoc.addNumberElementToData(
3216  "NotDoneID", feMacroRunThreadStruct_.back().parameters_.threadID_);
3217 
3218  if(TTEST(1))
3219  {
3220  std::ostringstream oss;
3221  xmldoc.outputXmlDocument(
3222  &oss, false /* dispStdOut */, true /* allowWhiteSpace */);
3223  __SUP_COUTT__ << "xmldoc: " << oss.str() << __E__;
3224  }
3225  }
3226  else //macro done!
3227  {
3228  __SUP_COUTT__ << "FE macro marked done - joining threads." << __E__;
3229  t.join(); //make sure thread fully complete
3230  if(feMacroRunThreadStruct_.back().parameters_.feMacroRunError_ != "")
3231  {
3232  __SUP_SS__ << feMacroRunThreadStruct_.back().parameters_.feMacroRunError_;
3233  __SUP_SS_THROW__;
3234  }
3235  //copy result back to user
3236  if(TTEST(1))
3237  {
3238  std::ostringstream oss;
3239  feMacroRunThreadStruct_.back().parameters_.xmldoc_.outputXmlDocument(
3240  &oss, false /* dispStdOut */, true /* allowWhiteSpace */);
3241  __SUP_COUTT__ << "xmldoc: " << oss.str() << __E__;
3242  }
3243  xmldoc.copyDataChildren(feMacroRunThreadStruct_.back().parameters_.xmldoc_);
3244 
3245  if(TTEST(1))
3246  {
3247  std::ostringstream oss;
3248  xmldoc.outputXmlDocument(
3249  &oss, false /* dispStdOut */, true /* allowWhiteSpace */);
3250  __SUP_COUTT__ << "xmldoc: " << oss.str() << __E__;
3251  }
3252 
3253  feMacroRunThreadStruct_.pop_back(); //drop the completed struct
3254  __SUP_COUT__ << "FE macro complete." << __E__;
3255  }
3256  for(const auto& feMacroRunThreadStruct : feMacroRunThreadStruct_)
3257  __SUP_COUTT__ << "[] threadID_ = " << feMacroRunThreadStruct.parameters_.threadID_
3258  << __E__;
3259 
3260 } //end runFEMacro()
3261 catch(const std::runtime_error& e)
3262 {
3263  __SUP_SS__ << "Error processing FE communication request: " << e.what() << __E__;
3264  __SUP_COUT_ERR__ << ss.str();
3265  xmldoc.addTextElementToData("Error", ss.str());
3266 }
3267 catch(...)
3268 {
3269  __SUP_SS__ << "Unknown error processing FE communication request." << __E__;
3270  try
3271  {
3272  throw;
3273  } //one more try to printout extra info
3274  catch(const std::exception& e)
3275  {
3276  ss << "Exception message: " << e.what();
3277  }
3278  catch(...)
3279  {
3280  }
3281  __SUP_COUT_ERR__ << ss.str();
3282 
3283  xmldoc.addTextElementToData("Error", ss.str());
3284 } // end runFEMacro() catch
3285 
3286 //==============================================================================
3288 void MacroMakerSupervisor::runFEMacroThread(runFEMacroStruct* feMacroRunThreadStruct,
3289  MacroMakerSupervisor* mmSupervisor)
3290 try
3291 {
3292  __COUT__ << "runFEMacro thread started... threadid = " << std::this_thread::get_id()
3293  << " " << mmSupervisor << " getpid()=" << getpid()
3294  << " gettid()=" << gettid() << __E__;
3295 
3296  mmSupervisor->runFEMacro(feMacroRunThreadStruct->parameters_.xmldoc_,
3297  feMacroRunThreadStruct->parameters_.feClassSelected_,
3298  feMacroRunThreadStruct->parameters_.feUIDSelected_,
3299  feMacroRunThreadStruct->parameters_.macroType_,
3300  feMacroRunThreadStruct->parameters_.macroName_,
3301  feMacroRunThreadStruct->parameters_.inputArgs_,
3302  feMacroRunThreadStruct->parameters_.outputArgs_,
3303  feMacroRunThreadStruct->parameters_.saveOutputs_,
3304  feMacroRunThreadStruct->parameters_.runningUsername_,
3305  feMacroRunThreadStruct->parameters_.userGroupPermissions_);
3306 
3307  feMacroRunThreadStruct->parameters_.doneTime_ = time(0);
3308  feMacroRunThreadStruct->feMacroRunDone_ = true;
3309  __COUT__ << "runFEMacro thread done. threadid = " << std::this_thread::get_id()
3310  << __E__;
3311 
3312 } //end static runFEMacroThread()
3313 catch(const std::runtime_error& e)
3314 {
3315  __SS__ << "Error during runFEMacro thread: " << e.what() << __E__;
3316  __COUT_ERR__ << ss.str();
3317  feMacroRunThreadStruct->parameters_.feMacroRunError_ = ss.str();
3318  feMacroRunThreadStruct->parameters_.doneTime_ = time(0);
3319  feMacroRunThreadStruct->feMacroRunDone_ = true;
3320 }
3321 catch(...)
3322 {
3323  __SS__ << "Unknown error during runFEMacro thread." << __E__;
3324  try
3325  {
3326  throw;
3327  } //one more try to printout extra info
3328  catch(const std::exception& e)
3329  {
3330  ss << "Exception message: " << e.what();
3331  }
3332  catch(...)
3333  {
3334  }
3335  __COUT_ERR__ << ss.str();
3336  feMacroRunThreadStruct->parameters_.feMacroRunError_ = ss.str();
3337  feMacroRunThreadStruct->parameters_.doneTime_ = time(0);
3338  feMacroRunThreadStruct->feMacroRunDone_ = true;
3339 } // end static runFEMacroThread() catch
3340 
3341 //==============================================================================
3342 void MacroMakerSupervisor::runFEMacro(HttpXmlDocument& xmldoc,
3343  std::string feClassSelected,
3344  std::string feUIDSelected,
3345  const std::string& macroType,
3346  const std::string& macroName,
3347  const std::string& inputArgs,
3348  const std::string outputArgs,
3349  bool saveOutputs,
3350  const std::string& username,
3351  const std::string& userGroupPermissions)
3352 {
3353  __SUP_COUTV__(feClassSelected);
3354  __SUP_COUTV__(feUIDSelected);
3355  __SUP_COUTV__(macroType);
3356  __SUP_COUTV__(macroName);
3357  __SUP_COUTV__(inputArgs);
3358  __SUP_COUTV__(outputArgs);
3359  __SUP_COUTV__(saveOutputs);
3360  __SUP_COUTV__(username);
3361  __SUP_COUTV__(userGroupPermissions);
3362 
3363  appendCommandToHistory(feClassSelected,
3364  feUIDSelected,
3365  macroType,
3366  macroName,
3367  inputArgs,
3368  outputArgs,
3369  saveOutputs,
3370  username);
3371 
3372  std::set<std::string /*feUID*/> feUIDs;
3373 
3374  if(feUIDSelected == "")
3375  feUIDSelected = "*"; // treat empty as all
3376  if(feClassSelected == "")
3377  feClassSelected = "*"; // treat empty as all
3378 
3379  if(feClassSelected == "" || feUIDSelected == "" || macroType == "" || macroName == "")
3380  {
3381  __SUP_SS__ << "Illegal empty front-end parameter." << __E__;
3382  __SUP_SS_THROW__;
3383  }
3384  else if(feUIDSelected != "*")
3385  {
3386  StringMacros::getSetFromString(feUIDSelected, feUIDs);
3387  }
3388  else // * all case
3389  {
3390  // add all FEs for type
3391  if(feClassSelected == "*")
3392  {
3393  for(auto& feTypePair : FEPluginTypetoFEsMap_)
3394  for(auto& feUID : feTypePair.second)
3395  feUIDs.emplace(feUID);
3396  }
3397  else
3398  {
3399  auto typeIt = FEPluginTypetoFEsMap_.find(feClassSelected);
3400  if(typeIt == FEPluginTypetoFEsMap_.end())
3401  {
3402  __SUP_SS__ << "Illegal front-end type parameter '" << feClassSelected
3403  << "' not in list of types." << __E__;
3404  __SUP_SS_THROW__;
3405  }
3406 
3407  for(auto& feUID : typeIt->second)
3408  feUIDs.emplace(feUID);
3409  }
3410  }
3411 
3412  __SUP_COUTV__(StringMacros::setToString(feUIDs));
3413 
3414  std::string macroString;
3415  if(macroType == "public")
3416  loadMacro(macroName, macroString);
3417  else if(macroType == "private")
3418  loadMacro(macroName, macroString, username);
3419 
3420  __SUP_COUTV__(macroString);
3421 
3422  FILE* fp = 0;
3423  try
3424  {
3425  if(saveOutputs)
3426  {
3427  std::string filename = "/macroOutput_" + std::to_string(time(0)) + "_" +
3428  std::to_string(clock()) + ".txt";
3429 
3430  __SUP_COUTV__(filename);
3431  fp = fopen((CodeEditor::OTSDAQ_DATA_PATH + filename).c_str(), "w");
3432  if(!fp)
3433  {
3434  __SUP_SS__ << "Failed to open file to save macro output '"
3435  << CodeEditor::OTSDAQ_DATA_PATH << filename << "'..." << __E__;
3436  __SUP_SS_THROW__;
3437  }
3438 
3439  fprintf(fp, "############################\n");
3440  fprintf(fp,
3441  "### Running '%s' at time %s\n",
3442  macroName.c_str(),
3444  fprintf(fp,
3445  "### \t Target front-ends (count=%lu): %s\n",
3446  feUIDs.size(),
3447  StringMacros::setToString(feUIDs).c_str());
3448  fprintf(fp, "### \t\t Inputs: %s\n", inputArgs.c_str());
3449  fprintf(fp, "############################\n\n\n");
3450 
3451  xmldoc.addTextElementToData("feMacroRunArgs_name", "Filename");
3452  xmldoc.addTextElementToData("feMacroRunArgs_value",
3453  "$OTSDAQ_DATA/" + filename);
3454  }
3455 
3456  // do for all target front-ends
3457  for(auto& feUID : feUIDs)
3458  {
3459  auto feIt = FEtoSupervisorMap_.find(feUID);
3460  if(feIt == FEtoSupervisorMap_.end())
3461  {
3462  __SUP_SS__ << "Destination front end interface ID '" << feUID
3463  << "' was not found in the list of front ends." << __E__;
3464  ss << "\n\nHere is the map:\n\n"
3465  << StringMacros::mapToString(FEtoSupervisorMap_) << __E__;
3466  __SUP_SS_THROW__;
3467  }
3468 
3469  unsigned int FESupervisorIndex = feIt->second;
3470  __SUP_COUT__ << "Found supervisor index: " << FESupervisorIndex << __E__;
3471 
3472  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
3473  if(it == allFESupervisorInfo_.end())
3474  {
3475  __SUP_SS__
3476  << "Error transmitting request to FE Supervisor '" << feUID << ":"
3477  << FESupervisorIndex << ".' \n\n"
3478  << "The FE Supervisor Index does not exist. Have you configured "
3479  "the state machine properly?"
3480  << __E__;
3481  __SUP_SS_THROW__;
3482  }
3483 
3484  // send command to chosen FE and await response
3485  SOAPParameters txParameters; // params for xoap to send
3486  if(macroType == "fe")
3487  txParameters.addParameter("Request", "RunInterfaceMacro");
3488  else
3489  txParameters.addParameter("Request", "RunMacroMakerMacro");
3490  txParameters.addParameter("InterfaceID", feUID);
3491  if(macroType == "fe")
3492  txParameters.addParameter("feMacroName", macroName);
3493  else
3494  {
3495  txParameters.addParameter("macroName", macroName);
3496  txParameters.addParameter("macroString", macroString);
3497  }
3498  txParameters.addParameter("inputArgs", inputArgs);
3499  txParameters.addParameter("outputArgs", outputArgs);
3500  txParameters.addParameter("userPermissions", userGroupPermissions);
3501 
3502  SOAPParameters rxParameters; // params for xoap to recv
3503  // rxParameters.addParameter("success");
3504  rxParameters.addParameter("outputArgs");
3505  rxParameters.addParameter("Error");
3506 
3507  if(saveOutputs)
3508  {
3509  fprintf(fp,
3510  "Running '%s' at time %s\n",
3511  macroName.c_str(),
3513  fprintf(fp,
3514  "\t Target front-end: '%s::%s'\n",
3515  FEtoPluginTypeMap_[feUID].c_str(),
3516  feUID.c_str());
3517  fprintf(fp,
3518  "\t\t Inputs: %s\n",
3519  StringMacros::decodeURIComponent(inputArgs).c_str());
3520  }
3521 
3522  // have FE supervisor descriptor, so send
3523  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
3524  it->second.getDescriptor(), // supervisor descriptor
3525  "MacroMakerSupervisorRequest",
3526  txParameters);
3527 
3528  __SUP_COUT__ << "Received response message: "
3529  << SOAPUtilities::translate(retMsg) << __E__;
3530 
3531  SOAPUtilities::receive(retMsg, rxParameters);
3532 
3533  __SUP_COUT__ << "Received it " << __E__;
3534 
3535  // bool success = rxParameters.getValue("success") == "1";
3536  std::string outputResults = rxParameters.getValue("outputArgs");
3537  std::string error = rxParameters.getValue("Error");
3538 
3539  //__SUP_COUT__ << "rx success = " << success << __E__;
3540  __SUP_COUT__ << "outputArgs = " << outputResults << __E__;
3541 
3542  if(error != "")
3543  {
3544  __SS__ << "Attempted FE Macro Failed. Attempted target "
3545  << "was UID=" << feUID
3546  << " at feSupervisorID=" << FESupervisorIndex << "." << __E__;
3547  ss << "\n\n The error was:\n\n" << error << __E__;
3548  __SUP_COUT_ERR__ << "\n" << ss.str();
3549  xmldoc.addTextElementToData("Error", ss.str());
3550  return;
3551  }
3552 
3553  // build output arguments
3554  // parse args, colon-separated pairs, and then comma-separated
3555  {
3556  DOMElement* feMacroExecParent =
3557  xmldoc.addTextElementToData("feMacroExec", macroName);
3558 
3559  xmldoc.addTextElementToParent(
3560  "exec_time", StringMacros::getTimestampString(), feMacroExecParent);
3561  xmldoc.addTextElementToParent("fe_uid", feUID, feMacroExecParent);
3562  xmldoc.addTextElementToParent(
3563  "fe_type", FEtoPluginTypeMap_[feUID], feMacroExecParent);
3564  xmldoc.addTextElementToParent(
3565  "fe_context", it->second.getContextName(), feMacroExecParent);
3566  xmldoc.addTextElementToParent(
3567  "fe_supervisor", it->second.getName(), feMacroExecParent);
3568  xmldoc.addTextElementToParent(
3569  "fe_hostname", it->second.getHostname(), feMacroExecParent);
3570 
3571  std::istringstream inputStream(outputResults);
3572  std::string splitVal, argName, argValue;
3573  while(getline(inputStream, splitVal, ';'))
3574  {
3575  std::istringstream pairInputStream(splitVal);
3576  getline(pairInputStream, argName, ',');
3577  getline(pairInputStream, argValue, ',');
3578 
3579  if(saveOutputs)
3580  {
3581  fprintf(fp,
3582  "\t\t Output '%s' = %s\n",
3583  argName.c_str(),
3584  StringMacros::decodeURIComponent(argValue).c_str());
3585  }
3586  else
3587  {
3588  xmldoc.addTextElementToParent(
3589  "outputArgs_name", argName, feMacroExecParent);
3590  xmldoc.addTextElementToParent(
3591  "outputArgs_value", argValue, feMacroExecParent);
3592  }
3593  __SUP_COUT__ << argName << ": " << argValue << __E__;
3594  }
3595  }
3596  } // end target front-end loop
3597  }
3598  catch(...) // handle file close on error
3599  {
3600  if(fp)
3601  fclose(fp);
3602  throw;
3603  }
3604 
3605  if(fp)
3606  fclose(fp);
3607 
3608 } // end runFEMacro()
3609 
3610 //==============================================================================
3611 void MacroMakerSupervisor::getFEMacroList(HttpXmlDocument& xmldoc,
3612  const std::string& username)
3613 {
3614  __SUP_COUT__ << "Getting FE Macro list" << __E__;
3615 
3616  SOAPParameters txParameters; // params for xoap to send
3617  txParameters.addParameter("Request", "GetInterfaceMacros");
3618 
3619  SOAPParameters rxParameters; // params for xoap to recv
3620  rxParameters.addParameter("FEMacros");
3621 
3622  std::string oneInterface;
3623  std::string rxFEMacros;
3624 
3625  // for each list of FE Supervisors,
3626  // get all FE specific macros
3627  for(auto& appInfo : allFESupervisorInfo_)
3628  {
3629  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId()
3630  << " name = " << appInfo.second.getName() << __E__;
3631 
3632  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
3633  appInfo.second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
3634  SOAPUtilities::receive(retMsg, rxParameters);
3635 
3636  rxFEMacros = rxParameters.getValue("FEMacros");
3637 
3638  __SUP_COUT__ << "FE Macros received: \n" << rxFEMacros << __E__;
3639 
3640  std::istringstream allInterfaces(rxFEMacros);
3641  while(std::getline(allInterfaces, oneInterface))
3642  {
3643  //__SUP_COUT__ << oneInterface << __E__;
3644  //__SUP_COUT__ << appInfo.second.getId() << __E__;
3645  xmldoc.addTextElementToData("FEMacros", oneInterface);
3646  // xmldoc.outputXmlDocument(0,true);
3647  }
3648  }
3649 
3650  // add macros to response
3651  std::pair<std::vector<std::string> /*public macros*/,
3652  std::vector<std::string> /*private macros*/>
3653  macroNames;
3654  loadMacroNames(username, macroNames);
3655 
3656  __SUP_COUT__ << "Public macro count: " << macroNames.first.size() << __E__;
3657  __SUP_COUT__ << "Private macro count: " << macroNames.second.size() << __E__;
3658 
3659  std::string macroString;
3660  // make xml ':' separated fields:
3661  // macro name
3662  // permissions string
3663  // number of inputs
3664  // inputs separated by :
3665  // number of outputs
3666  // outputs separated by :
3667 
3668  for(int i = 0; i < 2; ++i) // first is public, then private
3669  for(auto& macroName : (i ? macroNames.second : macroNames.first))
3670  {
3671  // get macro string
3672  loadMacro(macroName, macroString, username);
3673 
3674  // extract macro object
3675  FEVInterface::macroStruct_t macro(macroString);
3676 
3677  std::stringstream xmlMacroStream;
3678  xmlMacroStream << macro.macroName_;
3679  xmlMacroStream << ":"
3680  << "1"; // permissions string
3681  xmlMacroStream << ":" << macro.namesOfInputArguments_.size();
3682  for(auto& inputArg : macro.namesOfInputArguments_)
3683  xmlMacroStream << ":" << inputArg;
3684  xmlMacroStream << ":" << macro.namesOfOutputArguments_.size();
3685  for(auto& inputArg : macro.namesOfOutputArguments_)
3686  xmlMacroStream << ":" << inputArg;
3687 
3688  xmldoc.addTextElementToData(i ? "PrivateMacro" : "PublicMacro",
3689  xmlMacroStream.str());
3690  }
3691 } //end getFEMacroList()
static std::string postData(cgicc::Cgicc &cgi, const std::string &needle)
static std::string getOrPostData(cgicc::Cgicc &cgi, const std::string &needle)
static std::string getData(cgicc::Cgicc &cgi, const std::string &needle)
void loadTableGroup(const std::string &tableGroupName, const TableGroupKey &tableGroupKey, bool doActivate=false, std::map< std::string, TableVersion > *groupMembers=0, ProgressBar *progressBar=0, std::string *accumulateWarnings=0, std::string *groupComment=0, std::string *groupAuthor=0, std::string *groupCreateTime=0, bool doNotLoadMember=false, std::string *groupTypeString=0, std::map< std::string, std::string > *groupAliases=0, ConfigurationManager::LoadGroupType groupTypeToLoad=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false)
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
void getRequestUserInfo(WebUsers::RequestUserInfo &requestUserInfo)
friend friend class MacroMakerSupervisor
virtual void nonXmlRequest(const std::string &requestType, cgicc::Cgicc &cgiIn, std::ostream &out, const WebUsers::RequestUserInfo &userInfo)
void copyDataChildren(HttpXmlDocument &document)
std::string getMatchingValue(const std::string &field, const unsigned int occurance=0)
void outputXmlDocument(std::ostringstream *out, bool dispStdOut=false, bool allowWhiteSpace=false, bool printErrors=false)
virtual void forceSupervisorPropertyValues(void) override
override to force supervisor property values (and ignore user settings)
void addParameter(const std::string name, const std::string value)
static void tooltipSetNeverShowForUsername(const std::string &username, HttpXmlDocument *xmldoc, const std::string &srcFile, const std::string &srcFunc, const std::string &srcId, bool doNeverShow, bool temporarySilence)
static void tooltipCheckForUsername(const std::string &username, HttpXmlDocument *xmldoc, const std::string &srcFile, const std::string &srcFunc, const std::string &srcId)
xercesc::DOMElement * addTextElementToParent(const std::string &childName, const std::string &childText, xercesc::DOMElement *parent)
void INIT_MF(const char *name)
static std::string getTimestampString(const std::string &linuxTimeInSeconds)
static void getVectorFromString(const std::string &inputString, std::vector< std::string > &listToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'}, std::vector< char > *listOfDelimiters=0, bool decodeURIComponents=false)
static void getSetFromString(const std::string &inputString, std::set< std::string > &setToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'})
static std::string setToString(const std::set< T > &setToReturn, const std::string &delimeter=", ")
static std::string vectorToString(const std::vector< T > &setToReturn, const std::string &delimeter=", ")
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")
static std::string decodeURIComponent(const std::string &data)