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