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  getFElist(xmldoc);
844  else if(Command == "writeData") // called by MacroMaker GUI
845  writeData(xmldoc, cgi, userInfo.username_);
846  else if(Command == "readData") // called by MacroMaker GUI
847  readData(xmldoc, cgi, userInfo.username_);
848  else if(Command == "createMacro") // called by MacroMaker GUI
849  createMacro(xmldoc, cgi, userInfo.username_);
850  else if(Command == "loadMacros") // called by MacroMaker GUI
851  loadMacros(xmldoc, userInfo.username_);
852  else if(Command == "loadHistory") // called by MacroMaker GUI
853  loadHistory(xmldoc, userInfo.username_);
854  else if(Command == "deleteMacro") // called by MacroMaker GUI
855  deleteMacro(xmldoc, cgi, userInfo.username_);
856  else if(Command == "editMacro") // called by MacroMaker GUI
857  editMacro(xmldoc, cgi, userInfo.username_);
858  else if(Command == "clearHistory") // called by MacroMaker GUI
859  clearHistory(userInfo.username_);
860  else if(Command == "exportMacro") // called by MacroMaker GUI
861  exportMacro(xmldoc, cgi, userInfo.username_);
862  else if(Command == "exportFEMacro") // called by MacroMaker GUI
863  exportFEMacro(xmldoc, cgi, userInfo.username_);
864  else if(Command == "getFEMacroList") // called by FE Macro Test and returns FE Macros
865  // and Macro Maker Macros
866  {
867  std::string macroPath = (std::string)MACROS_DB_PATH + userInfo.username_ + "/";
868  mkdir(macroPath.c_str(), 0755);
869  std::string histPath = (std::string)MACROS_HIST_PATH + userInfo.username_ + "/";
870  mkdir(histPath.c_str(), 0755);
871 
872  getFEMacroList(xmldoc, userInfo.username_);
873  }
874  else if(Command == "runFEMacro") // called by FE Macro Test returns FE Macros and
875  // Macro Maker Macros
876  runFEMacro(xmldoc, cgi, userInfo);
877  else if(Command == "loadFEHistory") // called by FE Macro Test and returns FE Macros
878  // and Macro Maker Macros
879  loadFEHistory(xmldoc, userInfo.username_);
880  else if(Command == "clearFEHistory") // called by FE Macro Test returns FE Macros and
881  // Macro Maker Macros
882  clearFEHistory(userInfo.username_);
883  else if(Command == "loadFEMacroSequences")
884  loadFEMacroSequences(xmldoc, userInfo.username_);
885  else if(Command == "saveFEMacroSequence")
886  saveFEMacroSequence(cgi, userInfo.username_);
887  else if(Command == "getFEMacroSequence")
888  getFEMacroSequence(xmldoc, cgi, userInfo.username_);
889  else if(Command == "deleteFEMacroSequence")
890  deleteFEMacroSequence(cgi, userInfo.username_);
891  else if(Command == "makeSequencePublic")
892  makeSequencePublic(cgi, userInfo.username_);
893  else
894  xmldoc.addTextElementToData("Error", "Unrecognized command '" + Command + "'");
895 } // end handleRequest()
896 
897 //==============================================================================
898 xoap::MessageReference MacroMakerSupervisor::frontEndCommunicationRequest(
899  xoap::MessageReference message)
900 try
901 {
902  __COUTT__; //mark for debugging
903  __SUP_COUT__ << "FE Request received: " << SOAPUtilities::translate(message) << __E__;
904 
905  SOAPParameters typeParameter, rxParameters; // params for xoap to recv
906  typeParameter.addParameter("type");
907  SOAPUtilities::receive(message, typeParameter);
908 
909  std::string type = typeParameter.getValue("type");
910 
911  std::string error = "";
912 
913  if(type == "initFElist") // gateway initializes during configure
914  {
915  __SUP_COUTV__(type);
916 
917  rxParameters.addParameter("groupName");
918  rxParameters.addParameter("groupKey");
919  SOAPUtilities::receive(message, rxParameters);
920 
921  std::string groupName = rxParameters.getValue("groupName");
922  std::string groupKey = rxParameters.getValue("groupKey");
923 
924  __SUP_COUTV__(groupName);
925  __SUP_COUTV__(groupKey);
926 
927  ConfigurationManager cfgMgr;
928  cfgMgr.loadTableGroup(groupName, TableGroupKey(groupKey), true);
929 
930  // for each FESupervisor
931  // get all front end children
932 
933  const SupervisorInfoMap& feTypeSupervisors =
934  CorePropertySupervisorBase::allSupervisorInfo_.getAllFETypeSupervisorInfo();
935 
936  ConfigurationTree appsNode =
937  cfgMgr.getNode(ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME);
938 
939  __SUP_COUT__ << "Number of FE Supervisors found = " << feTypeSupervisors.size()
940  << __E__;
941 
942  FEPluginTypetoFEsMap_.clear(); // reset
943  FEtoSupervisorMap_.clear(); // reset
944  FEtoPluginTypeMap_.clear(); // reset
945  for(auto& feApp : feTypeSupervisors)
946  {
947  __SUP_COUT__ << "FEs for app " << feApp.first << ":" << feApp.second.getName()
948  << __E__;
949 
950  auto feChildren = appsNode.getNode(feApp.second.getName())
951  .getNode("LinkToSupervisorTable")
952  .getNode("LinkToFEInterfaceTable")
953  .getChildren();
954 
955  for(auto& fe : feChildren)
956  {
957  if(!fe.second.status())
958  continue; // skip disabled FEs
959 
960  __SUP_COUTV__(fe.first);
961  FEtoSupervisorMap_[fe.first] = feApp.first;
962 
963  std::string pluginType =
964  fe.second.getNode("FEInterfacePluginName").getValue();
965  FEPluginTypetoFEsMap_[pluginType].emplace(fe.first);
966  FEtoPluginTypeMap_[fe.first] = pluginType;
967  }
968  }
969 
970  __SUP_COUTV__(StringMacros::mapToString(FEtoSupervisorMap_));
971  __SUP_COUTV__(StringMacros::mapToString(FEPluginTypetoFEsMap_));
972  __SUP_COUTV__(StringMacros::mapToString(FEtoPluginTypeMap_));
973  }
974  else if(type == "feSend" || // from front-ends
975  type == "feMacro" || // from front-ends
976  type == "feMacroMultiDimensionalStart" || // from iterator
977  type == "feMacroMultiDimensionalCheck" || // from iterator
978  type == "macroMultiDimensionalStart" || // from iterator
979  type == "macroMultiDimensionalCheck") // from iterator
980  {
981  __SUP_COUTV__(type);
982 
983  rxParameters.addParameter("targetInterfaceID");
984  SOAPUtilities::receive(message, rxParameters);
985 
986  std::string targetInterfaceID = rxParameters.getValue("targetInterfaceID");
987 
988  __SUP_COUTV__(targetInterfaceID);
989 
990  auto feIt = FEtoSupervisorMap_.find(targetInterfaceID);
991  if(feIt == FEtoSupervisorMap_.end())
992  {
993  __SUP_SS__ << "Destination front end interface ID '" << targetInterfaceID
994  << "' was not found in the list of front ends." << __E__;
995  __SUP_SS_THROW__;
996  }
997 
998  unsigned int FESupervisorIndex = feIt->second;
999  __SUP_COUT__ << "Found supervisor index: " << FESupervisorIndex << __E__;
1000 
1001  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
1002  if(it == allFESupervisorInfo_.end())
1003  {
1004  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1005  << targetInterfaceID << ":" << FESupervisorIndex << ".' \n\n"
1006  << "The FE Supervisor Index does not exist. Have you configured "
1007  "the state machine properly?"
1008  << __E__;
1009  __SUP_SS_THROW__;
1010  }
1011 
1012  if(type == "macroMultiDimensionalStart")
1013  {
1014  // add Macro sequence (and check macro exists)
1015 
1016  SOAPParameters rxParameters;
1017  rxParameters.addParameter("macroName");
1018  SOAPUtilities::receive(message, rxParameters);
1019  std::string macroName = rxParameters.getValue("macroName");
1020  __SUP_COUTV__(macroName);
1021 
1022  std::string macroString;
1023  loadMacro(macroName, macroString);
1024 
1025  SOAPParameters parameters;
1026  parameters.addParameter("macroString", macroString);
1027  SOAPUtilities::addParameters(message, parameters);
1028  }
1029 
1030  try
1031  {
1032  __SUP_COUT__ << "Forwarding request: " << SOAPUtilities::translate(message)
1033  << __E__;
1034 
1035  xoap::MessageReference replyMessage =
1036  SOAPMessenger::sendWithSOAPReply(it->second.getDescriptor(), message);
1037 
1038  if(type != "feSend")
1039  {
1040  __SUP_COUT__ << "Forwarding FE Macro response: "
1041  << SOAPUtilities::translate(replyMessage) << __E__;
1042 
1043  return replyMessage;
1044  }
1045  }
1046  catch(const xdaq::exception::Exception& e)
1047  {
1048  __SUP_SS__ << "Error forwarding FE Communication request to FE Supervisor '"
1049  << targetInterfaceID << ":" << FESupervisorIndex << ".' "
1050  << "Have you configured the state machine properly?\n\n"
1051  << e.what() << __E__;
1052  __SUP_SS_THROW__;
1053  }
1054  }
1055  else
1056  {
1057  __SUP_SS__ << "Unrecognized FE Communication type: " << type << __E__;
1058  __SUP_SS_THROW__;
1059  }
1060 
1061  return SOAPUtilities::makeSOAPMessageReference("Received");
1062 } // end frontEndCommunicationRequest()
1063 catch(const std::runtime_error& e)
1064 {
1065  __SUP_SS__ << "Error processing FE communication request: " << e.what() << __E__;
1066  __SUP_COUT_ERR__ << ss.str();
1067 
1068  xoap::MessageReference returnMessage =
1069  SOAPUtilities::makeSOAPMessageReference("Error");
1070 
1071  SOAPParameters parameters;
1072  parameters.addParameter("Error", ss.str());
1073  SOAPUtilities::addParameters(returnMessage, parameters);
1074  return returnMessage;
1075 }
1076 catch(...)
1077 {
1078  xoap::MessageReference returnMessage =
1079  SOAPUtilities::makeSOAPMessageReference("Error");
1080 
1081  __SUP_SS__ << "Unknown error processing FE communication request." << __E__;
1082  try
1083  {
1084  throw;
1085  } //one more try to printout extra info
1086  catch(const std::exception& e)
1087  {
1088  ss << "Exception message: " << e.what();
1089  }
1090  catch(...)
1091  {
1092  }
1093  __SUP_COUT_ERR__ << ss.str();
1094 
1095  SOAPParameters parameters;
1096  parameters.addParameter("Error", ss.str());
1097  SOAPUtilities::addParameters(returnMessage, parameters);
1098  return returnMessage;
1099 } // end frontEndCommunicationRequest() catch
1100 
1101 //==============================================================================
1102 void MacroMakerSupervisor::getFElist(HttpXmlDocument& xmldoc)
1103 {
1104  __SUP_COUT__ << "Getting FE list!!!!!!!!!" << __E__;
1105 
1106  SOAPParameters txParameters; // params for xoap to send
1107  txParameters.addParameter("Request", "GetInterfaces");
1108 
1109  SOAPParameters rxParameters; // params for xoap to recv
1110  rxParameters.addParameter("Command");
1111  rxParameters.addParameter("FEList");
1112  rxParameters.addParameter("frontEndError"); // if there were errors recorded (during
1113  // configuration, e.g. in Macro Maker
1114  // only mode)
1115 
1116  SupervisorInfoMap::const_iterator it;
1117  std::string oneInterface;
1118  std::string rxFEList;
1119  std::string rxFrontEndError;
1120 
1121  size_t lastColonIndex;
1122 
1123  // for each list of FE Supervisors,
1124  // loop through each FE Supervisors and get FE interfaces list
1125  for(auto& appInfo : allFESupervisorInfo_)
1126  {
1127  // __SUP_COUT__ << "Number of " << listPair.first << " = " <<
1128  // listPair.second.size() << __E__;
1129  //
1130  // for (it = listPair.second.begin(); it != listPair.second.end(); it++)
1131  // {
1132 
1133  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId()
1134  << " name = " << appInfo.second.getName() << __E__;
1135 
1136  try
1137  {
1138  xoap::MessageReference retMsg =
1139  SOAPMessenger::sendWithSOAPReply(appInfo.second.getDescriptor(),
1140  "MacroMakerSupervisorRequest",
1141  txParameters);
1142  SOAPUtilities::receive(retMsg, rxParameters);
1143 
1144  __SUP_COUT__ << "Received MacroMaker response: "
1145  << SOAPUtilities::translate(retMsg).getCommand() << "==>"
1146  << SOAPUtilities::translate(retMsg) << __E__;
1147 
1148  if(SOAPUtilities::translate(retMsg).getCommand() == "Fault")
1149  {
1150  __SUP_SS__ << "Unrecognized command received!" << __E__;
1151  __SUP_SS_THROW__;
1152  }
1153  }
1154  catch(const xdaq::exception::Exception& e)
1155  {
1156  __SUP_SS__ << "Error transmitting request to FE Supervisor LID = "
1157  << appInfo.second.getId() << " name = " << appInfo.second.getName()
1158  << ". \n\n"
1159  << e.what() << __E__;
1160  __SUP_SS_THROW__;
1161  }
1162 
1163  rxFEList = rxParameters.getValue("FEList");
1164  rxFrontEndError = rxParameters.getValue("frontEndError");
1165 
1166  __SUP_COUT__ << "FE List received: \n" << rxFEList << __E__;
1167 
1168  if(rxFrontEndError != "")
1169  {
1170  __SUP_SS__ << "FE Errors received: \n" << rxFrontEndError << __E__;
1171  __SUP_SS_THROW__;
1172  }
1173 
1174  std::istringstream allInterfaces(rxFEList);
1175  while(std::getline(allInterfaces, oneInterface))
1176  {
1177  __SUP_COUTV__(oneInterface);
1178  xmldoc.addTextElementToData("FE", oneInterface);
1179 
1180  lastColonIndex = oneInterface.rfind(':');
1181  if(lastColonIndex == std::string::npos)
1182  {
1183  __SUP_SS__ << "Last colon could not be found in " << oneInterface
1184  << __E__;
1185  __SUP_SS_THROW__;
1186  }
1187  oneInterface = oneInterface.substr(lastColonIndex);
1188 
1189  __SUP_COUTV__(oneInterface);
1190  } // end FE extract loop
1191 
1192  } // end ask Supervisors for their FE list loop
1193 
1194 } // end getFEList()
1195 
1196 //==============================================================================
1197 void MacroMakerSupervisor::writeData(HttpXmlDocument& /*xmldoc*/,
1198  cgicc::Cgicc& cgi,
1199  const std::string& username)
1200 {
1201  __SUP_COUT__ << "MacroMaker writing..." << __E__;
1202 
1203  std::string Address = CgiDataUtilities::getData(cgi, "Address");
1204  std::string Data = CgiDataUtilities::getData(cgi, "Data");
1205  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
1206  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
1207  std::string time =
1209  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
1210  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
1211 
1212  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
1213 
1214  __SUP_COUT__ << "Write Address: " << Address << " Data: " << Data << __E__;
1215  __SUP_COUTV__(interfaces);
1216 
1217  std::string command = "w:" + Address + ":" + Data;
1218  std::string format = addressFormatStr + ":" + dataFormatStr;
1219  appendCommandToHistory(command, format, time, interfaces, username);
1220 
1221  SOAPParameters txParameters; // params for xoap to send
1222  txParameters.addParameter("Request", "UniversalWrite");
1223  txParameters.addParameter("Address", Address);
1224  txParameters.addParameter("Data", Data);
1225 
1226  __SUP_COUT__ << "Here comes the array from multiselect box for WRITE, behold: \n"
1227  << supervisorIndexArray << "\n"
1228  << interfaceIndexArray << __E__;
1229 
1232  std::vector<std::string> interfaceIndices;
1233  std::istringstream f(interfaceIndexArray);
1234  std::string s;
1235  while(getline(f, s, ','))
1236  interfaceIndices.push_back(s);
1237  std::vector<int> supervisorIndices;
1238  std::istringstream g(supervisorIndexArray);
1239  std::string t;
1240  while(getline(g, t, ','))
1241  supervisorIndices.push_back(std::stoi(t));
1242 
1243  for(unsigned int i = 0; i < supervisorIndices.size(); i++)
1244  {
1245  unsigned int FESupervisorIndex = supervisorIndices[i];
1246  std::string interfaceIndex = interfaceIndices[i];
1247 
1248  txParameters.addParameter("InterfaceID", interfaceIndex);
1249 
1250  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex
1251  << __E__;
1252  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
1253 
1254  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
1255  if(it == allFESupervisorInfo_.end())
1256  {
1257  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1258  << interfaceIndex << ":" << FESupervisorIndex << ".' \n\n"
1259  << "The FE Index doesn't exist. Have you configured the state "
1260  "machine properly?"
1261  << __E__;
1262  __SUP_SS_THROW__;
1263  }
1264 
1265  try
1266  {
1267  xoap::MessageReference replyMessage = SOAPMessenger::sendWithSOAPReply(
1268  it->second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
1269 
1270  __SUP_COUT__ << "Response received: "
1271  << SOAPUtilities::translate(replyMessage) << __E__;
1272 
1273  SOAPParameters rxParameters;
1274  rxParameters.addParameter("Error");
1275  SOAPUtilities::receive(replyMessage, rxParameters);
1276 
1277  std::string error = rxParameters.getValue("Error");
1278  __SUP_COUTV__(error);
1279 
1280  if(error != "")
1281  {
1282  // error occurred!
1283  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1284  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1285  << "Have you configured the state machine properly?\n\n"
1286  << error << __E__;
1287  __SUP_SS_THROW__;
1288  }
1289  }
1290  catch(const xdaq::exception::Exception& e)
1291  {
1292  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1293  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1294  << "Have you configured the state machine properly?\n\n"
1295  << e.what() << __E__;
1296  __SUP_SS_THROW__;
1297  }
1298 
1299  } // end FE Supervisor loop
1300 } // end writeData()
1301 
1302 //==============================================================================
1303 void MacroMakerSupervisor::readData(HttpXmlDocument& xmldoc,
1304  cgicc::Cgicc& cgi,
1305  const std::string& username)
1306 {
1307  __SUP_COUT__ << "@@@@@@@ MacroMaker wants to read data @@@@@@@@" << __E__;
1308  std::string Address = CgiDataUtilities::getData(cgi, "Address");
1309  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
1310  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
1311  std::string time =
1313  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
1314  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
1315 
1316  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
1317 
1318  __SUP_COUT__ << "Read Address: " << Address << __E__;
1319  __SUP_COUTV__(interfaces);
1320 
1321  SOAPParameters txParameters; // params for xoap to send
1322  txParameters.addParameter("Request", "UniversalRead");
1323  txParameters.addParameter("Address", Address);
1324 
1325  SOAPParameters rxParameters;
1326  rxParameters.addParameter("dataResult");
1327  rxParameters.addParameter("Error");
1328  __SUP_COUT__ << "Here comes the array from multiselect box for READ, behold: "
1329  << supervisorIndexArray << "," << interfaceIndexArray << __E__;
1330 
1333  std::vector<std::string> interfaceIndices;
1334  std::istringstream f(interfaceIndexArray);
1335  std::string s;
1336  while(getline(f, s, ','))
1337  interfaceIndices.push_back(s);
1338  std::vector<int> supervisorIndices;
1339  std::istringstream g(supervisorIndexArray);
1340  std::string t;
1341  while(getline(g, t, ','))
1342  supervisorIndices.push_back(std::stoi(t));
1343 
1344  for(unsigned int i = 0; i < supervisorIndices.size(); i++)
1345  {
1346  unsigned int FESupervisorIndex = supervisorIndices[i];
1347  std::string interfaceIndex = interfaceIndices[i];
1348 
1349  txParameters.addParameter("InterfaceID", interfaceIndex);
1350 
1351  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex
1352  << __E__;
1353  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
1354 
1355  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
1356  if(it == allFESupervisorInfo_.end())
1357  {
1358  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1359  << interfaceIndex << ":" << FESupervisorIndex << ".' \n\n"
1360  << "The FE Index doesn't exist. Have you configured the state "
1361  "machine properly?"
1362  << __E__;
1363  __SUP_SS_THROW__;
1364  }
1365 
1366  try
1367  {
1368  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
1369  it->second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
1370 
1371  __SUP_COUT__ << "Response received: " << SOAPUtilities::translate(retMsg)
1372  << __E__;
1373 
1374  // SOAPParameters rxParameters;
1375  // rxParameters.addParameter("Error");
1376  SOAPUtilities::receive(retMsg, rxParameters);
1377 
1378  std::string error = rxParameters.getValue("Error");
1379  __SUP_COUTV__(error);
1380 
1381  if(error != "")
1382  {
1383  // error occurred!
1384  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1385  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1386  << "Have you configured the state machine properly?\n\n"
1387  << error << __E__;
1388  __SUP_SS_THROW__;
1389  }
1390  }
1391  catch(const xdaq::exception::Exception& e)
1392  {
1393  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1394  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1395  << "Have you configured the state machine properly?\n\n"
1396  << e.what() << __E__;
1397  __SUP_SS_THROW__;
1398  }
1399 
1400  std::string dataReadResult = rxParameters.getValue("dataResult");
1401  __SUP_COUT__ << "Data reading result received: " << dataReadResult << __E__;
1402  xmldoc.addTextElementToData("readData", dataReadResult);
1403  std::string command = "r:" + Address + ":" + dataReadResult;
1404  std::string format = addressFormatStr + ":" + dataFormatStr;
1405  appendCommandToHistory(command, format, time, interfaces, username);
1406  }
1407 }
1408 
1409 //==============================================================================
1410 void MacroMakerSupervisor::createMacro(HttpXmlDocument& /*xmldoc*/,
1411  cgicc::Cgicc& cgi,
1412  const std::string& username)
1413 {
1414  __SUP_COUT__ << "MacroMaker wants to create a macro!!!!!!!!!" << __E__;
1415  std::string Name = CgiDataUtilities::postData(cgi, "Name");
1416  std::string Sequence = CgiDataUtilities::postData(cgi, "Sequence");
1417  std::string Time = CgiDataUtilities::postData(cgi, "Time");
1418  std::string Notes =
1420  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
1421  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
1422 
1423  __SUP_COUTV__(Name);
1424  __SUP_COUTV__(Sequence);
1425  __SUP_COUTV__(Notes);
1426  __SUP_COUTV__(Time);
1427  __SUP_COUTV__(isMacroPublic);
1428  __SUP_COUTV__(isMacroLSBF);
1429 
1430  __SUP_COUTV__(MACROS_DB_PATH);
1431 
1432  std::string fileName = Name + ".dat";
1433  std::string fullPath;
1434  if(isMacroPublic == "true")
1435  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
1436  else
1437  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
1438 
1439  __SUP_COUTV__(fullPath);
1440 
1441  std::ofstream macrofile(fullPath.c_str());
1442  if(macrofile.is_open())
1443  {
1444  macrofile << "{\n";
1445  macrofile << "\"name\":\"" << Name << "\",\n";
1446  macrofile << "\"sequence\":\"" << Sequence << "\",\n";
1447  macrofile << "\"time\":\"" << Time << "\",\n";
1448  macrofile << "\"notes\":\"" << Notes << "\",\n";
1449  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
1450  macrofile << "}@" << __E__;
1451  macrofile.close();
1452  }
1453  else
1454  __SUP_COUT__ << "Unable to open file" << __E__;
1455 } // end createMacro()
1456 
1457 //==============================================================================
1465 void MacroMakerSupervisor::loadMacro(const std::string& macroName,
1466  std::string& macroString,
1467  const std::string& username /*=""*/)
1468 {
1469  __SUP_COUTV__(macroName);
1470 
1471  // first check public folder, then user
1472  std::string fullPath, line;
1473  macroString = "";
1474  for(unsigned int i = 0; i < 2; ++i)
1475  {
1476  if(i == 1)
1477  fullPath = (std::string)MACROS_DB_PATH + username + "/";
1478  else
1479  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1480 
1481  fullPath += macroName;
1482  if(macroName.find(".dat") != macroName.size() - 4)
1483  fullPath += ".dat";
1484  __SUP_COUTV__(fullPath);
1485 
1486  std::ifstream read(fullPath.c_str()); // reading a file
1487  if(read.is_open())
1488  {
1489  while(!read.eof())
1490  {
1491  getline(read, line);
1492  macroString += line;
1493  }
1494 
1495  read.close();
1496  }
1497  else // file does not exist
1498  {
1499  __SUP_COUT__ << "Unable to open file: " << fullPath << __E__;
1500  continue;
1501  }
1502 
1503  if(macroString != "")
1504  break; // macro has been found!
1505  } // end load from path loop
1506 
1507  if(macroString == "")
1508  {
1509  __SUP_SS__ << "Unable to locate file for macro '" << macroName
1510  << "'... does it exist?" << __E__;
1511  if(username != "")
1512  ss << " Attempted username was '" << username << ".'" << __E__;
1513  __SUP_SS_THROW__;
1514  }
1515 
1516  __SUP_COUTV__(macroString);
1517 } // end loadMacro()
1518 
1519 //==============================================================================
1520 void MacroMakerSupervisor::loadMacroNames(
1521  const std::string& username,
1522  std::pair<std::vector<std::string> /*public macros*/,
1523  std::vector<std::string> /*private macros*/>& returnMacroNames)
1524 {
1525  DIR* dir;
1526  struct dirent* ent;
1527  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
1528  if((dir = opendir(fullPath.c_str())) != NULL)
1529  {
1530  /* print all the files and directories within directory */
1531  while((ent = readdir(dir)) != NULL)
1532  {
1533  /* File name validation check */
1534  if((unsigned)strlen(ent->d_name) > 4)
1535  {
1536  std::string line;
1537  std::ifstream read(
1538  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1539  if(read.is_open())
1540  {
1541  read.close();
1542  // private macro found
1543  returnMacroNames.second.push_back(ent->d_name);
1544  }
1545  else
1546  __SUP_COUT__ << "Unable to open file" << __E__;
1547  }
1548  }
1549  closedir(dir);
1550  }
1551  else
1552  {
1553  __SUP_COUT__ << "Looping through privateMacros folder failed! Wrong directory"
1554  << __E__;
1555  }
1556  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1557  if((dir = opendir(fullPath.c_str())) != NULL)
1558  {
1559  /* print all the files and directories within directory */
1560  while((ent = readdir(dir)) != NULL)
1561  {
1562  /* File name validation check */
1563  if((unsigned)strlen(ent->d_name) > 4)
1564  {
1565  std::string line;
1566  std::ifstream read(
1567  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1568  if(read.is_open())
1569  {
1570  // public macro found
1571  returnMacroNames.first.push_back(ent->d_name);
1572  read.close();
1573  }
1574  else
1575  __SUP_COUT__ << "Unable to open file" << __E__;
1576  }
1577  }
1578  closedir(dir);
1579  }
1580  else
1581  {
1582  __SUP_COUT__ << fullPath << __E__;
1583  __SUP_COUT__ << "Looping through MacroData folder failed! Wrong directory"
1584  << __E__;
1585  }
1586 
1587 } // end loadMacroNames
1588 
1589 //==============================================================================
1590 void MacroMakerSupervisor::loadMacros(HttpXmlDocument& xmldoc,
1591  const std::string& username)
1592 {
1593  DIR* dir;
1594  struct dirent* ent;
1595  std::string returnStr = "";
1596  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
1597  if((dir = opendir(fullPath.c_str())) != NULL)
1598  {
1599  /* print all the files and directories within directory */
1600  while((ent = readdir(dir)) != NULL)
1601  {
1602  /* File name validation check */
1603  if((unsigned)strlen(ent->d_name) > 4)
1604  {
1605  std::string line;
1606  std::ifstream read(
1607  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1608  if(read.is_open())
1609  {
1610  std::stringstream buffer;
1611  while(!read.eof())
1612  {
1613  getline(read, line);
1614  buffer << line;
1615  //__SUP_COUT__ << line << __E__;
1616  }
1617  returnStr += buffer.str();
1618 
1619  read.close();
1620  }
1621  else
1622  __SUP_COUT__ << "Unable to open file" << __E__;
1623  }
1624  }
1625  std::string returnMacroStr = returnStr.substr(0, returnStr.size() - 1);
1626 
1627  __SUP_COUT__ << "Loading existing macros! " << returnMacroStr << __E__;
1628 
1629  closedir(dir);
1630  xmldoc.addTextElementToData("returnMacroStr", returnMacroStr);
1631  }
1632  else
1633  {
1634  __SUP_COUT__ << "Looping through privateMacros folder failed! Wrong directory"
1635  << __E__;
1636  }
1637  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1638  returnStr = "";
1639  if((dir = opendir(fullPath.c_str())) != NULL)
1640  {
1641  /* print all the files and directories within directory */
1642  while((ent = readdir(dir)) != NULL)
1643  {
1644  /* File name validation check */
1645  if((unsigned)strlen(ent->d_name) > 4)
1646  {
1647  std::string line;
1648  std::ifstream read(
1649  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1650  if(read.is_open())
1651  {
1652  std::stringstream buffer;
1653  while(!read.eof())
1654  {
1655  getline(read, line);
1656  buffer << line;
1657  //__SUP_COUT__ << line << __E__;
1658  }
1659  returnStr += buffer.str();
1660  read.close();
1661  }
1662  else
1663  __SUP_COUT__ << "Unable to open file" << __E__;
1664  }
1665  }
1666  std::string returnPublicStr = returnStr.substr(0, returnStr.size() - 1);
1667  __SUP_COUT__ << "Loading existing public macros: " << returnPublicStr << __E__;
1668  closedir(dir);
1669  xmldoc.addTextElementToData("returnPublicStr", returnPublicStr);
1670  }
1671  else
1672  {
1673  __SUP_COUT__ << fullPath << __E__;
1674  __SUP_COUT__ << "Looping through MacroData folder failed! Wrong directory"
1675  << __E__;
1676  }
1677 } // end loadMacros()
1678 
1679 //==============================================================================
1680 void MacroMakerSupervisor::appendCommandToHistory(std::string Command,
1681  std::string Format,
1682  std::string Time,
1683  std::string Interfaces,
1684  const std::string& username)
1685 {
1686  std::string fileName = "history.hist";
1687  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
1688  __SUP_COUT__ << fullPath << __E__;
1689  std::ofstream histfile(fullPath.c_str(), std::ios::app);
1690  if(histfile.is_open())
1691  {
1692  histfile << "{\n";
1693  histfile << "\"Command\":\"" << Command << "\",\n";
1694  histfile << "\"Format\":\"" << Format << "\",\n";
1695  histfile << "\"Time\":\"" << Time << "\",\n";
1696  histfile << "\"Interfaces\":\"" << Interfaces << "\"\n";
1697  histfile << "}#" << __E__;
1698  histfile.close();
1699  }
1700  else
1701  __SUP_COUT__ << "Unable to open history.hist" << __E__;
1702 } //end appendCommandToHistory()
1703 
1704 //==============================================================================
1705 void MacroMakerSupervisor::appendCommandToHistory(std::string feClass,
1706  std::string feUID,
1707  std::string macroType,
1708  std::string macroName,
1709  std::string inputArgs,
1710  std::string outputArgs,
1711  bool saveOutputs,
1712  const std::string& username)
1713 {
1714  //prevent repeats to FE command history (otherwise live view can overwhelm history)
1715  auto feHistoryIt = lastFeCommandToHistory_.find(username);
1716  if(feHistoryIt != lastFeCommandToHistory_.end() && feHistoryIt->second.size() == 7 &&
1717  feHistoryIt->second[0] == feClass && feHistoryIt->second[1] == feUID &&
1718  feHistoryIt->second[2] == macroType && feHistoryIt->second[3] == macroName &&
1719  feHistoryIt->second[4] == inputArgs && feHistoryIt->second[5] == outputArgs &&
1720  feHistoryIt->second[6] == (saveOutputs ? "1" : "0"))
1721  {
1722  __SUP_COUTT__ << "Not saving repeat command to history from user " << username
1723  << __E__;
1724  return;
1725  }
1726 
1727  std::string fileName = "FEhistory.hist";
1728  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
1729  __SUP_COUT__ << fullPath << __E__;
1730  std::ofstream histfile(fullPath.c_str(), std::ios::app);
1731  if(histfile.is_open())
1732  {
1733  histfile << "{\n";
1734  histfile << "\"feClass\":\"" << feClass << "\",\n";
1735  histfile << "\"feUID\":\"" << feUID << "\",\n";
1736  histfile << "\"macroType\":\"" << macroType << "\",\n";
1737  histfile << "\"macroName\":\"" << macroName << "\",\n";
1738  histfile << "\"inputArgs\":\"" << inputArgs << "\",\n";
1739  histfile << "\"outputArgs\":\"" << outputArgs << "\",\n";
1740  if(saveOutputs)
1741  histfile << "\"saveOutputs\":\"" << 1 << "\"\n";
1742  else
1743  histfile << "\"saveOutputs\":\"" << 0 << "\"\n";
1744  histfile << "}#" << __E__;
1745  histfile.close();
1746 
1747  lastFeCommandToHistory_[username].clear(); //create instance and/or clear
1748  feHistoryIt = lastFeCommandToHistory_.find(username);
1749  feHistoryIt->second.push_back(feClass);
1750  feHistoryIt->second.push_back(feUID);
1751  feHistoryIt->second.push_back(macroType);
1752  feHistoryIt->second.push_back(macroName);
1753  feHistoryIt->second.push_back(inputArgs);
1754  feHistoryIt->second.push_back(outputArgs);
1755  feHistoryIt->second.push_back((saveOutputs ? "1" : "0"));
1756  }
1757  else
1758  __SUP_COUT__ << "Unable to open FEhistory.hist" << __E__;
1759 
1760 } //end appendCommandToHistory()
1761 
1762 //==============================================================================
1763 void MacroMakerSupervisor::loadFEMacroSequences(HttpXmlDocument& xmldoc,
1764  const std::string& username)
1765 {
1766  __SUP_COUT__ << "loadFEMacroSequences for " << username << __E__;
1767  DIR* dir;
1768  struct dirent* ent;
1769  std::string fullPath = (std::string)MACROS_SEQUENCE_PATH + username + "/";
1770  std::string sequences = "";
1771  __SUP_COUTV__(fullPath);
1772  if((dir = opendir(fullPath.c_str())) != NULL)
1773  {
1774  /* print all the files and directories within directory */
1775  while((ent = readdir(dir)) != NULL)
1776  {
1777  std::string line;
1778  std::ifstream read(
1779  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1780  if(read.is_open())
1781  {
1782  read.close();
1783  sequences += ent->d_name + std::string(";");
1784  }
1785  else
1786  __SUP_COUT__ << "Unable to open file" << __E__;
1787  }
1788  closedir(dir);
1789  }
1790  else
1791  {
1792  __SUP_COUT__ << "Looping through MacroSequence/" + username +
1793  " folder failed! Invalid directory."
1794  << __E__;
1795  }
1796 
1797  if(username == WebUsers::DEFAULT_ADMIN_USERNAME)
1798  {
1799  // already have admin list, return the list of sequences
1800  xmldoc.addTextElementToData("FEsequences", sequences);
1801  return;
1802  }
1803 
1804  //always add admin sequences (as "public")
1805  fullPath = (std::string)MACROS_SEQUENCE_PATH + WebUsers::DEFAULT_ADMIN_USERNAME + "/";
1806 
1807  if((dir = opendir(fullPath.c_str())) != NULL)
1808  {
1809  /* print all the files and directories within directory */
1810  while((ent = readdir(dir)) != NULL)
1811  {
1812  std::string line;
1813  std::ifstream read(
1814  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1815  if(read.is_open())
1816  {
1817  read.close();
1818  sequences += std::string("public/") + ent->d_name + std::string(";");
1819  }
1820  else
1821  __SUP_COUT__ << "Unable to open file" << __E__;
1822  }
1823  closedir(dir);
1824  }
1825  else
1826  {
1827  __SUP_COUT__ << "Looping through MacroSequence/" +
1828  WebUsers::DEFAULT_ADMIN_USERNAME +
1829  " folder failed! Invalid directory."
1830  << __E__;
1831  }
1832 
1833  // return the list of sequences
1834  xmldoc.addTextElementToData("FEsequences", sequences);
1835  return;
1836 } //end loadFEMacroSequences()
1837 
1838 //==============================================================================
1839 void MacroMakerSupervisor::saveFEMacroSequence(cgicc::Cgicc& cgi,
1840  const std::string& username)
1841 {
1842  // get data from the http request
1843  std::string name =
1845  std::string FEsequence =
1847  bool overwrite = CgiDataUtilities::getDataAsInt(cgi, "overwrite");
1848 
1849  __SUP_COUTV__(overwrite);
1850  __SUP_COUTV__(name);
1851  __SUP_COUTV__(FEsequence);
1852 
1853  //reject illegal characters (only alphanumeric, spaces, dash, underscores)
1854  std::string fixedName = "";
1855  for(size_t i = 0; i < name.size(); ++i)
1856  if(!(name[i] == ' ' || name[i] == '-' || name[i] == '_' ||
1857  (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') ||
1858  (name[i] >= 'a' && name[i] <= 'z')))
1859  {
1860  __SUP_SS__
1861  << "Illegal character in Sequence name (position " << i
1862  << ") - only alphanumeric, spaces, dashes, and underscores allowed!"
1863  << __E__;
1864  __SUP_SS_THROW__;
1865  }
1866  else
1867  fixedName += name[i];
1868  __SUP_COUTV__(fixedName);
1869 
1870  std::string fullPath =
1871  (std::string)MACROS_SEQUENCE_PATH + username + "/" + fixedName + ".dat";
1872  __SUP_COUTV__(fullPath);
1873 
1874  //do not allow overwrite
1875  if(!overwrite && std::filesystem::exists(fullPath))
1876  {
1877  __SUP_SS__ << "Please choose another Sequence name! A sequence with the same "
1878  "resulting filename already exists at "
1879  << fullPath << __E__;
1880  __SUP_SS_THROW__;
1881  }
1882 
1883  std::ofstream seqfile(fullPath.c_str());
1884  if(seqfile.is_open())
1885  {
1886  seqfile << FEsequence << __E__;
1887  seqfile.close();
1888  }
1889  else
1890  {
1891  __SUP_SS__ << "Unable to open file to save FE Macro Sequence at " << fullPath
1892  << __E__;
1893  __SUP_SS_THROW__;
1894  }
1895 } //end saveFEMacroSequence()
1896 
1897 //==============================================================================
1898 void MacroMakerSupervisor::getFEMacroSequence(HttpXmlDocument& xmldoc,
1899  cgicc::Cgicc& cgi,
1900  const std::string& username)
1901 {
1902  std::string name =
1904  __SUP_COUTV__(name);
1905 
1906  bool isPublic = (name.find("public/") == 0 ? true : false);
1907  __SUP_COUTV__(isPublic);
1908 
1909  //reject illegal characters (only alphanumeric, spaces, dash, underscores)
1910  std::string fixedName = "";
1911  for(size_t i = (isPublic ? std::string("public/").size() : 0); i < name.size(); ++i)
1912  if(!(name[i] == ' ' || name[i] == '-' || name[i] == '_' ||
1913  (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') ||
1914  (name[i] >= 'a' && name[i] <= 'z')))
1915  {
1916  __COUT__ << "Illegal character in Sequence name (position " << i
1917  << ") - only alphanumeric, spaces, dashes, and underscores allowed!"
1918  << __E__;
1919  }
1920  else
1921  fixedName += name[i];
1922  __SUP_COUTV__(fixedName);
1923 
1924  // access to the file
1925  std::string fullPath =
1926  (std::string)MACROS_SEQUENCE_PATH + username + "/" + fixedName + ".dat";
1927  __SUP_COUT__ << fullPath << __E__;
1928 
1929  std::ifstream read(fullPath.c_str()); // reading the file
1930  char* response;
1931  unsigned long long fileSize;
1932 
1933  if(!isPublic && read.is_open())
1934  {
1935  read.seekg(0, std::ios::end);
1936  fileSize = read.tellg();
1937  response = new char[fileSize + 1];
1938  response[fileSize] = '\0';
1939  read.seekg(0, std::ios::beg);
1940 
1941  // read data as a block:
1942  read.read(response, fileSize);
1943  read.close();
1944 
1945  xmldoc.addTextElementToData("FEsequence", &response[0]);
1946 
1947  delete[] response;
1948  }
1949  else
1950  {
1951  if(!isPublic)
1952  __SUP_COUT__ << "Unable to open " << fullPath << "! Trying public area..."
1953  << __E__;
1954 
1955  //attempt to load from admin "public" area
1956  std::string publicFullPath = (std::string)MACROS_SEQUENCE_PATH +
1957  WebUsers::DEFAULT_ADMIN_USERNAME + "/" + fixedName +
1958  ".dat";
1959  __SUP_COUT__ << publicFullPath << __E__;
1960 
1961  std::ifstream read(publicFullPath.c_str()); // reading the file
1962  char* response;
1963  unsigned long long fileSize;
1964 
1965  if(read.is_open())
1966  {
1967  read.seekg(0, std::ios::end);
1968  fileSize = read.tellg();
1969  response = new char[fileSize + 1];
1970  response[fileSize] = '\0';
1971  read.seekg(0, std::ios::beg);
1972 
1973  // read data as a block:
1974  read.read(response, fileSize);
1975  read.close();
1976 
1977  xmldoc.addTextElementToData("FEsequence", &response[0]);
1978 
1979  delete[] response;
1980  }
1981  else
1982  {
1983  __SUP_SS__ << "Unable to open FE Macro Sequence at " << fullPath << " or "
1984  << publicFullPath << __E__;
1985  __SUP_SS_THROW__;
1986  }
1987  }
1988 } //end getFEMacroSequence()
1989 
1990 //==============================================================================
1991 void MacroMakerSupervisor::deleteFEMacroSequence(cgicc::Cgicc& cgi,
1992  const std::string& username)
1993 {
1994  std::string name =
1996  __SUP_COUTV__(name);
1997 
1998  bool isPublic = (name.find("public/") == 0 ? true : false);
1999  __SUP_COUTV__(isPublic);
2000 
2001  //reject illegal characters (only alphanumeric, spaces, dash, underscores)
2002  std::string fixedName = "";
2003  for(size_t i = (isPublic ? std::string("public/").size() : 0); i < name.size(); ++i)
2004  if(!(name[i] == ' ' || name[i] == '-' || name[i] == '_' ||
2005  (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') ||
2006  (name[i] >= 'a' && name[i] <= 'z')))
2007  {
2008  __COUT__ << "Illegal character in Sequence name (position " << i
2009  << ") - only alphanumeric, spaces, dashes, and underscores allowed!"
2010  << __E__;
2011  }
2012  else
2013  fixedName += name[i];
2014  __SUP_COUTV__(fixedName);
2015 
2016  // access to the file
2017  std::string fullPath =
2018  (std::string)MACROS_SEQUENCE_PATH + username + "/" + fixedName + ".dat";
2019  if(isPublic)
2020  fullPath = (std::string)MACROS_SEQUENCE_PATH + WebUsers::DEFAULT_ADMIN_USERNAME +
2021  "/" + fixedName + ".dat";
2022  __SUP_COUT__ << fullPath << __E__;
2023 
2024  //do not allow overwrite
2025  if(!std::filesystem::exists(fullPath))
2026  {
2027  __SUP_SS__
2028  << "The specified Sequence name does not exist! Looking for sequence file at "
2029  << fullPath << __E__;
2030  __SUP_SS_THROW__;
2031  }
2032 
2033  std::remove(fullPath.c_str());
2034  __SUP_COUT__ << "Successfully deleted " << fullPath << __E__;
2035 } //end deleteFEMacroSequence()
2036 
2037 //==============================================================================
2038 void MacroMakerSupervisor::makeSequencePublic(cgicc::Cgicc& cgi,
2039  const std::string& username)
2040 {
2041  std::string name =
2043  __SUP_COUTV__(name);
2044 
2045  bool isPublic = (name.find("public/") == 0 ? true : false);
2046  __SUP_COUTV__(isPublic);
2047  if(isPublic)
2048  {
2049  __SUP_SS__ << "The specified Sequence name is already designated as public."
2050  << __E__;
2051  __SUP_SS_THROW__;
2052  }
2053 
2054  //reject illegal characters (only alphanumeric, spaces, dash, underscores)
2055  std::string fixedName = "";
2056  for(size_t i = 0; i < name.size(); ++i)
2057  if(!(name[i] == ' ' || name[i] == '-' || name[i] == '_' ||
2058  (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') ||
2059  (name[i] >= 'a' && name[i] <= 'z')))
2060  {
2061  __COUT__ << "Illegal character in Sequence name (position " << i
2062  << ") - only alphanumeric, spaces, dashes, and underscores allowed!"
2063  << __E__;
2064  }
2065  else
2066  fixedName += name[i];
2067  __SUP_COUTV__(fixedName);
2068 
2069  // access to the file
2070  std::string source =
2071  (std::string)MACROS_SEQUENCE_PATH + username + "/" + fixedName + ".dat";
2072  __SUP_COUT__ << source << __E__;
2073  std::string destination = (std::string)MACROS_SEQUENCE_PATH +
2074  WebUsers::DEFAULT_ADMIN_USERNAME + "/" + fixedName + ".dat";
2075  __SUP_COUT__ << destination << __E__;
2076 
2077  if(std::filesystem::exists(destination))
2078  {
2079  __SUP_SS__ << "The sequence name '" << fixedName
2080  << "' already exists in the admin/public location: " << destination
2081  << __E__;
2082  __SUP_SS_THROW__;
2083  }
2084 
2085  //copy if file does not already exist
2086  std::filesystem::copy_file(
2087  source, destination, std::filesystem::copy_options::skip_existing);
2088  __SUP_COUT__ << "Successfully made " << fixedName
2089  << " public at path: " << destination << __E__;
2090 } //end deleteFEMacroSequence()
2091 
2092 //==============================================================================
2093 void MacroMakerSupervisor::loadHistory(HttpXmlDocument& xmldoc,
2094  const std::string& username)
2095 {
2096  std::string fileName = MACROS_HIST_PATH + username + "/" + "history.hist";
2097 
2098  std::ifstream read(fileName.c_str()); // reading a file
2099  __SUP_COUT__ << fileName << __E__;
2100 
2101  if(read.is_open())
2102  {
2103  std::string line;
2104  char* returnStr;
2105  unsigned long long fileSz, i = 0, MAX_HISTORY_SIZE = 100000;
2106 
2107  // get length of file to reserve the string size
2108  // and to cap history size
2109  read.seekg(0, std::ios::end);
2110  fileSz = read.tellg();
2111  returnStr = new char[fileSz + 1];
2112  returnStr[fileSz] = '\0';
2113  read.seekg(0, std::ios::beg);
2114 
2115  // read data as a block:
2116  read.read(returnStr, fileSz);
2117  read.close();
2118 
2119  // find i such that new string size is less than
2120  if(fileSz > MAX_HISTORY_SIZE)
2121  {
2122  i = fileSz - MAX_HISTORY_SIZE;
2123  for(; i < fileSz; ++i)
2124  if(returnStr[i] == '#')
2125  {
2126  i += 2;
2127  break; // skip new line character also to get to next record
2128  }
2129  if(i > fileSz)
2130  i = fileSz;
2131 
2132  // write back to file truncated history
2133  FILE* fp = fopen(fileName.c_str(), "w");
2134  if(!fp)
2135  {
2136  delete[] returnStr;
2137  __SS__ << "Big problem with macromaker history file: " << fileName
2138  << __E__;
2139  __SS_THROW__;
2140  }
2141  fwrite(&returnStr[i], fileSz - i, 1, fp);
2142  fclose(fp);
2143  }
2144 
2145  __SUP_COUT__ << "Loading user history! " << __E__;
2146 
2147  if(fileSz > 1)
2148  returnStr[fileSz - 2] = '\0'; // remove final newline and last #
2149 
2150  xmldoc.addTextElementToData("returnHistStr", &returnStr[i]);
2151 
2152  delete[] returnStr;
2153  }
2154  else
2155  __SUP_COUT__ << "Unable to open history.hist" << __E__;
2156 
2157 } //end loadHistory()
2158 
2159 //==============================================================================
2160 void MacroMakerSupervisor::loadFEHistory(HttpXmlDocument& xmldoc,
2161  const std::string& username)
2162 {
2163  std::string fileName = MACROS_HIST_PATH + username + "/" + "FEhistory.hist";
2164 
2165  std::ifstream read(fileName.c_str());
2166  __SUP_COUT__ << fileName << __E__;
2167 
2168  if(!read.is_open() && username != WebUsers::DEFAULT_ADMIN_USERNAME)
2169  {
2170  __SUP_COUT__ << "Unable to open FE history.hist.. Defaulting to admin's FE "
2171  "history as starting point."
2172  << __E__;
2173 
2174  fileName =
2175  MACROS_HIST_PATH + WebUsers::DEFAULT_ADMIN_USERNAME + "/" + "FEhistory.hist";
2176  read.open(fileName.c_str());
2177  }
2178 
2179  if(read.is_open())
2180  {
2181  std::string line;
2182  char* returnStr;
2183  unsigned long long fileSize;
2184  unsigned long long i = 0;
2185  unsigned long long MAX_HISTORY_SIZE = 100000;
2186 
2187  // get the length of the file
2188  read.seekg(0, std::ios::end);
2189  fileSize = read.tellg();
2190  returnStr = new char[fileSize + 1];
2191  returnStr[fileSize] = '\0';
2192  read.seekg(0, std::ios::beg);
2193 
2194  // read data as block
2195  read.read(returnStr, fileSize);
2196  read.close();
2197 
2198  // find i such that new string size is less than
2199  if(fileSize > MAX_HISTORY_SIZE)
2200  {
2201  i = fileSize - MAX_HISTORY_SIZE;
2202  for(; i < fileSize; ++i)
2203  {
2204  if(returnStr[i] == '#') // skip the new line char
2205  {
2206  i += 2;
2207  break;
2208  }
2209  }
2210  if(i > fileSize)
2211  i = fileSize;
2212 
2213  // write back to file truncated history
2214  FILE* fp = fopen(fileName.c_str(), "w");
2215  if(!fp)
2216  {
2217  delete[] returnStr;
2218  __SS__ << "Big problem with FE history file: " << fileName << __E__;
2219  __SS_THROW__;
2220  }
2221  fwrite(&returnStr[i], fileSize - i, 1, fp);
2222  fclose(fp);
2223  }
2224 
2225  __SUP_COUT__ << "Loading user history! " << __E__;
2226 
2227  if(fileSize > 1)
2228  returnStr[fileSize - 2] = '\0'; // remove final newline and last #
2229 
2230  xmldoc.addTextElementToData("returnHistStr", &returnStr[i]);
2231 
2232  delete[] returnStr;
2233  }
2234  else
2235  __SUP_COUT__ << "Unable to open FE history.hist" << __E__;
2236 
2237 } //end loadFEHistory()
2238 
2239 //==============================================================================
2240 void MacroMakerSupervisor::deleteMacro(HttpXmlDocument& xmldoc,
2241  cgicc::Cgicc& cgi,
2242  const std::string& username)
2243 {
2244  std::string MacroName = CgiDataUtilities::getData(cgi, "MacroName");
2245  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
2246 
2247  std::string fileName = MacroName + ".dat";
2248  std::string fullPath;
2249  if(isMacroPublic == "true")
2250  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
2251  else
2252  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
2253 
2254  __SUP_COUT__ << fullPath << __E__;
2255 
2256  std::remove(fullPath.c_str());
2257  __SUP_COUT__ << "Successfully deleted " << MacroName;
2258  xmldoc.addTextElementToData("deletedMacroName", MacroName);
2259 } //end deleteMacro()
2260 
2261 //==============================================================================
2262 void MacroMakerSupervisor::editMacro(HttpXmlDocument& xmldoc,
2263  cgicc::Cgicc& cgi,
2264  const std::string& username)
2265 {
2266  std::string oldMacroName = CgiDataUtilities::postData(cgi, "oldMacroName");
2267  std::string newMacroName = CgiDataUtilities::postData(cgi, "newMacroName");
2268  std::string FESequence = CgiDataUtilities::postData(cgi, "FEsequence");
2269  std::string Time = CgiDataUtilities::postData(cgi, "Time");
2270  std::string Notes =
2272 
2273  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
2274  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
2275 
2276  __SUP_COUTV__(oldMacroName);
2277  __SUP_COUTV__(newMacroName);
2278  __SUP_COUTV__(FESequence);
2279  __SUP_COUTV__(Notes);
2280  __SUP_COUTV__(Time);
2281  __SUP_COUTV__(isMacroPublic);
2282  __SUP_COUTV__(isMacroLSBF);
2283 
2284  __SUP_COUTV__(MACROS_DB_PATH);
2285 
2286  std::string fileName = oldMacroName + ".dat";
2287  std::string fullPath;
2288  if(isMacroPublic == "true")
2289  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
2290  else
2291  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
2292 
2293  __SUP_COUTV__(fullPath);
2294 
2295  std::ofstream macrofile(fullPath.c_str());
2296  if(macrofile.is_open())
2297  {
2298  macrofile << "{\n";
2299  macrofile << "\"name\":\"" << newMacroName << "\",\n";
2300  macrofile << "\"FEsequence\":\"" << FESequence << "\",\n";
2301  macrofile << "\"time\":\"" << Time << "\",\n";
2302  macrofile << "\"notes\":\"" << Notes << "\",\n";
2303  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
2304  macrofile << "}@" << __E__;
2305  macrofile.close();
2306  }
2307  else
2308  __SUP_COUT__ << "Unable to open file" << __E__;
2309 
2310  if(oldMacroName != newMacroName) // renaming macro
2311  {
2312  int result;
2313  result =
2314  rename((MACROS_DB_PATH + username + "/" + oldMacroName + ".dat").c_str(),
2315  (MACROS_DB_PATH + username + "/" + newMacroName + ".dat").c_str());
2316  if(result == 0)
2317  xmldoc.addTextElementToData("newMacroName", newMacroName);
2318  else
2319  xmldoc.addTextElementToData("newMacroName", "ERROR");
2320  }
2321 } //end editMacro()
2322 
2323 //==============================================================================
2324 void MacroMakerSupervisor::clearHistory(const std::string& username)
2325 {
2326  std::string fileName = "history.hist";
2327  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
2328 
2329  std::remove(fullPath.c_str());
2330  __SUP_COUT__ << "Successfully deleted " << fullPath;
2331 } //end clearHistory()
2332 
2333 //==============================================================================
2334 void MacroMakerSupervisor::clearFEHistory(const std::string& username)
2335 {
2336  std::string fileName = "FEhistory.hist";
2337  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
2338 
2339  std::remove(fullPath.c_str());
2340  __SUP_COUT__ << "Successfully deleted " << fullPath;
2341 } //end clearFEHistory()
2342 
2343 //==============================================================================
2344 void MacroMakerSupervisor::exportFEMacro(HttpXmlDocument& xmldoc,
2345  cgicc::Cgicc& cgi,
2346  const std::string& username)
2347 {
2348  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
2349  std::string pluginName = CgiDataUtilities::getData(cgi, "PluginName");
2350  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
2351  std::string macroNotes =
2353 
2354  __SUP_COUTV__(pluginName);
2355  __SUP_COUTV__(macroName);
2356  __SUP_COUTV__(macroSequence);
2357 
2358  // replace all special characters with white space
2359  for(unsigned int i = 0; i < macroNotes.length(); ++i)
2360  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
2361  macroNotes[i] = ' ';
2362  __SUP_COUTV__(macroNotes);
2363 
2364  std::stringstream ss(macroSequence);
2365  std::string command;
2366  std::vector<std::string> commands;
2367 
2368  while(getline(ss, command, ','))
2369  commands.push_back(command);
2370 
2371  __SUP_COUTV__(StringMacros::vectorToString(commands));
2372 
2373  std::map<std::string /*special type*/, std::set<std::string> /*special file paths*/>
2374  specialsCodeMap = CodeEditor::getSpecialsMap();
2375 
2376  //__SUP_COUTV__(StringMacros::mapToString(specialsCodeMap));
2377  auto specialsCodeMapIt = specialsCodeMap.find(CodeEditor::SPECIAL_TYPE_FEInterface);
2378  if(specialsCodeMapIt == specialsCodeMap.end())
2379  {
2380  __SS__
2381  << "Could not find any FE Interface plugins in source code. Does MacroMaker "
2382  << "have access to the source code? Check that the Supervisor context places "
2383  "MacroMaker in a "
2384  << "location with access to the source code." << __E__;
2385  __SS_THROW__;
2386  }
2387 
2388  // find first .h and .cc with the plugin name
2389  std::string headerFile = pluginName + ".h";
2390  std::string sourceFile = pluginName + "_interface.cc";
2391  bool foundHeaderFile = false;
2392  bool foundSourceFile = false;
2393  for(const auto& filePath : specialsCodeMapIt->second)
2394  {
2395  if(!foundHeaderFile && filePath.find(headerFile) != std::string::npos)
2396  {
2397  foundHeaderFile = true;
2398  headerFile = filePath;
2399  __SUP_COUT__ << "found headerFile=" << filePath << __E__;
2400  }
2401  if(!foundSourceFile && filePath.find(sourceFile) != std::string::npos)
2402  {
2403  foundSourceFile = true;
2404  sourceFile = filePath;
2405  __SUP_COUT__ << "found sourceFile=" << filePath << __E__;
2406  }
2407 
2408  if(foundSourceFile && foundHeaderFile)
2409  break;
2410  } // end file search loop
2411 
2412  if(!foundHeaderFile)
2413  {
2414  __SS__ << "Could not find the header file for the FE Interface plugins at '"
2415  << headerFile << ".' Does MacroMaker "
2416  << "have access to the source code? Check that the Supervisor context "
2417  "places MacroMaker in a "
2418  << "location with access to the source code." << __E__;
2419  __SS_THROW__;
2420  }
2421  if(!foundSourceFile)
2422  {
2423  __SS__ << "Could not find the source file for the FE Interface plugins at '"
2424  << sourceFile << ".' Does MacroMaker "
2425  << "have access to the source code? Check that the Supervisor context "
2426  "places MacroMaker in a "
2427  << "location with access to the source code." << __E__;
2428  __SS_THROW__;
2429  }
2430 
2431  // at this point have header and source file, now add FE Macro
2432  // Steps for each file:
2433  // - read current file
2434  // - find insert point
2435  // - open file for writing
2436  // - write original file up to insert point
2437  // - insert new code
2438  // - write remaining original file
2439 
2440  char timeBuffer[100];
2441  { // get time string
2442  time_t rawtime;
2443  struct tm* timeinfo;
2444 
2445  time(&rawtime);
2446  timeinfo = localtime(&rawtime);
2447 
2448  strftime(timeBuffer, 100, "%b-%d-%Y %I:%M:%S", timeinfo);
2449  }
2450 
2451  std::string contents;
2452  std::string insert;
2453 
2455  // handle source file modifications
2456  CodeEditor::readFile(CodeEditor::SOURCE_BASE_PATH, sourceFile, contents);
2457  //__SUP_COUTV__(contents);
2458 
2459  // return file locations, for the user to inspect on error
2460  xmldoc.addTextElementToData("sourceFile", sourceFile);
2461  xmldoc.addTextElementToData("headerFile", headerFile);
2462 
2463  // check for duplicate functions
2464  if(contents.find(pluginName + "::" + macroName) != std::string::npos)
2465  {
2466  __SS__ << "The function definition '" << (pluginName + "::" + macroName)
2467  << "(...)' already exists in the source file '" << sourceFile
2468  << ".' Duplicate functions are not allowed - please rename the macro or "
2469  "modify the source file."
2470  << __E__;
2471  __SS_THROW__;
2472  }
2473 
2474  std::stringstream codess;
2475  std::set<std::string> inArgNames, outArgNames;
2476  createCode(codess,
2477  commands,
2478  "\t" /*tabOffset*/,
2479  true /*forFeMacro*/,
2480  &inArgNames,
2481  &outArgNames);
2482  __SUP_COUTV__(StringMacros::setToString(inArgNames));
2483  __SUP_COUTV__(StringMacros::setToString(outArgNames));
2484 
2485  // find start of constructor and register macro
2486  {
2487  auto insertPos = contents.find(pluginName + "::" + pluginName);
2488  if(insertPos == std::string::npos)
2489  {
2490  __SS__ << "Could not find the code insert position in the source file '"
2491  << sourceFile << ".' The FE plugin class constructor must be '"
2492  << pluginName << ":" << pluginName << "' - is this the case?" << __E__;
2493  __SS_THROW__;
2494  }
2495  __SUP_COUTV__(insertPos);
2496  // find opening bracket after constructor name
2497  insertPos = contents.find("{", insertPos);
2498  if(insertPos == std::string::npos)
2499  {
2500  __SS__ << "Could not find the code insert position in the source file '"
2501  << sourceFile
2502  << ".' The FE plugin class constructor must begin with '{"
2503  << "' - is this the case?" << __E__;
2504  __SS_THROW__;
2505  }
2506  ++insertPos; // go past {
2507  __SUP_COUTV__(insertPos);
2508 
2509  insert = "\n\t//registration of FEMacro '" + macroName + "' generated, " +
2510  timeBuffer + ", by '" + username + "' using MacroMaker.\n\t" +
2511  "FEVInterface::registerFEMacroFunction(\"" + macroName +
2512  "\",//feMacroName \n\t\t" +
2513  "static_cast<FEVInterface::frontEndMacroFunction_t>(&" + pluginName +
2514  "::" + macroName + "), //feMacroFunction \n\t\t" +
2515  "std::vector<std::string>{";
2516  { // insert input argument names
2517  bool first = true;
2518  for(const auto& inArg : inArgNames)
2519  {
2520  if(first)
2521  first = false;
2522  else
2523  insert += ",";
2524  insert += "\"" + inArg + "\"";
2525  }
2526  }
2527  insert += "}, //namesOfInputArgs \n\t\t";
2528  insert += "std::vector<std::string>{";
2529  { // insert output argument names
2530  bool first = true;
2531  for(const auto& outArg : outArgNames)
2532  {
2533  if(first)
2534  first = false;
2535  else
2536  insert += ",";
2537  insert += "\"" + outArg + "\"";
2538  }
2539  }
2540  insert += "}, //namesOfOutputArgs \n\t\t";
2541  insert += "1); //requiredUserPermissions \n\n";
2542 
2543  __SUP_COUTV__(insert);
2544  contents = contents.substr(0, insertPos) + insert + contents.substr(insertPos);
2545  }
2546 
2547  // find end of source to append FE Macro function
2548  {
2549  auto insertPos = contents.rfind("DEFINE_OTS_INTERFACE");
2550  if(insertPos == std::string::npos)
2551  {
2552  __SS__ << "Could not find the code insert position in the source file '"
2553  << sourceFile
2554  << ".' The FE plugin class must end with a 'DEFINE_OTS_INTERFACE("
2555  << pluginName << ")' - is this the case?" << __E__;
2556  __SS_THROW__;
2557  }
2558  __SUP_COUTV__(insertPos);
2559 
2560  insert =
2561  "\n//"
2562  "============================================================================"
2563  "============================================\n//" +
2564  macroName + "\n" + "//\tFEMacro '" + macroName + "' generated, " +
2565  timeBuffer + ", by '" + username + "' using MacroMaker.\n" +
2566  "//\tMacro Notes: " + macroNotes + "\n" + "void " + pluginName +
2567  "::" + macroName + "(__ARGS__)\n{\n\t" +
2568  "__CFG_COUT__ << \"# of input args = \" << argsIn.size() << __E__; \n\t" +
2569  "__CFG_COUT__ << \"# of output args = \" << argsOut.size() << __E__; \n\t" +
2570  "for(auto &argIn:argsIn) \n\t\t" +
2571  "__CFG_COUT__ << argIn.first << \": \" << argIn.second << __E__; \n\n\t" +
2572  "//macro commands section \n" + codess.str() + "\n\n\t" +
2573  "for(auto &argOut:argsOut) \n\t\t" +
2574  "__CFG_COUT__ << argOut.first << \": \" << argOut.second << __E__; \n\n" +
2575  "} //end " + macroName + "()\n\n";
2576 
2577  //__SUP_COUTV__(insert);
2578  CodeEditor::writeFile(CodeEditor::SOURCE_BASE_PATH,
2579  sourceFile,
2580  contents,
2581  "MacroMaker-" + username,
2582  insertPos,
2583  insert);
2584  }
2585 
2587  // handle include file insertions
2588  CodeEditor::readFile(CodeEditor::SOURCE_BASE_PATH, headerFile, contents);
2589  //__SUP_COUTV__(contents);
2590 
2591  // find end of class by looking for last };
2592  {
2593  auto insertPos = contents.rfind("};");
2594  if(insertPos == std::string::npos)
2595  {
2596  __SS__ << "Could not find the code insert position in the header file '"
2597  << headerFile
2598  << ".' The FE plugin class must end with a '};' - is this the case?"
2599  << __E__;
2600  __SS_THROW__;
2601  }
2602 
2603  __SUP_COUTV__(insertPos);
2604 
2605  insert = "\npublic: // FEMacro '" + macroName + "' generated, " + timeBuffer +
2606  ", by '" + username + "' using MacroMaker.\n\t" + "void " + macroName +
2607  "\t(__ARGS__);\n";
2608 
2609  __SUP_COUTV__(insert);
2610  CodeEditor::writeFile(CodeEditor::SOURCE_BASE_PATH,
2611  headerFile,
2612  contents,
2613  "MacroMaker-" + username,
2614  insertPos,
2615  insert);
2616  }
2617 
2618 } // end exportFEMacro()
2619 
2620 //==============================================================================
2621 void MacroMakerSupervisor::exportMacro(HttpXmlDocument& xmldoc,
2622  cgicc::Cgicc& cgi,
2623  const std::string& username)
2624 {
2625  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
2626  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
2627  std::string macroNotes =
2629 
2630  __SUP_COUTV__(macroName);
2631  __SUP_COUTV__(macroSequence);
2632 
2633  // replace all special characters with white space
2634  for(unsigned int i = 0; i < macroNotes.length(); ++i)
2635  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
2636  macroNotes[i] = ' ';
2637  __SUP_COUTV__(macroNotes);
2638 
2639  std::stringstream ss(macroSequence);
2640  std::string command;
2641  std::vector<std::string> commands;
2642 
2643  while(getline(ss, command, ','))
2644  commands.push_back(command);
2645 
2646  std::string fileName = macroName + ".cc";
2647 
2648  std::string fullPath =
2649  __ENV__("SERVICE_DATA_PATH") + MACROS_EXPORT_PATH + username + "/" + fileName;
2650  __SUP_COUT__ << fullPath << __E__;
2651  std::ofstream exportFile(fullPath.c_str(), std::ios::trunc);
2652  if(exportFile.is_open())
2653  {
2654  exportFile << "//Generated Macro Name:\t" << macroName << "\n";
2655  exportFile << "//Macro Notes: " << macroNotes << "\n";
2656 
2657  {
2658  time_t rawtime;
2659  struct tm* timeinfo;
2660  char buffer[100];
2661 
2662  time(&rawtime);
2663  timeinfo = localtime(&rawtime);
2664 
2665  strftime(buffer, 100, "%b-%d-%Y %I:%M:%S", timeinfo);
2666  exportFile << "//Generated Time: \t\t" << buffer << "\n";
2667  }
2668 
2669  exportFile << "//Paste this whole file into an interface to transfer Macro "
2670  "functionality.\n";
2671 
2672  createCode(exportFile, commands);
2673 
2674  exportFile.close();
2675 
2676  xmldoc.addTextElementToData(
2677  "ExportFile",
2678  "$USER_DATA/ServiceData/" + MACROS_EXPORT_PATH + username + "/" + fileName);
2679  }
2680  else
2681  __SUP_COUT__ << "Unable to open file" << __E__;
2682 } // end exportMacro()
2683 
2684 //==============================================================================
2686 void MacroMakerSupervisor::createCode(std::ostream& out,
2687  const std::vector<std::string>& commands,
2688  const std::string& tabOffset,
2689  bool forFeMacro,
2690  std::set<std::string>* inArgNames,
2691  std::set<std::string>* outArgNames)
2692 {
2693  // int numOfHexBytes;
2694  std::set<std::string /*argInName*/> argInHasBeenInitializedSet;
2695  bool addressIsVariable, dataIsVariable;
2696 
2697  out << tabOffset << "{";
2698 
2699  out << "\n"
2700  << tabOffset << "\t"
2701  << "char *address \t= new char[universalAddressSize_]{0}; //create address "
2702  "buffer of interface size and init to all 0";
2703  out << "\n"
2704  << tabOffset << "\t"
2705  << "char *data \t\t= new char[universalDataSize_]{0}; //create data buffer "
2706  "of interface size and init to all 0";
2707 
2708  out << "\n"
2709  << tabOffset << "\t"
2710  << "uint64_t macroAddress; //create macro address buffer (size 8 bytes)";
2711  out << "\n"
2712  << tabOffset << "\t"
2713  << "uint64_t macroData; //create macro address buffer (size 8 bytes)";
2714 
2715  out << "\n"
2716  << tabOffset << "\t"
2717  << "std::map<std::string /*arg name*/,uint64_t /*arg val*/> macroArgs; //create "
2718  "map from arg name to 64-bit number";
2719 
2720  // loop through each macro command
2721  for(unsigned int i = 0; i < commands.size(); i++)
2722  {
2723  std::stringstream sst(commands[i]);
2724  std::string tokens;
2725  std::vector<std::string>
2726  oneCommand; // 4 fields: cmd index | cmd type | addr | data
2727  while(getline(sst, tokens, ':'))
2728  oneCommand.push_back(tokens);
2729  while(oneCommand.size() < 4)
2730  oneCommand.push_back(""); // fill out the 4 fields
2731 
2732  __SUP_COUTV__(StringMacros::vectorToString(oneCommand));
2733 
2734  // make this:
2735  // std::map<std::string,uint64_t> macroArgs;
2736  // {
2737  // uint64_t address = 0x1001; //create address buffer
2738  // uint64_t data = 0x100203; //create data buffer
2739  //
2740  // universalWrite(address,data);
2741  // universalRead(address,data);
2742  // }
2743  //
2744  // //if variable, first time init
2745  // {
2746  // address =
2747  // theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode("variableName").getValue<uint64_t>();
2748  // or
2749  // address = __GET_ARG_IN__("variableName",uint64_t);
2750  // }
2751  //
2752  // //if variable, second time use macroArgs
2753  // {
2754  // address = macroArgs["variableName"];
2755  // data = macroArgs["variableName"];
2756  // }
2757 
2758  addressIsVariable = isArgumentVariable(oneCommand[2]);
2759  dataIsVariable = isArgumentVariable(oneCommand[3]);
2760 
2761  __SUP_COUTV__(addressIsVariable);
2762  __SUP_COUTV__(dataIsVariable);
2763 
2764  out << "\n\n" << tabOffset << "\t// command-#" << i << ": ";
2765 
2766  if(oneCommand[1][0] == 'w' || oneCommand[1][0] == 'r')
2767  {
2768  if(oneCommand[1][0] == 'w')
2769  out << "Write(";
2770  else if(oneCommand[1][0] == 'r')
2771  out << "Read(";
2772 
2773  if(addressIsVariable)
2774  out << oneCommand[2];
2775  else // literal hex address
2776  out << "0x" << oneCommand[2];
2777  out << " /*address*/,";
2778 
2779  if(dataIsVariable) // read or write can have variable data, sink or source
2780  // respectively
2781  out << oneCommand[3] << " /*data*/";
2782  else if(oneCommand[1][0] == 'w') // literal hex data
2783  out << "0x" << oneCommand[3] << " /*data*/";
2784  else if(oneCommand[1][0] == 'r') // just reading to buffer
2785  out << "data";
2786  out << ");\n";
2787  }
2788  else if(oneCommand[1][0] == 'd')
2789  {
2790  out << "delay(" << oneCommand[2] << ");\n";
2791  out << tabOffset << "\t"
2792  << "__CFG_COUT__ << \"Sleeping for... \" << " << oneCommand[2]
2793  << " << \" milliseconds \" << __E__;\n";
2794  out << tabOffset << "\t"
2795  << "usleep(" << oneCommand[2] << "*1000 /* microseconds */);\n";
2796  continue;
2797  }
2798  else
2799  {
2800  __SS__ << "FATAL ERROR: Unknown command '" << oneCommand[1]
2801  << "'... command is not w, r or d" << __E__;
2802  __SS_THROW__;
2803  }
2804 
2806  // handle address
2807  if(addressIsVariable) // handle address as variable
2808  {
2809  if(argInHasBeenInitializedSet.find(oneCommand[2]) ==
2810  argInHasBeenInitializedSet.end()) // only initialize input argument once
2811  {
2812  argInHasBeenInitializedSet.emplace(oneCommand[2]);
2813 
2814  if(!forFeMacro)
2815  {
2816  // get address from configuration Tree
2817  out << tabOffset << "\t"
2818  << "macroArgs[\"" << oneCommand[2]
2819  << "\"] = "
2820  "theXDAQContextConfigTree_.getNode(theConfigurationPath_)."
2821  "getNode("
2822  << "\n"
2823  << tabOffset << "\t\t\"" << oneCommand[2]
2824  << "\").getValue<uint64_t>();";
2825  }
2826  else
2827  {
2828  if(inArgNames)
2829  inArgNames->emplace(oneCommand[2]);
2830 
2831  // get address from arguments
2832  out << tabOffset << "\t"
2833  << "macroArgs[\"" << oneCommand[2] << "\"] = __GET_ARG_IN__(\""
2834  << oneCommand[2] << "\", uint64_t);";
2835  }
2836  }
2837  out << "\t//get macro address argument";
2838  out << "\n"
2839  << tabOffset << "\tmemcpy(address,&macroArgs[\"" << oneCommand[2]
2840  << "\"],8); //copy macro address argument to buffer";
2841  }
2842  else // handle address as literal
2843  {
2844  out << tabOffset << "\t"
2845  << "macroAddress = 0x" << oneCommand[2]
2846  << "; memcpy(address,&macroAddress,8);"
2847  << "\t//copy macro address to buffer";
2848  }
2849 
2851  // handle data
2852  if(oneCommand[1] == "w") // if write, handle data too
2853  {
2854  if(dataIsVariable) // handle data as variable
2855  {
2856  if(argInHasBeenInitializedSet.find(oneCommand[3]) ==
2857  argInHasBeenInitializedSet
2858  .end()) // only initialize input argument once
2859  {
2860  argInHasBeenInitializedSet.emplace(oneCommand[3]);
2861 
2862  if(forFeMacro)
2863  {
2864  if(inArgNames)
2865  inArgNames->emplace(oneCommand[3]);
2866 
2867  // get data from arguments
2868  out << "\n"
2869  << tabOffset << "\t"
2870  << "macroArgs[\"" << oneCommand[3]
2871  << "\"] = __GET_ARG_IN__(\"" << oneCommand[3]
2872  << "\", uint64_t); //initialize from input arguments";
2873  }
2874  else
2875  {
2876  // get data from configuration Tree
2877  out << "\n"
2878  << tabOffset << "\t"
2879  << "macroArgs[\"" << oneCommand[3]
2880  << "\"] = "
2881  "theXDAQContextConfigTree_.getNode(theConfigurationPath_)."
2882  "getNode("
2883  << "\n"
2884  << tabOffset << "\t\t\"" << oneCommand[3]
2885  << "\").getValue<uint64_t>(); //initialize from "
2886  "configuration tree";
2887  }
2888  }
2889  out << "\t//get macro data argument";
2890  out << "\n"
2891  << tabOffset << "\tmemcpy(data,&macroArgs[\"" << oneCommand[3]
2892  << "\"],8); //copy macro data argument to buffer";
2893  }
2894  else // handle data as literal
2895  {
2896  out << "\n"
2897  << tabOffset << "\t"
2898  << "macroData = 0x" << oneCommand[3] << "; memcpy(data,&macroData,8);"
2899  << "\t//copy macro data to buffer";
2900  }
2901  out << "\n"
2902  << tabOffset << "\t"
2903  << "universalWrite(address,data);";
2904  }
2905  else
2906  {
2907  out << "\n"
2908  << tabOffset << "\t"
2909  << "universalRead(address,data);";
2910 
2911  std::string outputArgName;
2912 
2913  if(dataIsVariable) // handle data as variable
2914  outputArgName = oneCommand[3];
2915  else // give each read data a unique argument name
2916  {
2917  char str[20];
2918  sprintf(str, "outArg%d", i);
2919  outputArgName = str; // use command index for uniqueness
2920  }
2921  __SUP_COUTV__(outputArgName);
2922 
2923  out << tabOffset << "\t"
2924  << "memcpy(&macroArgs[\"" << outputArgName
2925  << "\"],data,8); //copy buffer to argument map";
2926 
2927  // copy read data to output args
2928  if(forFeMacro)
2929  out << "\n"
2930  << tabOffset << "\t"
2931  << "__SET_ARG_OUT__(\"" << outputArgName << "\",macroArgs[\""
2932  << outputArgName << "\"]); //update output argument result";
2933 
2934  if(outArgNames)
2935  outArgNames->emplace(outputArgName);
2936  argInHasBeenInitializedSet.emplace(
2937  outputArgName); // mark initialized since value has been read
2938  }
2939  } // end command loop
2940 
2941  out << "\n\n" << tabOffset << "\tdelete[] address; //free the memory";
2942  out << "\n" << tabOffset << "\tdelete[] data; //free the memory";
2943  out << "\n" << tabOffset << "}";
2944 
2945  __SUP_COUT__ << "Done with code generation." << __E__;
2946 } // end createCode()
2947 
2948 //==============================================================================
2951 bool MacroMakerSupervisor::isArgumentVariable(const std::string& argumentString)
2952 {
2953  for(unsigned int i = 0; i < argumentString.length(); ++i)
2954  {
2955  // detect non-hex
2956  if(!((argumentString[i] >= '0' && argumentString[i] <= '9') ||
2957  (argumentString[i] >= 'a' && argumentString[i] <= 'f') ||
2958  (argumentString[i] >= 'A' && argumentString[i] <= 'F')))
2959  return true;
2960  }
2961  return false;
2962 } // end isArgumentVariable()
2963 //==============================================================================
2973 std::string MacroMakerSupervisor::generateHexArray(const std::string& sourceHexString,
2974  int& numOfBytes)
2975 {
2976  std::stringstream retSs;
2977 
2978  std::string srcHexStr = sourceHexString;
2979  __SUP_COUT__ << "Translating: \n";
2980  __SUP_COUT__ << srcHexStr << __E__;
2981 
2982  if(srcHexStr.size() % 2) // if odd, make even
2983  srcHexStr = "0" + srcHexStr;
2984 
2985  numOfBytes = srcHexStr.size() / 2;
2986  retSs << "[" << numOfBytes << "] = {";
2987 
2988  for(int i = 0; i < numOfBytes * 2; i += 2)
2989  {
2990  // detect non-hex
2991  if(!((srcHexStr[i] >= '0' && srcHexStr[i] <= '9') ||
2992  (srcHexStr[i] >= 'a' && srcHexStr[i] <= 'f') ||
2993  (srcHexStr[i] >= 'A' && srcHexStr[i] <= 'F')) ||
2994  !((srcHexStr[i + 1] >= '0' && srcHexStr[i + 1] <= '9') ||
2995  (srcHexStr[i + 1] >= 'a' && srcHexStr[i + 1] <= 'f') ||
2996  (srcHexStr[i + 1] >= 'A' && srcHexStr[i + 1] <= 'F')))
2997  {
2998  numOfBytes = -1;
2999  return srcHexStr;
3000  }
3001 
3002  if(i != 0)
3003  retSs << ", ";
3004  retSs << "0x" << srcHexStr[srcHexStr.size() - 1 - i - 1]
3005  << srcHexStr[srcHexStr.size() - 1 - i];
3006  }
3007  retSs << "};";
3008 
3009  __SUP_COUT__ << retSs.str() << __E__;
3010 
3011  return retSs.str();
3012 } //end generateHexArray()
3013 
3014 //==============================================================================
3015 void MacroMakerSupervisor::runFEMacro(HttpXmlDocument& xmldoc,
3016  cgicc::Cgicc& cgi,
3017  const WebUsers::RequestUserInfo& userInfo)
3018 try
3019 {
3020  __SUP_COUTT__ << __E__;
3021 
3022  uint64_t NotDoneID = CgiDataUtilities::getDataAsUint64_t(cgi, "NotDoneID");
3023  if(NotDoneID)
3024  {
3025  __SUP_COUT__ << "Checking if recent FE macro run has completed for NotDoneID = "
3026  << NotDoneID << __E__;
3027 
3028  for(const auto& feMacroRunThreadStruct : feMacroRunThreadStruct_)
3029  __SUP_COUTT__ << "[] threadID_ = "
3030  << feMacroRunThreadStruct.parameters_.threadID_ << __E__;
3031 
3032  time_t now = time(0);
3033  size_t target_i = -1;
3034  for(size_t i = 0; i < feMacroRunThreadStruct_.size(); ++i)
3035  {
3036  if(feMacroRunThreadStruct_[i].parameters_.threadID_ == NotDoneID)
3037  {
3038  //found
3039  __SUP_COUTT__ << "Found NotDoneID = " << NotDoneID << __E__;
3040  target_i = i;
3041  }
3042  else if(feMacroRunThreadStruct_[i].feMacroRunDone_ &&
3043  now - feMacroRunThreadStruct_[i].parameters_.doneTime_ >
3044  5 * 60 * 60 /* 5 minutes*/)
3045  {
3046  __SUP_COUTT__ << "Cleaning up completed NotDoneID = " << NotDoneID
3047  << __E__;
3048  //clean up old structs
3049  feMacroRunThreadStruct_.erase(feMacroRunThreadStruct_.begin() + i);
3050  --i; //rewind
3051  }
3052  else if(now - feMacroRunThreadStruct_[i].parameters_.startTime_ >
3053  5 * 60 * 60 /* 5 minutes*/)
3054  {
3055  __SUP_COUT_WARN__
3056  << "Found old FE Macro exectution of '"
3057  << feMacroRunThreadStruct_[i].parameters_.macroName_ << "' at '"
3058  << feMacroRunThreadStruct_[i].parameters_.feUIDSelected_ << ".'"
3059  << __E__;
3060  }
3061  }
3062 
3063  if(target_i >= feMacroRunThreadStruct_.size())
3064  {
3065  __SUP_SS__
3066  << "Attempted to check recent FE Macro run completion with invalid ID="
3067  << NotDoneID
3068  << ". Perhaps this FE Macro completed more than 5 minutes ago?" << __E__;
3069  __SUP_SS_THROW__;
3070  }
3071 
3072  if(feMacroRunThreadStruct_[target_i].feMacroRunDone_)
3073  {
3074  __SUP_COUT__ << "Found done for NotDoneID = " << NotDoneID << __E__;
3075 
3076  if(feMacroRunThreadStruct_[target_i].parameters_.feMacroRunError_ != "")
3077  {
3078  __SUP_SS__
3079  << feMacroRunThreadStruct_[target_i].parameters_.feMacroRunError_;
3080  __SUP_SS_THROW__;
3081  }
3082  //copy result back to user
3083  if(TTEST(1))
3084  {
3085  std::ostringstream oss;
3086  feMacroRunThreadStruct_.back().parameters_.xmldoc_.outputXmlDocument(
3087  &oss);
3088  __SUP_COUTT__ << "xmldoc: " << oss.str() << __E__;
3089  }
3090  xmldoc.copyDataChildren(
3091  feMacroRunThreadStruct_[target_i].parameters_.xmldoc_);
3092  __SUP_COUT__ << "FE macro complete." << __E__;
3093  }
3094  else
3095  {
3096  __SUP_COUT__ << "Found still going for NotDoneID = " << NotDoneID << __E__;
3097  //return same NotDoneID to user for future check
3098  xmldoc.addNumberElementToData("NotDoneID", NotDoneID);
3099  }
3100 
3101  return;
3102  } //end done checking for done long duration FE Macro
3103 
3104  std::string feClassSelected = CgiDataUtilities::getData(cgi, "feClassSelected");
3105  std::string feUIDSelected =
3106  CgiDataUtilities::getData(cgi, "feUIDSelected"); // allow CSV multi-selection
3107  std::string macroType = CgiDataUtilities::getData(cgi, "macroType");
3108  std::string macroName =
3110  std::string inputArgs = CgiDataUtilities::postData(cgi, "inputArgs");
3111  std::string outputArgs = CgiDataUtilities::postData(cgi, "outputArgs");
3112  bool saveOutputs = CgiDataUtilities::getDataAsInt(cgi, "saveOutputs") == 1;
3113 
3114  __SUP_COUTTV__(feClassSelected);
3115  __SUP_COUTTV__(feUIDSelected);
3116  __SUP_COUTTV__(macroType);
3117  __SUP_COUTTV__(macroName);
3118  __SUP_COUTTV__(inputArgs);
3119  __SUP_COUTTV__(outputArgs);
3120  __SUP_COUTTV__(saveOutputs);
3121  __SUP_COUTTV__(userInfo.username_);
3122  __SUP_COUTTV__(StringMacros::mapToString(userInfo.getGroupPermissionLevels()));
3123 
3124  feMacroRunThreadStruct_.emplace_back( //runFEMacroStruct constructor
3125  xmldoc,
3126  feClassSelected,
3127  feUIDSelected,
3128  macroType,
3129  macroName,
3130  inputArgs,
3131  outputArgs,
3132  saveOutputs,
3133  userInfo.username_,
3134  StringMacros::mapToString(userInfo.getGroupPermissionLevels()));
3135 
3136  // Old single-threaded call:
3137  // runFEMacro(
3138  // xmldoc,
3139  // feClassSelected,
3140  // feUIDSelected,
3141  // macroType,
3142  // macroName,
3143  // inputArgs,
3144  // outputArgs,
3145  // saveOutputs,
3146  // userInfo.username_,
3147  // StringMacros::mapToString(userInfo.getGroupPermissionLevels()));
3148 
3149  std::thread t(
3150  [](runFEMacroStruct* s, MacroMakerSupervisor* mm) {
3151  MacroMakerSupervisor::runFEMacroThread(s, mm);
3152  },
3153  &feMacroRunThreadStruct_.back(),
3154  this);
3155 
3156  size_t sleepTime = 10 * 1000; //10ms
3157  usleep(sleepTime);
3158  //if not done in 5 seconds, track in "not-done" queue
3159  for(int i = 0; i < 6; ++i)
3160  {
3161  if(feMacroRunThreadStruct_.back().feMacroRunDone_)
3162  {
3163  __SUP_COUTT__ << "FE macro marked done" << __E__;
3164  break;
3165  }
3166  else
3167  {
3168  __SUP_COUTT__ << "FE macro not done, sleeping..." << __E__;
3169  sleepTime *= 5; //50ms, 250ms, 1s
3170  if(sleepTime > 1000 * 1000 /* seconds*/)
3171  sleepTime = 1000 * 1000; //max 1 sec
3172  usleep(sleepTime);
3173  }
3174  } //end wait loop
3175 
3176  if(!feMacroRunThreadStruct_.back().feMacroRunDone_) //macro not done...
3177  {
3178  if(t.get_id() == std::thread::id())
3179  {
3180  __SUP_SS__ << "Invalid thread ID. Contact system admins!" << __E__;
3181  __SUP_SS_THROW__;
3182  }
3183  feMacroRunThreadStruct_.back().parameters_.threadID_ =
3184  std::hash<std::thread::id>{}(t.get_id());
3185 
3186  if(feMacroRunThreadStruct_.back().parameters_.threadID_ == 0)
3187  {
3188  __SUP_SS__ << "Invalid thread ID hash. Contact system admins!" << __E__;
3189  __SUP_SS_THROW__;
3190  }
3191 
3192  __SUP_COUT__ << "FE macro not done, detaching thread="
3193  << feMacroRunThreadStruct_.back().parameters_.threadID_ << __E__;
3194  t.detach();
3195  xmldoc.addNumberElementToData(
3196  "NotDoneID", feMacroRunThreadStruct_.back().parameters_.threadID_);
3197 
3198  if(TTEST(1))
3199  {
3200  std::ostringstream oss;
3201  xmldoc.outputXmlDocument(
3202  &oss, false /* dispStdOut */, true /* allowWhiteSpace */);
3203  __SUP_COUTT__ << "xmldoc: " << oss.str() << __E__;
3204  }
3205  }
3206  else //macro done!
3207  {
3208  __SUP_COUTT__ << "FE macro marked done - joining threads." << __E__;
3209  t.join(); //make sure thread fully complete
3210  if(feMacroRunThreadStruct_.back().parameters_.feMacroRunError_ != "")
3211  {
3212  __SUP_SS__ << feMacroRunThreadStruct_.back().parameters_.feMacroRunError_;
3213  __SUP_SS_THROW__;
3214  }
3215  //copy result back to user
3216  if(TTEST(1))
3217  {
3218  std::ostringstream oss;
3219  feMacroRunThreadStruct_.back().parameters_.xmldoc_.outputXmlDocument(
3220  &oss, false /* dispStdOut */, true /* allowWhiteSpace */);
3221  __SUP_COUTT__ << "xmldoc: " << oss.str() << __E__;
3222  }
3223  xmldoc.copyDataChildren(feMacroRunThreadStruct_.back().parameters_.xmldoc_);
3224 
3225  if(TTEST(1))
3226  {
3227  std::ostringstream oss;
3228  xmldoc.outputXmlDocument(
3229  &oss, false /* dispStdOut */, true /* allowWhiteSpace */);
3230  __SUP_COUTT__ << "xmldoc: " << oss.str() << __E__;
3231  }
3232 
3233  feMacroRunThreadStruct_.pop_back(); //drop the completed struct
3234  __SUP_COUT__ << "FE macro complete." << __E__;
3235  }
3236  for(const auto& feMacroRunThreadStruct : feMacroRunThreadStruct_)
3237  __SUP_COUTT__ << "[] threadID_ = " << feMacroRunThreadStruct.parameters_.threadID_
3238  << __E__;
3239 
3240 } //end runFEMacro()
3241 catch(const std::runtime_error& e)
3242 {
3243  __SUP_SS__ << "Error processing FE communication request: " << e.what() << __E__;
3244  __SUP_COUT_ERR__ << ss.str();
3245  xmldoc.addTextElementToData("Error", ss.str());
3246 }
3247 catch(...)
3248 {
3249  __SUP_SS__ << "Unknown error processing FE communication request." << __E__;
3250  try
3251  {
3252  throw;
3253  } //one more try to printout extra info
3254  catch(const std::exception& e)
3255  {
3256  ss << "Exception message: " << e.what();
3257  }
3258  catch(...)
3259  {
3260  }
3261  __SUP_COUT_ERR__ << ss.str();
3262 
3263  xmldoc.addTextElementToData("Error", ss.str());
3264 } // end runFEMacro() catch
3265 
3266 //==============================================================================
3268 void MacroMakerSupervisor::runFEMacroThread(runFEMacroStruct* feMacroRunThreadStruct,
3269  MacroMakerSupervisor* mmSupervisor)
3270 try
3271 {
3272  __COUT__ << "runFEMacro thread started... threadid = " << std::this_thread::get_id()
3273  << " " << mmSupervisor << " getpid()=" << getpid()
3274  << " gettid()=" << gettid() << __E__;
3275 
3276  mmSupervisor->runFEMacro(feMacroRunThreadStruct->parameters_.xmldoc_,
3277  feMacroRunThreadStruct->parameters_.feClassSelected_,
3278  feMacroRunThreadStruct->parameters_.feUIDSelected_,
3279  feMacroRunThreadStruct->parameters_.macroType_,
3280  feMacroRunThreadStruct->parameters_.macroName_,
3281  feMacroRunThreadStruct->parameters_.inputArgs_,
3282  feMacroRunThreadStruct->parameters_.outputArgs_,
3283  feMacroRunThreadStruct->parameters_.saveOutputs_,
3284  feMacroRunThreadStruct->parameters_.runningUsername_,
3285  feMacroRunThreadStruct->parameters_.userGroupPermissions_);
3286 
3287  feMacroRunThreadStruct->parameters_.doneTime_ = time(0);
3288  feMacroRunThreadStruct->feMacroRunDone_ = true;
3289  __COUT__ << "runFEMacro thread done. threadid = " << std::this_thread::get_id()
3290  << __E__;
3291 
3292 } //end static runFEMacroThread()
3293 catch(const std::runtime_error& e)
3294 {
3295  __SS__ << "Error during runFEMacro thread: " << e.what() << __E__;
3296  __COUT_ERR__ << ss.str();
3297  feMacroRunThreadStruct->parameters_.feMacroRunError_ = ss.str();
3298  feMacroRunThreadStruct->parameters_.doneTime_ = time(0);
3299  feMacroRunThreadStruct->feMacroRunDone_ = true;
3300 }
3301 catch(...)
3302 {
3303  __SS__ << "Unknown error during runFEMacro thread." << __E__;
3304  try
3305  {
3306  throw;
3307  } //one more try to printout extra info
3308  catch(const std::exception& e)
3309  {
3310  ss << "Exception message: " << e.what();
3311  }
3312  catch(...)
3313  {
3314  }
3315  __COUT_ERR__ << ss.str();
3316  feMacroRunThreadStruct->parameters_.feMacroRunError_ = ss.str();
3317  feMacroRunThreadStruct->parameters_.doneTime_ = time(0);
3318  feMacroRunThreadStruct->feMacroRunDone_ = true;
3319 } // end static runFEMacroThread() catch
3320 
3321 //==============================================================================
3322 void MacroMakerSupervisor::runFEMacro(HttpXmlDocument& xmldoc,
3323  std::string feClassSelected,
3324  std::string feUIDSelected,
3325  const std::string& macroType,
3326  const std::string& macroName,
3327  const std::string& inputArgs,
3328  const std::string outputArgs,
3329  bool saveOutputs,
3330  const std::string& username,
3331  const std::string& userGroupPermissions)
3332 {
3333  __SUP_COUTV__(feClassSelected);
3334  __SUP_COUTV__(feUIDSelected);
3335  __SUP_COUTV__(macroType);
3336  __SUP_COUTV__(macroName);
3337  __SUP_COUTV__(inputArgs);
3338  __SUP_COUTV__(outputArgs);
3339  __SUP_COUTV__(saveOutputs);
3340  __SUP_COUTV__(username);
3341  __SUP_COUTV__(userGroupPermissions);
3342 
3343  appendCommandToHistory(feClassSelected,
3344  feUIDSelected,
3345  macroType,
3346  macroName,
3347  inputArgs,
3348  outputArgs,
3349  saveOutputs,
3350  username);
3351 
3352  std::set<std::string /*feUID*/> feUIDs;
3353 
3354  if(feUIDSelected == "")
3355  feUIDSelected = "*"; // treat empty as all
3356  if(feClassSelected == "")
3357  feClassSelected = "*"; // treat empty as all
3358 
3359  if(feClassSelected == "" || feUIDSelected == "" || macroType == "" || macroName == "")
3360  {
3361  __SUP_SS__ << "Illegal empty front-end parameter." << __E__;
3362  __SUP_SS_THROW__;
3363  }
3364  else if(feUIDSelected != "*")
3365  {
3366  StringMacros::getSetFromString(feUIDSelected, feUIDs);
3367  }
3368  else // * all case
3369  {
3370  // add all FEs for type
3371  if(feClassSelected == "*")
3372  {
3373  for(auto& feTypePair : FEPluginTypetoFEsMap_)
3374  for(auto& feUID : feTypePair.second)
3375  feUIDs.emplace(feUID);
3376  }
3377  else
3378  {
3379  auto typeIt = FEPluginTypetoFEsMap_.find(feClassSelected);
3380  if(typeIt == FEPluginTypetoFEsMap_.end())
3381  {
3382  __SUP_SS__ << "Illegal front-end type parameter '" << feClassSelected
3383  << "' not in list of types." << __E__;
3384  __SUP_SS_THROW__;
3385  }
3386 
3387  for(auto& feUID : typeIt->second)
3388  feUIDs.emplace(feUID);
3389  }
3390  }
3391 
3392  __SUP_COUTV__(StringMacros::setToString(feUIDs));
3393 
3394  std::string macroString;
3395  if(macroType == "public")
3396  loadMacro(macroName, macroString);
3397  else if(macroType == "private")
3398  loadMacro(macroName, macroString, username);
3399 
3400  __SUP_COUTV__(macroString);
3401 
3402  FILE* fp = 0;
3403  try
3404  {
3405  if(saveOutputs)
3406  {
3407  std::string filename = "/macroOutput_" + std::to_string(time(0)) + "_" +
3408  std::to_string(clock()) + ".txt";
3409 
3410  __SUP_COUTV__(filename);
3411  fp = fopen((CodeEditor::OTSDAQ_DATA_PATH + filename).c_str(), "w");
3412  if(!fp)
3413  {
3414  __SUP_SS__ << "Failed to open file to save macro output '"
3415  << CodeEditor::OTSDAQ_DATA_PATH << filename << "'..." << __E__;
3416  __SUP_SS_THROW__;
3417  }
3418 
3419  fprintf(fp, "############################\n");
3420  fprintf(fp,
3421  "### Running '%s' at time %s\n",
3422  macroName.c_str(),
3424  fprintf(fp,
3425  "### \t Target front-ends (count=%lu): %s\n",
3426  feUIDs.size(),
3427  StringMacros::setToString(feUIDs).c_str());
3428  fprintf(fp, "### \t\t Inputs: %s\n", inputArgs.c_str());
3429  fprintf(fp, "############################\n\n\n");
3430 
3431  xmldoc.addTextElementToData("feMacroRunArgs_name", "Filename");
3432  xmldoc.addTextElementToData("feMacroRunArgs_value",
3433  "$OTSDAQ_DATA/" + filename);
3434  }
3435 
3436  // do for all target front-ends
3437  for(auto& feUID : feUIDs)
3438  {
3439  auto feIt = FEtoSupervisorMap_.find(feUID);
3440  if(feIt == FEtoSupervisorMap_.end())
3441  {
3442  __SUP_SS__ << "Destination front end interface ID '" << feUID
3443  << "' was not found in the list of front ends." << __E__;
3444  ss << "\n\nHere is the map:\n\n"
3445  << StringMacros::mapToString(FEtoSupervisorMap_) << __E__;
3446  __SUP_SS_THROW__;
3447  }
3448 
3449  unsigned int FESupervisorIndex = feIt->second;
3450  __SUP_COUT__ << "Found supervisor index: " << FESupervisorIndex << __E__;
3451 
3452  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
3453  if(it == allFESupervisorInfo_.end())
3454  {
3455  __SUP_SS__
3456  << "Error transmitting request to FE Supervisor '" << feUID << ":"
3457  << FESupervisorIndex << ".' \n\n"
3458  << "The FE Supervisor Index does not exist. Have you configured "
3459  "the state machine properly?"
3460  << __E__;
3461  __SUP_SS_THROW__;
3462  }
3463 
3464  // send command to chosen FE and await response
3465  SOAPParameters txParameters; // params for xoap to send
3466  if(macroType == "fe")
3467  txParameters.addParameter("Request", "RunInterfaceMacro");
3468  else
3469  txParameters.addParameter("Request", "RunMacroMakerMacro");
3470  txParameters.addParameter("InterfaceID", feUID);
3471  if(macroType == "fe")
3472  txParameters.addParameter("feMacroName", macroName);
3473  else
3474  {
3475  txParameters.addParameter("macroName", macroName);
3476  txParameters.addParameter("macroString", macroString);
3477  }
3478  txParameters.addParameter("inputArgs", inputArgs);
3479  txParameters.addParameter("outputArgs", outputArgs);
3480  txParameters.addParameter("userPermissions", userGroupPermissions);
3481 
3482  SOAPParameters rxParameters; // params for xoap to recv
3483  // rxParameters.addParameter("success");
3484  rxParameters.addParameter("outputArgs");
3485  rxParameters.addParameter("Error");
3486 
3487  if(saveOutputs)
3488  {
3489  fprintf(fp,
3490  "Running '%s' at time %s\n",
3491  macroName.c_str(),
3493  fprintf(fp,
3494  "\t Target front-end: '%s::%s'\n",
3495  FEtoPluginTypeMap_[feUID].c_str(),
3496  feUID.c_str());
3497  fprintf(fp,
3498  "\t\t Inputs: %s\n",
3499  StringMacros::decodeURIComponent(inputArgs).c_str());
3500  }
3501 
3502  // have FE supervisor descriptor, so send
3503  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
3504  it->second.getDescriptor(), // supervisor descriptor
3505  "MacroMakerSupervisorRequest",
3506  txParameters);
3507 
3508  __SUP_COUT__ << "Received response message: "
3509  << SOAPUtilities::translate(retMsg) << __E__;
3510 
3511  SOAPUtilities::receive(retMsg, rxParameters);
3512 
3513  __SUP_COUT__ << "Received it " << __E__;
3514 
3515  // bool success = rxParameters.getValue("success") == "1";
3516  std::string outputResults = rxParameters.getValue("outputArgs");
3517  std::string error = rxParameters.getValue("Error");
3518 
3519  //__SUP_COUT__ << "rx success = " << success << __E__;
3520  __SUP_COUT__ << "outputArgs = " << outputResults << __E__;
3521 
3522  if(error != "")
3523  {
3524  __SS__ << "Attempted FE Macro Failed. Attempted target "
3525  << "was UID=" << feUID
3526  << " at feSupervisorID=" << FESupervisorIndex << "." << __E__;
3527  ss << "\n\n The error was:\n\n" << error << __E__;
3528  __SUP_COUT_ERR__ << "\n" << ss.str();
3529  xmldoc.addTextElementToData("Error", ss.str());
3530  return;
3531  }
3532 
3533  // build output arguments
3534  // parse args, colon-separated pairs, and then comma-separated
3535  {
3536  DOMElement* feMacroExecParent =
3537  xmldoc.addTextElementToData("feMacroExec", macroName);
3538 
3539  xmldoc.addTextElementToParent(
3540  "exec_time", StringMacros::getTimestampString(), feMacroExecParent);
3541  xmldoc.addTextElementToParent("fe_uid", feUID, feMacroExecParent);
3542  xmldoc.addTextElementToParent(
3543  "fe_type", FEtoPluginTypeMap_[feUID], feMacroExecParent);
3544  xmldoc.addTextElementToParent(
3545  "fe_context", it->second.getContextName(), feMacroExecParent);
3546  xmldoc.addTextElementToParent(
3547  "fe_supervisor", it->second.getName(), feMacroExecParent);
3548  xmldoc.addTextElementToParent(
3549  "fe_hostname", it->second.getHostname(), feMacroExecParent);
3550 
3551  std::istringstream inputStream(outputResults);
3552  std::string splitVal, argName, argValue;
3553  while(getline(inputStream, splitVal, ';'))
3554  {
3555  std::istringstream pairInputStream(splitVal);
3556  getline(pairInputStream, argName, ',');
3557  getline(pairInputStream, argValue, ',');
3558 
3559  if(saveOutputs)
3560  {
3561  fprintf(fp,
3562  "\t\t Output '%s' = %s\n",
3563  argName.c_str(),
3564  StringMacros::decodeURIComponent(argValue).c_str());
3565  }
3566  else
3567  {
3568  xmldoc.addTextElementToParent(
3569  "outputArgs_name", argName, feMacroExecParent);
3570  xmldoc.addTextElementToParent(
3571  "outputArgs_value", argValue, feMacroExecParent);
3572  }
3573  __SUP_COUT__ << argName << ": " << argValue << __E__;
3574  }
3575  }
3576  } // end target front-end loop
3577  }
3578  catch(...) // handle file close on error
3579  {
3580  if(fp)
3581  fclose(fp);
3582  throw;
3583  }
3584 
3585  if(fp)
3586  fclose(fp);
3587 
3588 } // end runFEMacro()
3589 
3590 //==============================================================================
3591 void MacroMakerSupervisor::getFEMacroList(HttpXmlDocument& xmldoc,
3592  const std::string& username)
3593 {
3594  __SUP_COUT__ << "Getting FE Macro list" << __E__;
3595 
3596  SOAPParameters txParameters; // params for xoap to send
3597  txParameters.addParameter("Request", "GetInterfaceMacros");
3598 
3599  SOAPParameters rxParameters; // params for xoap to recv
3600  rxParameters.addParameter("FEMacros");
3601 
3602  std::string oneInterface;
3603  std::string rxFEMacros;
3604 
3605  // for each list of FE Supervisors,
3606  // get all FE specific macros
3607  for(auto& appInfo : allFESupervisorInfo_)
3608  {
3609  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId()
3610  << " name = " << appInfo.second.getName() << __E__;
3611 
3612  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
3613  appInfo.second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
3614  SOAPUtilities::receive(retMsg, rxParameters);
3615 
3616  rxFEMacros = rxParameters.getValue("FEMacros");
3617 
3618  __SUP_COUT__ << "FE Macros received: \n" << rxFEMacros << __E__;
3619 
3620  std::istringstream allInterfaces(rxFEMacros);
3621  while(std::getline(allInterfaces, oneInterface))
3622  {
3623  //__SUP_COUT__ << oneInterface << __E__;
3624  //__SUP_COUT__ << appInfo.second.getId() << __E__;
3625  xmldoc.addTextElementToData("FEMacros", oneInterface);
3626  // xmldoc.outputXmlDocument(0,true);
3627  }
3628  }
3629 
3630  // add macros to response
3631  std::pair<std::vector<std::string> /*public macros*/,
3632  std::vector<std::string> /*private macros*/>
3633  macroNames;
3634  loadMacroNames(username, macroNames);
3635 
3636  __SUP_COUT__ << "Public macro count: " << macroNames.first.size() << __E__;
3637  __SUP_COUT__ << "Private macro count: " << macroNames.second.size() << __E__;
3638 
3639  std::string macroString;
3640  // make xml ':' separated fields:
3641  // macro name
3642  // permissions string
3643  // number of inputs
3644  // inputs separated by :
3645  // number of outputs
3646  // outputs separated by :
3647 
3648  for(int i = 0; i < 2; ++i) // first is public, then private
3649  for(auto& macroName : (i ? macroNames.second : macroNames.first))
3650  {
3651  // get macro string
3652  loadMacro(macroName, macroString, username);
3653 
3654  // extract macro object
3655  FEVInterface::macroStruct_t macro(macroString);
3656 
3657  std::stringstream xmlMacroStream;
3658  xmlMacroStream << macro.macroName_;
3659  xmlMacroStream << ":"
3660  << "1"; // permissions string
3661  xmlMacroStream << ":" << macro.namesOfInputArguments_.size();
3662  for(auto& inputArg : macro.namesOfInputArguments_)
3663  xmlMacroStream << ":" << inputArg;
3664  xmlMacroStream << ":" << macro.namesOfOutputArguments_.size();
3665  for(auto& inputArg : macro.namesOfOutputArguments_)
3666  xmlMacroStream << ":" << inputArg;
3667 
3668  xmldoc.addTextElementToData(i ? "PrivateMacro" : "PublicMacro",
3669  xmlMacroStream.str());
3670  }
3671 } //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 onlyLoadIfBackboneOrContext=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)