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