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