otsdaq_utilities  v2_05_02_indev
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 <dirent.h> //for DIR
8 #include <stdio.h> //for file rename
9 #include <sys/stat.h> //for mkdir
10 #include <cstdio>
11 #include <fstream>
12 #include <thread> //for std::thread
13 #include "otsdaq/TableCore/TableGroupKey.h"
14 
15 #define MACROS_DB_PATH std::string(__ENV__("SERVICE_DATA_PATH")) + "/MacroData/"
16 #define MACROS_HIST_PATH std::string(__ENV__("SERVICE_DATA_PATH")) + "/MacroHistory/"
17 #define MACROS_EXPORT_PATH std::string("/MacroExport/")
18 
19 #define SEQUENCE_FILE_NAME \
20  std::string(__ENV__("SERVICE_DATA_PATH")) + "/OtsWizardData/sequence.dat"
21 #define SEQUENCE_OUT_FILE_NAME \
22  std::string(__ENV__("SERVICE_DATA_PATH")) + "/OtsWizardData/sequence.out"
23 
24 using namespace ots;
25 
26 #undef __MF_SUBJECT__
27 #define __MF_SUBJECT__ "MacroMaker"
28 
29 XDAQ_INSTANTIATOR_IMPL(MacroMakerSupervisor)
30 
31 //==============================================================================
32 MacroMakerSupervisor::MacroMakerSupervisor(xdaq::ApplicationStub* stub)
33  : CoreSupervisorBase(stub)
34 {
35  __SUP_COUT__ << "Constructing..." << __E__;
36 
37  INIT_MF("." /*directory used is USER_DATA/LOG/.*/);
38 
39  // make macro directories in case they don't exist
40  mkdir(((std::string)MACROS_DB_PATH).c_str(), 0755);
41  mkdir(((std::string)MACROS_HIST_PATH).c_str(), 0755);
42  mkdir((__ENV__("SERVICE_DATA_PATH") + MACROS_EXPORT_PATH).c_str(), 0755);
43 
44  xoap::bind(this,
45  &MacroMakerSupervisor::frontEndCommunicationRequest,
46  "FECommunication",
47  XDAQ_NS_URI);
48 
49  // start requests for MacroMaker only mode
50  if(CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
51  {
52  __SUP_COUT__ << "Starting constructor for Macro Maker mode." << __E__;
53 
54  xgi::bind(this, &MacroMakerSupervisor::requestIcons, "requestIcons");
55  xgi::bind(this, &MacroMakerSupervisor::verification, "Verify");
56  xgi::bind(this, &MacroMakerSupervisor::tooltipRequest, "TooltipRequest");
57  xgi::bind(this, &MacroMakerSupervisor::requestWrapper, "Request");
58  generateURL();
59  __SUP_COUT__ << "Completed constructor for Macro Maker mode." << __E__;
60  }
61  else
62  __SUP_COUT__ << "Not Macro Maker only mode." << __E__;
63  // end requests for MacroMaker only mode
64 
65  init();
66 
67  __SUP_COUT__ << "Constructed." << __E__;
68 } // end constructor
69 
70 //==============================================================================
71 MacroMakerSupervisor::~MacroMakerSupervisor(void) { destroy(); }
72 
73 //==============================================================================
74 void MacroMakerSupervisor::init(void)
75 {
76  // called by constructor
77 
78  // MacroMaker should consider all FE compatible types..
79  allFESupervisorInfo_ = SupervisorInfoMap( allSupervisorInfo_.getAllFETypeSupervisorInfo() );
80 
81 } // end init()
82 
83 //==============================================================================
84 void MacroMakerSupervisor::destroy(void)
85 {
86  // called by destructor
87 }
88 
89 //==============================================================================
90 // forceSupervisorPropertyValues
91 // override to force supervisor property values (and ignore user settings)
92 void MacroMakerSupervisor::forceSupervisorPropertyValues()
93 {
94  // CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NeedUsernameRequestTypes,
95  // "getPermission");
96 } // end forceSupervisorPropertyValues()
97 
98 //==============================================================================
99 void MacroMakerSupervisor::tooltipRequest(xgi::Input* in, xgi::Output* out)
100 {
101  cgicc::Cgicc cgi(in);
102 
103  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
104  //__COUT__ << "Command = " << Command << __E__;
105 
106  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
107 
108  // SECURITY CHECK START ****
109  if(securityCode_.compare(submittedSequence) != 0)
110  {
111  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
112  << __E__;
113  return;
114  }
115  // else
116  // {
117  // __COUT__ << "***Successfully authenticated security sequence." << __E__;
118  // }
119  // SECURITY CHECK END ****
120 
121  HttpXmlDocument xmldoc;
122 
123  if(Command == "check")
124  {
125  WebUsers::tooltipCheckForUsername(WebUsers::DEFAULT_ADMIN_USERNAME,
126  &xmldoc,
127  CgiDataUtilities::getData(cgi, "srcFile"),
128  CgiDataUtilities::getData(cgi, "srcFunc"),
129  CgiDataUtilities::getData(cgi, "srcId"));
130  }
131  else if(Command == "setNeverShow")
132  {
133  WebUsers::tooltipSetNeverShowForUsername(
134  WebUsers::DEFAULT_ADMIN_USERNAME,
135  &xmldoc,
136  CgiDataUtilities::getData(cgi, "srcFile"),
137  CgiDataUtilities::getData(cgi, "srcFunc"),
138  CgiDataUtilities::getData(cgi, "srcId"),
139  CgiDataUtilities::getData(cgi, "doNeverShow") == "1" ? true : false,
140  CgiDataUtilities::getData(cgi, "temporarySilence") == "1" ? true : false);
141  }
142  else
143  __COUT__ << "Command Request, " << Command << ", not recognized." << __E__;
144 
145  xmldoc.outputXmlDocument((std::ostringstream*)out, false, true);
146 } // end tooltipRequest()
147 
148 //==============================================================================
149 void MacroMakerSupervisor::verification(xgi::Input* in, xgi::Output* out)
150 {
151  cgicc::Cgicc cgi(in);
152  std::string submittedSequence = CgiDataUtilities::getData(cgi, "code");
153  __COUT__ << "submittedSequence=" << submittedSequence << " " << time(0) << __E__;
154 
155  std::string securityWarning = "";
156 
157  if(securityCode_.compare(submittedSequence) != 0)
158  {
159  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
160  << __E__;
161  *out << "Invalid code.";
162  return;
163  }
164  else
165  {
166  // defaultSequence_ = false;
167  __COUT__ << "*** Successfully authenticated security sequence "
168  << "@ " << time(0) << __E__;
169 
170  if(defaultSequence_)
171  {
172  //__COUT__ << " UNSECURE!!!" << __E__;
173  securityWarning = "&secure=False";
174  }
175  }
176 
177  *out << "<!DOCTYPE HTML><html lang='en'><head><title>ots wiz</title>" <<
178  // show ots icon
179  // from http://www.favicon-generator.org/
180  "<link rel='apple-touch-icon' sizes='57x57' href='/WebPath/images/otsdaqIcons/apple-icon-57x57.png'>\
181  <link rel='apple-touch-icon' sizes='60x60' href='/WebPath/images/otsdaqIcons/apple-icon-60x60.png'>\
182  <link rel='apple-touch-icon' sizes='72x72' href='/WebPath/images/otsdaqIcons/apple-icon-72x72.png'>\
183  <link rel='apple-touch-icon' sizes='76x76' href='/WebPath/images/otsdaqIcons/apple-icon-76x76.png'>\
184  <link rel='apple-touch-icon' sizes='114x114' href='/WebPath/images/otsdaqIcons/apple-icon-114x114.png'>\
185  <link rel='apple-touch-icon' sizes='120x120' href='/WebPath/images/otsdaqIcons/apple-icon-120x120.png'>\
186  <link rel='apple-touch-icon' sizes='144x144' href='/WebPath/images/otsdaqIcons/apple-icon-144x144.png'>\
187  <link rel='apple-touch-icon' sizes='152x152' href='/WebPath/images/otsdaqIcons/apple-icon-152x152.png'>\
188  <link rel='apple-touch-icon' sizes='180x180' href='/WebPath/images/otsdaqIcons/apple-icon-180x180.png'>\
189  <link rel='icon' type='image/png' sizes='192x192' href='/WebPath/images/otsdaqIcons/android-icon-192x192.png'>\
190  <link rel='icon' type='image/png' sizes='32x32' href='/WebPath/images/otsdaqIcons/favicon-32x32.png'>\
191  <link rel='icon' type='image/png' sizes='96x96' href='/WebPath/images/otsdaqIcons/favicon-96x96.png'>\
192  <link rel='icon' type='image/png' sizes='16x16' href='/WebPath/images/otsdaqIcons/favicon-16x16.png'>\
193  <link rel='manifest' href='/WebPath/images/otsdaqIcons/manifest.json'>\
194  <meta name='msapplication-TileColor' content='#ffffff'>\
195  <meta name='msapplication-TileImage' content='/ms-icon-144x144.png'>\
196  <meta name='theme-color' content='#ffffff'>"
197  <<
198  // end show ots icon
199  "</head>"
200  << "<frameset col='100%' row='100%'><frame "
201  "src='/WebPath/html/MacroMakerSupervisor.html?urn="
202  << this->getApplicationDescriptor()->getLocalId() << securityWarning
203  << "'></frameset></html>";
204 } // end verification()
205 
206 //==============================================================================
207 void MacroMakerSupervisor::generateURL()
208 {
209  defaultSequence_ = true;
210 
211  int length = 4;
212  FILE* fp = fopen((SEQUENCE_FILE_NAME).c_str(), "r");
213  if(fp)
214  {
215  __SUP_COUT_INFO__ << "Sequence length file found: " << SEQUENCE_FILE_NAME
216  << __E__;
217  char line[100];
218  fgets(line, 100, fp);
219  sscanf(line, "%d", &length);
220  fclose(fp);
221  if(length < 4)
222  length = 4; // don't allow shorter than 4
223  else
224  defaultSequence_ = false;
225  srand(time(0)); // randomize differently each "time"
226  }
227  else
228  {
229  __SUP_COUT_INFO__
230  << "(Reverting to default wiz security) Sequence length file NOT found: "
231  << SEQUENCE_FILE_NAME << __E__;
232  srand(0); // use same seed for convenience if file not found
233  }
234 
235  __SUP_COUT__ << "Sequence length = " << length << __E__;
236 
237  securityCode_ = "";
238 
239  const char alphanum[] =
240  "0123456789"
241  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
242  "abcdefghijklmnopqrstuvwxyz";
243 
244  for(int i = 0; i < length; ++i)
245  {
246  securityCode_ += alphanum[rand() % (sizeof(alphanum) - 1)];
247  }
248 
249  __SUP_COUT__ << __ENV__("HOSTNAME") << ":" << __ENV__("PORT")
250  << "/urn:xdaq-application:lid="
251  << this->getApplicationDescriptor()->getLocalId()
252  << "/Verify?code=" << securityCode_ << __E__;
253 
254  // Note: print out handled by start ots script now
255  // std::thread([&](WizardSupervisor *ptr, std::string securityCode)
256  // {printURL(ptr,securityCode);},this,securityCode_).detach();
257 
258  fp = fopen((SEQUENCE_OUT_FILE_NAME).c_str(), "w");
259  if(fp)
260  {
261  fprintf(fp, "%s", securityCode_.c_str());
262  fclose(fp);
263  }
264  else
265  __SUP_COUT_ERR__ << "Sequence output file NOT found: " << SEQUENCE_OUT_FILE_NAME
266  << __E__;
267 
268  return;
269 } // end generateURL()
270 //==============================================================================
271 void MacroMakerSupervisor::requestIcons(xgi::Input* in, xgi::Output* out)
272 {
273  cgicc::Cgicc cgi(in);
274 
275  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
276 
277  // SECURITY CHECK START ****
278  if(securityCode_.compare(submittedSequence) != 0)
279  {
280  __COUT__ << "Unauthorized Request made, security sequence doesn't match! "
281  << time(0) << __E__;
282  return;
283  }
284  else
285  {
286  __COUT__ << "***Successfully authenticated security sequence. " << time(0)
287  << __E__;
288  }
289  // SECURITY CHECK END ****
290 
291  // an icon is 7 fields.. give comma-separated
292  // 0 - subtext = text below icon
293  // 1 - altText = text for icon if image set to 0
294  // 2 - uniqueWin = if true, only one window is allowed, else multiple instances of
295  // window 3 - permissions = security level needed to see icon 4 - picfn = icon image
296  // filename, 0 for no image 5 - linkurl = url of the window to open 6 - folderPath =
297  // folder and subfolder location
298 
299  *out << "Macro Maker "
300  ",MM,0,1,icon-MacroMaker.png,/WebPath/html/"
301  "MacroMaker.html?urn=290,/"
302  ",FE Macros"
303  ",CFG,0,1,icon-Configure.png,/WebPath/html/"
304  "FEMacroTest.html?urn=290,/"
305  << "";
306 
307  // if there is a file of more icons, add to end of output
308  std::string iconFile = std::string(__ENV__("USER_DATA")) + "/MacroMakerModeIcons.dat";
309  __COUT__ << "Macro Maker mode user icons file: " << iconFile << __E__;
310  FILE* fp = fopen(iconFile.c_str(), "r");
311  if(fp)
312  {
313  __COUT__ << "Macro Maker mode user icons loading from " << iconFile << __E__;
314  fseek(fp, 0, SEEK_END);
315  const unsigned long fileSize = ftell(fp);
316  std::string fileString(fileSize, 0);
317  rewind(fp);
318  if(fread(&fileString[0], 1, fileSize, fp) != fileSize)
319  {
320  __COUT_ERR__ << "Unable to read proper size string from icons file!" << __E__;
321  return;
322  }
323 
324  fclose(fp);
325  __COUTV__(fileString);
326  *out << fileString;
327  }
328  else
329  __COUT__ << "Macro Maker mode user icons file not found: " << iconFile << __E__;
330  return;
331 } // end requestIcons()
332 
333 //==============================================================================
334 // requestWrapper ~
335 // wrapper for handling very-specialized MacroMaker mode Supervisor request call
336 void MacroMakerSupervisor::requestWrapper(xgi::Input* in, xgi::Output* out)
337 {
338  // use default wrapper if not Macro Maker mode
339  if(!CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
340  {
341  //__SUP_COUT__ << "Default request wrapper" << __E__;
342  return CoreSupervisorBase::requestWrapper(in, out);
343  }
344  // else very specialized Macro Maker mode!
345 
346  //__SUP_COUT__ << "MacroMaker mode request handler!" << __E__;
347 
348  // checkSupervisorPropertySetup();
349 
350  cgicc::Cgicc cgiIn(in);
351 
352  std::string submittedSequence = CgiDataUtilities::postData(cgiIn, "sequence");
353 
354  // SECURITY CHECK START ****
355  if(securityCode_.compare(submittedSequence) != 0)
356  {
357  __COUT__ << "Unauthorized Request made, security sequence doesn't match! "
358  << time(0) << __E__;
359  return;
360  }
361  else
362  {
363  __COUT__ << "***Successfully authenticated security sequence. " << time(0)
364  << __E__;
365  }
366  // SECURITY CHECK END ****
367 
368  std::string requestType = CgiDataUtilities::getData(cgiIn, "RequestType");
369 
370  //__SUP_COUT__ << "requestType " << requestType << " files: " <<
371  // cgiIn.getFiles().size() << __E__;
372 
373  HttpXmlDocument xmlOut;
374  WebUsers::RequestUserInfo userInfo(
375  requestType, CgiDataUtilities::getOrPostData(cgiIn, "CookieCode"));
376 
377  CorePropertySupervisorBase::getRequestUserInfo(userInfo);
378 
379  // copied from WebUsers::checkRequestAccess
380  userInfo.username_ = "admin";
381  userInfo.displayName_ = "Admin";
382  userInfo.usernameWithLock_ = "admin";
383  userInfo.activeUserSessionIndex_ = 0;
384 
385  if(1 || !userInfo.automatedCommand_)
386  __SUP_COUT__ << "requestType: " << requestType << __E__;
387 
388  if(userInfo.NonXMLRequestType_)
389  {
390  try
391  {
392  nonXmlRequest(requestType, cgiIn, *out, userInfo);
393  }
394  catch(const std::runtime_error& e)
395  {
396  __SUP_SS__ << "An error was encountered handling requestType '" << requestType
397  << "':" << e.what() << __E__;
398  __SUP_COUT_ERR__ << "\n" << ss.str();
399  __SUP_MOUT_ERR__ << "\n" << ss.str();
400  }
401  catch(...)
402  {
403  __SUP_SS__ << "An unknown error was encountered handling requestType '"
404  << requestType << ".' "
405  << "Please check the printouts to debug." << __E__;
406  __SUP_COUT_ERR__ << "\n" << ss.str();
407  __SUP_MOUT_ERR__ << "\n" << ss.str();
408  }
409  return;
410  }
411  // else xml request type
412 
413  try
414  {
415  // call derived class' request()
416  request(requestType, cgiIn, xmlOut, userInfo);
417  }
418  catch(const std::runtime_error& e)
419  {
420  __SUP_SS__ << "An error was encountered handling requestType '" << requestType
421  << "':" << e.what() << __E__;
422  __SUP_COUT_ERR__ << "\n" << ss.str();
423  xmlOut.addTextElementToData("Error", ss.str());
424  }
425  catch(...)
426  {
427  __SUP_SS__ << "An unknown error was encountered handling requestType '"
428  << requestType << ".' "
429  << "Please check the printouts to debug." << __E__;
430  __SUP_COUT_ERR__ << "\n" << ss.str();
431  xmlOut.addTextElementToData("Error", ss.str());
432  }
433 
434  // report any errors encountered
435  {
436  unsigned int occurance = 0;
437  std::string err = xmlOut.getMatchingValue("Error", occurance++);
438  while(err != "")
439  {
440  __SUP_COUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err
441  << __E__;
442  __SUP_MOUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err
443  << __E__;
444  err = xmlOut.getMatchingValue("Error", occurance++);
445  }
446  }
447 
448  // return xml doc holding server response
449  xmlOut.outputXmlDocument((std::ostringstream*)out,
450  false /*print to cout*/,
451  !userInfo.NoXmlWhiteSpace_ /*allow whitespace*/);
452 } // end requestWrapper()
453 
454 //==============================================================================
455 void MacroMakerSupervisor::request(const std::string& requestType,
456  cgicc::Cgicc& cgiIn,
457  HttpXmlDocument& xmlOut,
458  const WebUsers::RequestUserInfo& userInfo) try
459 {
460  // sanitize username
461  std::string username = "";
462  for(unsigned int i = 0; i < userInfo.username_.size(); ++i)
463  if((userInfo.username_[i] >= 'a' && userInfo.username_[i] <= 'z') ||
464  (userInfo.username_[i] >= 'A' && userInfo.username_[i] <= 'Z') ||
465  (userInfo.username_[i] >= '0' && userInfo.username_[i] <= '9') ||
466  userInfo.username_[i] >= '-' || userInfo.username_[i] <= '_')
467  username += userInfo.username_[i];
468 
469  if(username.size() < 2)
470  {
471  __SUP_SS__ << "Illegal username '" << userInfo.username_ << "' received."
472  << __E__;
473  __SUP_SS_THROW__;
474  }
475 
476  __SUP_COUT__ << "User name is " << userInfo.username_ << "." << __E__;
477  __SUP_COUT__ << "User permission level for request '" << requestType << "' is "
478  << unsigned(userInfo.permissionLevel_) << "." << __E__;
479 
480  // handle request per requestType
481  if(requestType == "getPermission")
482  {
483  xmlOut.addTextElementToData("Permission",
484  std::to_string(unsigned(userInfo.permissionLevel_)));
485 
486  // create macro maker folders for the user (the first time a user authenticates
487  // with macro maker)
488  std::string macroPath = (std::string)MACROS_DB_PATH + userInfo.username_ + "/";
489  mkdir(macroPath.c_str(), 0755);
490  std::string histPath = (std::string)MACROS_HIST_PATH + userInfo.username_ + "/";
491  mkdir(histPath.c_str(), 0755);
492  std::string publicPath = (std::string)MACROS_DB_PATH + "publicMacros/";
493  mkdir(publicPath.c_str(), 0755);
494  std::string exportPath =
495  __ENV__("SERVICE_DATA_PATH") + MACROS_EXPORT_PATH + userInfo.username_ + "/";
496  mkdir(exportPath.c_str(), 0755);
497  }
498  else
499  handleRequest(requestType, xmlOut, cgiIn, userInfo.username_);
500 } // end request()
501 catch(const std::runtime_error& e)
502 {
503  __SS__ << "Error occurred handling request '" << requestType << "': " << e.what()
504  << __E__;
505  __SUP_COUT__ << ss.str();
506  xmlOut.addTextElementToData("Error", ss.str());
507 }
508 catch(...)
509 {
510  __SS__ << "Unknown error occurred handling request '" << requestType << "!'" << __E__;
511  __SUP_COUT__ << ss.str();
512  xmlOut.addTextElementToData("Error", ss.str());
513 } // end request() error handling
514 
515 //==============================================================================
516 void MacroMakerSupervisor::handleRequest(const std::string Command,
517  HttpXmlDocument& xmldoc,
518  cgicc::Cgicc& cgi,
519  const std::string& username)
520 {
521  if(Command == "FElist") // called by MacroMaker GUI
522  getFElist(xmldoc);
523  else if(Command == "writeData") // called by MacroMaker GUI
524  writeData(xmldoc, cgi, username);
525  else if(Command == "readData") // called by MacroMaker GUI
526  readData(xmldoc, cgi, username);
527  else if(Command == "createMacro") // called by MacroMaker GUI
528  createMacro(xmldoc, cgi, username);
529  else if(Command == "loadMacros") // called by MacroMaker GUI
530  loadMacros(xmldoc, username);
531  else if(Command == "loadHistory") // called by MacroMaker GUI
532  loadHistory(xmldoc, username);
533  else if(Command == "deleteMacro") // called by MacroMaker GUI
534  deleteMacro(xmldoc, cgi, username);
535  else if(Command == "editMacro") // called by MacroMaker GUI
536  editMacro(xmldoc, cgi, username);
537  else if(Command == "clearHistory") // called by MacroMaker GUI
538  clearHistory(username);
539  else if(Command == "exportMacro") // called by MacroMaker GUI
540  exportMacro(xmldoc, cgi, username);
541  else if(Command == "exportFEMacro") // called by MacroMaker GUI
542  exportFEMacro(xmldoc, cgi, username);
543  else if(Command == "getFEMacroList") // called by FE Macro Test and returns FE Macros
544  // and Macro Maker Macros
545  getFEMacroList(xmldoc, username);
546  else if(Command == "runFEMacro") // called by FE Macro Test returns FE Macros and
547  // Macro Maker Macros
548  runFEMacro(xmldoc, cgi, username);
549  else
550  xmldoc.addTextElementToData("Error", "Unrecognized command '" + Command + "'");
551 } // end handleRequest()
552 
553 //==============================================================================
554 xoap::MessageReference MacroMakerSupervisor::frontEndCommunicationRequest(
555  xoap::MessageReference message) try
556 {
557  __SUP_COUT__ << "FE Request received: " << SOAPUtilities::translate(message) << __E__;
558 
559  SOAPParameters typeParameter, rxParameters; // params for xoap to recv
560  typeParameter.addParameter("type");
561  SOAPUtilities::receive(message, typeParameter);
562 
563  std::string type = typeParameter.getValue("type");
564 
565  std::string error = "";
566 
567  if(type == "initFElist") // gateway initializes during configure
568  {
569  __SUP_COUTV__(type);
570 
571  rxParameters.addParameter("groupName");
572  rxParameters.addParameter("groupKey");
573  SOAPUtilities::receive(message, rxParameters);
574 
575  std::string groupName = rxParameters.getValue("groupName");
576  std::string groupKey = rxParameters.getValue("groupKey");
577 
578  __SUP_COUTV__(groupName);
579  __SUP_COUTV__(groupKey);
580 
581  ConfigurationManager cfgMgr;
582  cfgMgr.loadTableGroup(groupName, TableGroupKey(groupKey), true);
583 
584  // for each FESupervisor
585  // get all front end children
586 
587  const SupervisorInfoMap& feTypeSupervisors =
588  CorePropertySupervisorBase::allSupervisorInfo_.getAllFETypeSupervisorInfo();
589 
590  ConfigurationTree appsNode =
591  cfgMgr.getNode(ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME);
592 
593  __SUP_COUT__ << "Number of FE Supervisors found = " << feTypeSupervisors.size()
594  << __E__;
595 
596  FEPluginTypetoFEsMap_.clear(); // reset
597  FEtoSupervisorMap_.clear(); // reset
598  FEtoPluginTypeMap_.clear(); // reset
599  for(auto& feApp : feTypeSupervisors)
600  {
601  __SUP_COUT__ << "FEs for app " << feApp.first << ":" << feApp.second.getName()
602  << __E__;
603 
604  auto feChildren = appsNode.getNode(feApp.second.getName())
605  .getNode("LinkToSupervisorTable")
606  .getNode("LinkToFEInterfaceTable")
607  .getChildren();
608 
609  for(auto& fe : feChildren)
610  {
611  __SUP_COUTV__(fe.first);
612  FEtoSupervisorMap_[fe.first] = feApp.first;
613 
614  std::string pluginType =
615  fe.second.getNode("FEInterfacePluginName").getValue();
616  FEPluginTypetoFEsMap_[pluginType].emplace(fe.first);
617  FEtoPluginTypeMap_[fe.first] = pluginType;
618  }
619  }
620 
621  __SUP_COUTV__(StringMacros::mapToString(FEtoSupervisorMap_));
622  __SUP_COUTV__(StringMacros::mapToString(FEPluginTypetoFEsMap_));
623  __SUP_COUTV__(StringMacros::mapToString(FEtoPluginTypeMap_));
624  }
625  else if(type == "feSend" || // from front-ends
626  type == "feMacro" || // from front-ends
627  type == "feMacroMultiDimensionalStart" || // from iterator
628  type == "feMacroMultiDimensionalCheck" || // from iterator
629  type == "macroMultiDimensionalStart" || // from iterator
630  type == "macroMultiDimensionalCheck") // from iterator
631  {
632  __SUP_COUTV__(type);
633 
634  rxParameters.addParameter("targetInterfaceID");
635  SOAPUtilities::receive(message, rxParameters);
636 
637  std::string targetInterfaceID = rxParameters.getValue("targetInterfaceID");
638 
639  __SUP_COUTV__(targetInterfaceID);
640 
641  auto feIt = FEtoSupervisorMap_.find(targetInterfaceID);
642  if(feIt == FEtoSupervisorMap_.end())
643  {
644  __SUP_SS__ << "Destination front end interface ID '" << targetInterfaceID
645  << "' was not found in the list of front ends." << __E__;
646  __SUP_SS_THROW__;
647  }
648 
649  unsigned int FESupervisorIndex = feIt->second;
650  __SUP_COUT__ << "Found supervisor index: " << FESupervisorIndex << __E__;
651 
652  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
653  if(it == allFESupervisorInfo_.end())
654  {
655  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
656  << targetInterfaceID << ":" << FESupervisorIndex << ".' \n\n"
657  << "The FE Supervisor Index does not exist. Have you configured "
658  "the state machine properly?"
659  << __E__;
660  __SUP_SS_THROW__;
661  }
662 
663  if(type == "macroMultiDimensionalStart")
664  {
665  // add Macro sequence (and check macro exists)
666 
667  SOAPParameters rxParameters;
668  rxParameters.addParameter("macroName");
669  SOAPUtilities::receive(message, rxParameters);
670  std::string macroName = rxParameters.getValue("macroName");
671  __SUP_COUTV__(macroName);
672 
673  std::string macroString;
674  loadMacro(macroName, macroString);
675 
676  SOAPParameters parameters;
677  parameters.addParameter("macroString", macroString);
678  SOAPUtilities::addParameters(message, parameters);
679  }
680 
681  try
682  {
683  __SUP_COUT__ << "Forwarding request: " << SOAPUtilities::translate(message)
684  << __E__;
685 
686  xoap::MessageReference replyMessage =
687  SOAPMessenger::sendWithSOAPReply(it->second.getDescriptor(), message);
688 
689  if(type != "feSend")
690  {
691  __SUP_COUT__ << "Forwarding FE Macro response: "
692  << SOAPUtilities::translate(replyMessage) << __E__;
693 
694  return replyMessage;
695  }
696  }
697  catch(const xdaq::exception::Exception& e)
698  {
699  __SUP_SS__ << "Error forwarding FE Communication request to FE Supervisor '"
700  << targetInterfaceID << ":" << FESupervisorIndex << ".' "
701  << "Have you configured the state machine properly?\n\n"
702  << e.what() << __E__;
703  __SUP_SS_THROW__;
704  }
705  }
706  else
707  {
708  __SUP_SS__ << "Unrecognized FE Communication type: " << type << __E__;
709  __SUP_SS_THROW__;
710  }
711 
712  return SOAPUtilities::makeSOAPMessageReference("Received");
713 } // end frontEndCommunicationRequest()
714 catch(const std::runtime_error& e)
715 {
716  __SUP_SS__ << "Error processing FE communication request: " << e.what() << __E__;
717  __SUP_COUT_ERR__ << ss.str();
718 
719  xoap::MessageReference returnMessage =
720  SOAPUtilities::makeSOAPMessageReference("Error");
721 
722  SOAPParameters parameters;
723  parameters.addParameter("Error", ss.str());
724  SOAPUtilities::addParameters(returnMessage, parameters);
725  return returnMessage;
726 }
727 catch(...)
728 {
729  xoap::MessageReference returnMessage =
730  SOAPUtilities::makeSOAPMessageReference("Error");
731 
732  __SUP_SS__ << "Unknown error processing FE communication request." << __E__;
733  __SUP_COUT_ERR__ << ss.str();
734 
735  SOAPParameters parameters;
736  parameters.addParameter("Error", ss.str());
737  SOAPUtilities::addParameters(returnMessage, parameters);
738  return returnMessage;
739 } // end frontEndCommunicationRequest() catch
740 
741 //==============================================================================
742 void MacroMakerSupervisor::getFElist(HttpXmlDocument& xmldoc)
743 {
744  __SUP_COUT__ << "Getting FE list!!!!!!!!!" << __E__;
745 
746  SOAPParameters txParameters; // params for xoap to send
747  txParameters.addParameter("Request", "GetInterfaces");
748 
749  SOAPParameters rxParameters; // params for xoap to recv
750  rxParameters.addParameter("FEList");
751  rxParameters.addParameter(
752  "frontEndError"); // if there were errors recorded (during
753  // configuration, e.g. in Macro Maker only
754  // mode)
755 
756  SupervisorInfoMap::const_iterator it;
757  std::string oneInterface;
758  std::string rxFEList;
759  std::string rxFrontEndError;
760 
761  size_t lastColonIndex;
762 
763  // for each list of FE Supervisors,
764  // loop through each FE Supervisors and get FE interfaces list
765  for(auto& appInfo : allFESupervisorInfo_)
766  {
767  // __SUP_COUT__ << "Number of " << listPair.first << " = " <<
768  // listPair.second.size() << __E__;
769  //
770  // for (it = listPair.second.begin(); it != listPair.second.end(); it++)
771  // {
772 
773  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId()
774  << " name = " << appInfo.second.getName() << __E__;
775 
776  try
777  {
778  xoap::MessageReference retMsg =
779  SOAPMessenger::sendWithSOAPReply(appInfo.second.getDescriptor(),
780  "MacroMakerSupervisorRequest",
781  txParameters);
782  SOAPUtilities::receive(retMsg, rxParameters);
783  }
784  catch(const xdaq::exception::Exception& e)
785  {
786  __SUP_SS__ << "Error transmitting request to FE Supervisor LID = "
787  << appInfo.second.getId() << " name = " << appInfo.second.getName()
788  << ". \n\n"
789  << e.what() << __E__;
790  __SUP_SS_THROW__;
791  }
792 
793  rxFEList = rxParameters.getValue("FEList");
794  rxFrontEndError = rxParameters.getValue("frontEndError");
795 
796  __SUP_COUT__ << "FE List received: \n" << rxFEList << __E__;
797 
798  if(rxFrontEndError != "")
799  {
800  __SUP_SS__ << "FE Errors received: \n" << rxFrontEndError << __E__;
801  __SUP_SS_THROW__;
802  }
803 
804  std::istringstream allInterfaces(rxFEList);
805  while(std::getline(allInterfaces, oneInterface))
806  {
807  __SUP_COUTV__(oneInterface);
808  xmldoc.addTextElementToData("FE", oneInterface);
809 
810  lastColonIndex = oneInterface.rfind(':');
811  if(lastColonIndex == std::string::npos)
812  {
813  __SUP_SS__ << "Last colon could not be found in " << oneInterface
814  << __E__;
815  __SUP_SS_THROW__;
816  }
817  oneInterface = oneInterface.substr(lastColonIndex);
818 
819  __SUP_COUTV__(oneInterface);
820  } // end FE extract loop
821 
822  } // end ask Supervisors for their FE list loop
823 
824 } // end getFEList()
825 
826 //==============================================================================
827 void MacroMakerSupervisor::writeData(HttpXmlDocument& /*xmldoc*/,
828  cgicc::Cgicc& cgi,
829  const std::string& username)
830 {
831  __SUP_COUT__ << "MacroMaker writing..." << __E__;
832 
833  std::string Address = CgiDataUtilities::getData(cgi, "Address");
834  std::string Data = CgiDataUtilities::getData(cgi, "Data");
835  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
836  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
837  std::string time =
838  StringMacros::decodeURIComponent(CgiDataUtilities::getData(cgi, "time"));
839  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
840  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
841 
842  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
843 
844  __SUP_COUT__ << "Write Address: " << Address << " Data: " << Data << __E__;
845  __SUP_COUTV__(interfaces);
846 
847  std::string command = "w:" + Address + ":" + Data;
848  std::string format = addressFormatStr + ":" + dataFormatStr;
849  appendCommandToHistory(command, format, time, interfaces, username);
850 
851  SOAPParameters txParameters; // params for xoap to send
852  txParameters.addParameter("Request", "UniversalWrite");
853  txParameters.addParameter("Address", Address);
854  txParameters.addParameter("Data", Data);
855 
856  __SUP_COUT__ << "Here comes the array from multiselect box for WRITE, behold: \n"
857  << supervisorIndexArray << "\n"
858  << interfaceIndexArray << __E__;
859 
862  std::vector<std::string> interfaceIndices;
863  std::istringstream f(interfaceIndexArray);
864  std::string s;
865  while(getline(f, s, ','))
866  interfaceIndices.push_back(s);
867  std::vector<int> supervisorIndices;
868  std::istringstream g(supervisorIndexArray);
869  std::string t;
870  while(getline(g, t, ','))
871  supervisorIndices.push_back(std::stoi(t));
872 
873  for(unsigned int i = 0; i < supervisorIndices.size(); i++)
874  {
875  unsigned int FESupervisorIndex = supervisorIndices[i];
876  std::string interfaceIndex = interfaceIndices[i];
877 
878  txParameters.addParameter("InterfaceID", interfaceIndex);
879 
880  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex
881  << __E__;
882  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
883 
884  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
885  if(it == allFESupervisorInfo_.end())
886  {
887  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
888  << interfaceIndex << ":" << FESupervisorIndex << ".' \n\n"
889  << "The FE Index doesn't exist. Have you configured the state "
890  "machine properly?"
891  << __E__;
892  __SUP_SS_THROW__;
893  }
894 
895  try
896  {
897  xoap::MessageReference replyMessage = SOAPMessenger::sendWithSOAPReply(
898  it->second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
899 
900  __SUP_COUT__ << "Response received: "
901  << SOAPUtilities::translate(replyMessage) << __E__;
902 
903  SOAPParameters rxParameters;
904  rxParameters.addParameter("Error");
905  SOAPUtilities::receive(replyMessage, rxParameters);
906 
907  std::string error = rxParameters.getValue("Error");
908  __SUP_COUTV__(error);
909 
910  if(error != "")
911  {
912  // error occurred!
913  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
914  << interfaceIndex << ":" << FESupervisorIndex << ".' "
915  << "Have you configured the state machine properly?\n\n"
916  << error << __E__;
917  __SUP_SS_THROW__;
918  }
919  }
920  catch(const xdaq::exception::Exception& e)
921  {
922  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
923  << interfaceIndex << ":" << FESupervisorIndex << ".' "
924  << "Have you configured the state machine properly?\n\n"
925  << e.what() << __E__;
926  __SUP_SS_THROW__;
927  }
928 
929  } // end FE Supervisor loop
930 } // end writeData()
931 
932 //==============================================================================
933 void MacroMakerSupervisor::readData(HttpXmlDocument& xmldoc,
934  cgicc::Cgicc& cgi,
935  const std::string& username)
936 {
937  __SUP_COUT__ << "@@@@@@@ MacroMaker wants to read data @@@@@@@@" << __E__;
938  std::string Address = CgiDataUtilities::getData(cgi, "Address");
939  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
940  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
941  std::string time =
942  StringMacros::decodeURIComponent(CgiDataUtilities::getData(cgi, "time"));
943  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
944  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
945 
946  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
947 
948  __SUP_COUT__ << "Read Address: " << Address << __E__;
949  __SUP_COUTV__(interfaces);
950 
951  SOAPParameters txParameters; // params for xoap to send
952  txParameters.addParameter("Request", "UniversalRead");
953  txParameters.addParameter("Address", Address);
954 
955  SOAPParameters rxParameters;
956  rxParameters.addParameter("dataResult");
957  rxParameters.addParameter("Error");
958  __SUP_COUT__ << "Here comes the array from multiselect box for READ, behold: "
959  << supervisorIndexArray << "," << interfaceIndexArray << __E__;
960 
963  std::vector<std::string> interfaceIndices;
964  std::istringstream f(interfaceIndexArray);
965  std::string s;
966  while(getline(f, s, ','))
967  interfaceIndices.push_back(s);
968  std::vector<int> supervisorIndices;
969  std::istringstream g(supervisorIndexArray);
970  std::string t;
971  while(getline(g, t, ','))
972  supervisorIndices.push_back(std::stoi(t));
973 
974  for(unsigned int i = 0; i < supervisorIndices.size(); i++)
975  {
976  unsigned int FESupervisorIndex = supervisorIndices[i];
977  std::string interfaceIndex = interfaceIndices[i];
978 
979  txParameters.addParameter("InterfaceID", interfaceIndex);
980 
981  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex
982  << __E__;
983  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
984 
985  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
986  if(it == allFESupervisorInfo_.end())
987  {
988  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
989  << interfaceIndex << ":" << FESupervisorIndex << ".' \n\n"
990  << "The FE Index doesn't exist. Have you configured the state "
991  "machine properly?"
992  << __E__;
993  __SUP_SS_THROW__;
994  }
995 
996  try
997  {
998  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
999  it->second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
1000 
1001  __SUP_COUT__ << "Response received: " << SOAPUtilities::translate(retMsg)
1002  << __E__;
1003 
1004  // SOAPParameters rxParameters;
1005  // rxParameters.addParameter("Error");
1006  SOAPUtilities::receive(retMsg, rxParameters);
1007 
1008  std::string error = rxParameters.getValue("Error");
1009  __SUP_COUTV__(error);
1010 
1011  if(error != "")
1012  {
1013  // error occurred!
1014  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1015  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1016  << "Have you configured the state machine properly?\n\n"
1017  << error << __E__;
1018  __SUP_SS_THROW__;
1019  }
1020  }
1021  catch(const xdaq::exception::Exception& e)
1022  {
1023  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1024  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1025  << "Have you configured the state machine properly?\n\n"
1026  << e.what() << __E__;
1027  __SUP_SS_THROW__;
1028  }
1029 
1030  std::string dataReadResult = rxParameters.getValue("dataResult");
1031  __SUP_COUT__ << "Data reading result received: " << dataReadResult << __E__;
1032  xmldoc.addTextElementToData("readData", dataReadResult);
1033  std::string command = "r:" + Address + ":" + dataReadResult;
1034  std::string format = addressFormatStr + ":" + dataFormatStr;
1035  appendCommandToHistory(command, format, time, interfaces, username);
1036  }
1037 }
1038 
1039 //==============================================================================
1040 void MacroMakerSupervisor::createMacro(HttpXmlDocument& /*xmldoc*/,
1041  cgicc::Cgicc& cgi,
1042  const std::string& username)
1043 {
1044  __SUP_COUT__ << "MacroMaker wants to create a macro!!!!!!!!!" << __E__;
1045  std::string Name = CgiDataUtilities::postData(cgi, "Name");
1046  std::string Sequence = CgiDataUtilities::postData(cgi, "Sequence");
1047  std::string Time = CgiDataUtilities::postData(cgi, "Time");
1048  std::string Notes =
1049  StringMacros::decodeURIComponent(CgiDataUtilities::postData(cgi, "Notes"));
1050  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
1051  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
1052 
1053  __SUP_COUTV__(Name);
1054  __SUP_COUTV__(Sequence);
1055  __SUP_COUTV__(Notes);
1056  __SUP_COUTV__(Time);
1057  __SUP_COUTV__(isMacroPublic);
1058  __SUP_COUTV__(isMacroLSBF);
1059 
1060  __SUP_COUTV__(MACROS_DB_PATH);
1061 
1062  std::string fileName = Name + ".dat";
1063  std::string fullPath;
1064  if(isMacroPublic == "true")
1065  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
1066  else
1067  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
1068 
1069  __SUP_COUTV__(fullPath);
1070 
1071  std::ofstream macrofile(fullPath.c_str());
1072  if(macrofile.is_open())
1073  {
1074  macrofile << "{\n";
1075  macrofile << "\"name\":\"" << Name << "\",\n";
1076  macrofile << "\"sequence\":\"" << Sequence << "\",\n";
1077  macrofile << "\"time\":\"" << Time << "\",\n";
1078  macrofile << "\"notes\":\"" << Notes << "\",\n";
1079  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
1080  macrofile << "}@" << __E__;
1081  macrofile.close();
1082  }
1083  else
1084  __SUP_COUT__ << "Unable to open file" << __E__;
1085 } // end createMacro()
1086 
1087 //==============================================================================
1088 // loadMacro
1089 // Load macro string from file.
1090 // look in public macros and username (if given)
1091 // for the macroName.
1092 //
1093 // If found, return by reference
1094 // Else, throw exception
1095 void MacroMakerSupervisor::loadMacro(const std::string& macroName,
1096  std::string& macroString,
1097  const std::string& username /*=""*/)
1098 {
1099  __SUP_COUTV__(macroName);
1100 
1101  // first check public folder, then user
1102  std::string fullPath, line;
1103  macroString = "";
1104  for(unsigned int i = 0; i < 2; ++i)
1105  {
1106  if(i == 1)
1107  fullPath = (std::string)MACROS_DB_PATH + username + "/";
1108  else
1109  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1110 
1111  fullPath += macroName;
1112  if(macroName.find(".dat") != macroName.size() - 4)
1113  fullPath += ".dat";
1114  __SUP_COUTV__(fullPath);
1115 
1116  std::ifstream read(fullPath.c_str()); // reading a file
1117  if(read.is_open())
1118  {
1119  while(!read.eof())
1120  {
1121  getline(read, line);
1122  macroString += line;
1123  }
1124 
1125  read.close();
1126  }
1127  else // file does not exist
1128  {
1129  __SUP_COUT__ << "Unable to open file: " << fullPath << __E__;
1130  continue;
1131  }
1132 
1133  if(macroString != "")
1134  break; // macro has been found!
1135  } // end load from path loop
1136 
1137  if(macroString == "")
1138  {
1139  __SUP_SS__ << "Unable to locate file for macro '" << macroName
1140  << "'... does it exist?" << __E__;
1141  if(username != "")
1142  ss << " Attempted username was '" << username << ".'" << __E__;
1143  __SUP_SS_THROW__;
1144  }
1145 
1146  __SUP_COUTV__(macroString);
1147 } // end loadMacro()
1148 
1149 //==============================================================================
1150 void MacroMakerSupervisor::loadMacroNames(
1151  const std::string& username,
1152  std::pair<std::vector<std::string> /*public macros*/,
1153  std::vector<std::string> /*private macros*/>& returnMacroNames)
1154 {
1155  DIR* dir;
1156  struct dirent* ent;
1157  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
1158  if((dir = opendir(fullPath.c_str())) != NULL)
1159  {
1160  /* print all the files and directories within directory */
1161  while((ent = readdir(dir)) != NULL)
1162  {
1163  /* File name validation check */
1164  if((unsigned)strlen(ent->d_name) > 4)
1165  {
1166  std::string line;
1167  std::ifstream read(
1168  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1169  if(read.is_open())
1170  {
1171  read.close();
1172  // private macro found
1173  returnMacroNames.second.push_back(ent->d_name);
1174  }
1175  else
1176  __SUP_COUT__ << "Unable to open file" << __E__;
1177  }
1178  }
1179  closedir(dir);
1180  }
1181  else
1182  {
1183  __SUP_COUT__ << "Looping through privateMacros folder failed! Wrong directory"
1184  << __E__;
1185  }
1186  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1187  if((dir = opendir(fullPath.c_str())) != NULL)
1188  {
1189  /* print all the files and directories within directory */
1190  while((ent = readdir(dir)) != NULL)
1191  {
1192  /* File name validation check */
1193  if((unsigned)strlen(ent->d_name) > 4)
1194  {
1195  std::string line;
1196  std::ifstream read(
1197  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1198  if(read.is_open())
1199  {
1200  // public macro found
1201  returnMacroNames.first.push_back(ent->d_name);
1202  read.close();
1203  }
1204  else
1205  __SUP_COUT__ << "Unable to open file" << __E__;
1206  }
1207  }
1208  closedir(dir);
1209  }
1210  else
1211  {
1212  __SUP_COUT__ << fullPath << __E__;
1213  __SUP_COUT__ << "Looping through MacroData folder failed! Wrong directory"
1214  << __E__;
1215  }
1216 
1217 } // end loadMacroNames
1218 
1219 //==============================================================================
1220 void MacroMakerSupervisor::loadMacros(HttpXmlDocument& xmldoc,
1221  const std::string& username)
1222 {
1223  DIR* dir;
1224  struct dirent* ent;
1225  std::string returnStr = "";
1226  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
1227  if((dir = opendir(fullPath.c_str())) != NULL)
1228  {
1229  /* print all the files and directories within directory */
1230  while((ent = readdir(dir)) != NULL)
1231  {
1232  /* File name validation check */
1233  if((unsigned)strlen(ent->d_name) > 4)
1234  {
1235  std::string line;
1236  std::ifstream read(
1237  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1238  if(read.is_open())
1239  {
1240  std::stringstream buffer;
1241  while(!read.eof())
1242  {
1243  getline(read, line);
1244  buffer << line;
1245  //__SUP_COUT__ << line << __E__;
1246  }
1247  returnStr += buffer.str();
1248 
1249  read.close();
1250  }
1251  else
1252  __SUP_COUT__ << "Unable to open file" << __E__;
1253  }
1254  }
1255  std::string returnMacroStr = returnStr.substr(0, returnStr.size() - 1);
1256 
1257  __SUP_COUT__ << "Loading existing macros! " << returnMacroStr << __E__;
1258 
1259  closedir(dir);
1260  xmldoc.addTextElementToData("returnMacroStr", returnMacroStr);
1261  }
1262  else
1263  {
1264  __SUP_COUT__ << "Looping through privateMacros folder failed! Wrong directory"
1265  << __E__;
1266  }
1267  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1268  returnStr = "";
1269  if((dir = opendir(fullPath.c_str())) != NULL)
1270  {
1271  /* print all the files and directories within directory */
1272  while((ent = readdir(dir)) != NULL)
1273  {
1274  /* File name validation check */
1275  if((unsigned)strlen(ent->d_name) > 4)
1276  {
1277  std::string line;
1278  std::ifstream read(
1279  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1280  if(read.is_open())
1281  {
1282  std::stringstream buffer;
1283  while(!read.eof())
1284  {
1285  getline(read, line);
1286  buffer << line;
1287  //__SUP_COUT__ << line << __E__;
1288  }
1289  returnStr += buffer.str();
1290  read.close();
1291  }
1292  else
1293  __SUP_COUT__ << "Unable to open file" << __E__;
1294  }
1295  }
1296  std::string returnPublicStr = returnStr.substr(0, returnStr.size() - 1);
1297  __SUP_COUT__ << "Loading existing public macros: " << returnPublicStr << __E__;
1298  closedir(dir);
1299  xmldoc.addTextElementToData("returnPublicStr", returnPublicStr);
1300  }
1301  else
1302  {
1303  __SUP_COUT__ << fullPath << __E__;
1304  __SUP_COUT__ << "Looping through MacroData folder failed! Wrong directory"
1305  << __E__;
1306  }
1307 } // end loadMacros()
1308 
1309 //==============================================================================
1310 void MacroMakerSupervisor::appendCommandToHistory(std::string Command,
1311  std::string Format,
1312  std::string Time,
1313  std::string Interfaces,
1314  const std::string& username)
1315 {
1316  std::string fileName = "history.hist";
1317  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
1318  __SUP_COUT__ << fullPath << __E__;
1319  std::ofstream histfile(fullPath.c_str(), std::ios::app);
1320  if(histfile.is_open())
1321  {
1322  histfile << "{\n";
1323  histfile << "\"Command\":\"" << Command << "\",\n";
1324  histfile << "\"Format\":\"" << Format << "\",\n";
1325  histfile << "\"Time\":\"" << Time << "\",\n";
1326  histfile << "\"Interfaces\":\"" << Interfaces << "\"\n";
1327  histfile << "}#" << __E__;
1328  histfile.close();
1329  }
1330  else
1331  __SUP_COUT__ << "Unable to open history.hist" << __E__;
1332 }
1333 
1334 //==============================================================================
1335 void MacroMakerSupervisor::loadHistory(HttpXmlDocument& xmldoc,
1336  const std::string& username)
1337 {
1338  std::string fileName = MACROS_HIST_PATH + username + "/" + "history.hist";
1339 
1340  std::ifstream read(fileName.c_str()); // reading a file
1341  __SUP_COUT__ << fileName << __E__;
1342 
1343  if(read.is_open())
1344  {
1345  std::string line;
1346  char* returnStr;
1347  unsigned long long fileSz, i = 0, MAX_HISTORY_SIZE = 100000;
1348 
1349  // get length of file to reserve the string size
1350  // and to cap history size
1351  read.seekg(0, std::ios::end);
1352  fileSz = read.tellg();
1353  returnStr = new char[fileSz + 1];
1354  returnStr[fileSz] = '\0';
1355  read.seekg(0, std::ios::beg);
1356 
1357  // read data as a block:
1358  read.read(returnStr, fileSz);
1359  read.close();
1360 
1361  // find i such that new string size is less than
1362  if(fileSz > MAX_HISTORY_SIZE)
1363  {
1364  i = fileSz - MAX_HISTORY_SIZE;
1365  for(; i < fileSz; ++i)
1366  if(returnStr[i] == '#')
1367  {
1368  i += 2;
1369  break; // skip new line character also to get to next record
1370  }
1371  if(i > fileSz)
1372  i = fileSz;
1373 
1374  // write back to file truncated history
1375  FILE* fp = fopen(fileName.c_str(), "w");
1376  if(!fp)
1377  {
1378  __SS__ << "Big problem with macromaker history file: " << fileName
1379  << __E__;
1380  __SS_THROW__;
1381  }
1382  fwrite(&returnStr[i], fileSz - i, 1, fp);
1383  fclose(fp);
1384  }
1385 
1386  __SUP_COUT__ << "Loading user history! " << __E__;
1387 
1388  if(fileSz > 1)
1389  returnStr[fileSz - 2] = '\0'; // remove final newline and last #
1390 
1391  xmldoc.addTextElementToData("returnHistStr", &returnStr[i]);
1392 
1393  delete[] returnStr;
1394  }
1395  else
1396 
1397  __SUP_COUT__ << "Unable to open history.hist" << __E__;
1398 }
1399 
1400 //==============================================================================
1401 void MacroMakerSupervisor::deleteMacro(HttpXmlDocument& xmldoc,
1402  cgicc::Cgicc& cgi,
1403  const std::string& username)
1404 {
1405  std::string MacroName = CgiDataUtilities::getData(cgi, "MacroName");
1406  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
1407 
1408  std::string fileName = MacroName + ".dat";
1409  std::string fullPath;
1410  if(isMacroPublic == "true")
1411  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
1412  else
1413  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
1414 
1415  __SUP_COUT__ << fullPath << __E__;
1416 
1417  std::remove(fullPath.c_str());
1418  __SUP_COUT__ << "Successfully deleted " << MacroName;
1419  xmldoc.addTextElementToData("deletedMacroName", MacroName);
1420 }
1421 
1422 //==============================================================================
1423 void MacroMakerSupervisor::editMacro(HttpXmlDocument& xmldoc,
1424  cgicc::Cgicc& cgi,
1425  const std::string& username)
1426 {
1427  std::string oldMacroName = CgiDataUtilities::postData(cgi, "oldMacroName");
1428  std::string newMacroName = CgiDataUtilities::postData(cgi, "newMacroName");
1429  std::string Sequence = CgiDataUtilities::postData(cgi, "Sequence");
1430  std::string Time = CgiDataUtilities::postData(cgi, "Time");
1431  std::string Notes =
1432  StringMacros::decodeURIComponent(CgiDataUtilities::postData(cgi, "Notes"));
1433 
1434  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
1435  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
1436 
1437  __SUP_COUTV__(oldMacroName);
1438  __SUP_COUTV__(newMacroName);
1439  __SUP_COUTV__(Sequence);
1440  __SUP_COUTV__(Notes);
1441  __SUP_COUTV__(Time);
1442  __SUP_COUTV__(isMacroPublic);
1443  __SUP_COUTV__(isMacroLSBF);
1444 
1445  __SUP_COUTV__(MACROS_DB_PATH);
1446 
1447  std::string fileName = oldMacroName + ".dat";
1448  std::string fullPath;
1449  if(isMacroPublic == "true")
1450  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
1451  else
1452  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
1453 
1454  __SUP_COUTV__(fullPath);
1455 
1456  std::ofstream macrofile(fullPath.c_str());
1457  if(macrofile.is_open())
1458  {
1459  macrofile << "{\n";
1460  macrofile << "\"name\":\"" << newMacroName << "\",\n";
1461  macrofile << "\"sequence\":\"" << Sequence << "\",\n";
1462  macrofile << "\"time\":\"" << Time << "\",\n";
1463  macrofile << "\"notes\":\"" << Notes << "\",\n";
1464  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
1465  macrofile << "}@" << __E__;
1466  macrofile.close();
1467  }
1468  else
1469  __SUP_COUT__ << "Unable to open file" << __E__;
1470 
1471  if(oldMacroName != newMacroName) // renaming macro
1472  {
1473  int result;
1474  result =
1475  rename((MACROS_DB_PATH + username + "/" + oldMacroName + ".dat").c_str(),
1476  (MACROS_DB_PATH + username + "/" + newMacroName + ".dat").c_str());
1477  if(result == 0)
1478  xmldoc.addTextElementToData("newMacroName", newMacroName);
1479  else
1480  xmldoc.addTextElementToData("newMacroName", "ERROR");
1481  }
1482 }
1483 
1484 //==============================================================================
1485 void MacroMakerSupervisor::clearHistory(const std::string& username)
1486 {
1487  std::string fileName = "history.hist";
1488  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
1489 
1490  std::remove(fullPath.c_str());
1491  __SUP_COUT__ << "Successfully deleted " << fullPath;
1492 }
1493 
1494 //==============================================================================
1495 void MacroMakerSupervisor::exportFEMacro(HttpXmlDocument& xmldoc,
1496  cgicc::Cgicc& cgi,
1497  const std::string& username)
1498 {
1499  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
1500  std::string pluginName = CgiDataUtilities::getData(cgi, "PluginName");
1501  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
1502  std::string macroNotes =
1503  StringMacros::decodeURIComponent(CgiDataUtilities::postData(cgi, "MacroNotes"));
1504 
1505  __SUP_COUTV__(pluginName);
1506  __SUP_COUTV__(macroName);
1507  __SUP_COUTV__(macroSequence);
1508 
1509  // replace all special characters with white space
1510  for(unsigned int i = 0; i < macroNotes.length(); ++i)
1511  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
1512  macroNotes[i] = ' ';
1513  __SUP_COUTV__(macroNotes);
1514 
1515  std::stringstream ss(macroSequence);
1516  std::string command;
1517  std::vector<std::string> commands;
1518 
1519  while(getline(ss, command, ','))
1520  commands.push_back(command);
1521 
1522  __SUP_COUTV__(StringMacros::vectorToString(commands));
1523 
1524  std::map<std::string /*special type*/, std::set<std::string> /*special file paths*/>
1525  specialsCodeMap = CodeEditor::getSpecialsMap();
1526 
1527  //__SUP_COUTV__(StringMacros::mapToString(specialsCodeMap));
1528  auto specialsCodeMapIt = specialsCodeMap.find(CodeEditor::SPECIAL_TYPE_FEInterface);
1529  if(specialsCodeMapIt == specialsCodeMap.end())
1530  {
1531  __SS__
1532  << "Could not find any FE Interface plugins in source code. Does MacroMaker "
1533  << "have access to the source code? Check that the Supervisor context places "
1534  "MacroMaker in a "
1535  << "location with access to the source code." << __E__;
1536  __SS_THROW__;
1537  }
1538 
1539  // find first .h and .cc with the plugin name
1540  std::string headerFile = pluginName + ".h";
1541  std::string sourceFile = pluginName + "_interface.cc";
1542  bool foundHeaderFile = false;
1543  bool foundSourceFile = false;
1544  for(const auto& filePath : specialsCodeMapIt->second)
1545  {
1546  if(!foundHeaderFile && filePath.find(headerFile) != std::string::npos)
1547  {
1548  foundHeaderFile = true;
1549  headerFile = filePath;
1550  __SUP_COUT__ << "found headerFile=" << filePath << __E__;
1551  }
1552  if(!foundSourceFile && filePath.find(sourceFile) != std::string::npos)
1553  {
1554  foundSourceFile = true;
1555  sourceFile = filePath;
1556  __SUP_COUT__ << "found sourceFile=" << filePath << __E__;
1557  }
1558 
1559  if(foundSourceFile && foundHeaderFile)
1560  break;
1561  } // end file search loop
1562 
1563  if(!foundHeaderFile)
1564  {
1565  __SS__ << "Could not find the header file for the FE Interface plugins at '"
1566  << headerFile << ".' Does MacroMaker "
1567  << "have access to the source code? Check that the Supervisor context "
1568  "places MacroMaker in a "
1569  << "location with access to the source code." << __E__;
1570  __SS_THROW__;
1571  }
1572  if(!foundSourceFile)
1573  {
1574  __SS__ << "Could not find the source file for the FE Interface plugins at '"
1575  << sourceFile << ".' Does MacroMaker "
1576  << "have access to the source code? Check that the Supervisor context "
1577  "places MacroMaker in a "
1578  << "location with access to the source code." << __E__;
1579  __SS_THROW__;
1580  }
1581 
1582  // at this point have header and source file, now add FE Macro
1583  // Steps for each file:
1584  // - read current file
1585  // - find insert point
1586  // - open file for writing
1587  // - write original file up to insert point
1588  // - insert new code
1589  // - write remaining original file
1590 
1591  char timeBuffer[100];
1592  { // get time string
1593  time_t rawtime;
1594  struct tm* timeinfo;
1595 
1596  time(&rawtime);
1597  timeinfo = localtime(&rawtime);
1598 
1599  strftime(timeBuffer, 100, "%b-%d-%Y %I:%M:%S", timeinfo);
1600  }
1601 
1602  std::string contents;
1603  std::string insert;
1604 
1606  // handle source file modifications
1607  CodeEditor::readFile(CodeEditor::SOURCE_BASE_PATH, sourceFile, contents);
1608  //__SUP_COUTV__(contents);
1609 
1610  // return file locations, for the user to inspect on error
1611  xmldoc.addTextElementToData("sourceFile", sourceFile);
1612  xmldoc.addTextElementToData("headerFile", headerFile);
1613 
1614  // check for duplicate functions
1615  if(contents.find(pluginName + "::" + macroName) != std::string::npos)
1616  {
1617  __SS__ << "The function definition '" << (pluginName + "::" + macroName)
1618  << "(...)' already exists in the source file '" << sourceFile
1619  << ".' Duplicate functions are not allowed - please rename the macro or "
1620  "modify the source file."
1621  << __E__;
1622  __SS_THROW__;
1623  }
1624 
1625  std::stringstream codess;
1626  std::set<std::string> inArgNames, outArgNames;
1627  createCode(codess,
1628  commands,
1629  "\t" /*tabOffset*/,
1630  true /*forFeMacro*/,
1631  &inArgNames,
1632  &outArgNames);
1633  __SUP_COUTV__(StringMacros::setToString(inArgNames));
1634  __SUP_COUTV__(StringMacros::setToString(outArgNames));
1635 
1636  // find start of constructor and register macro
1637  {
1638  auto insertPos = contents.find(pluginName + "::" + pluginName);
1639  if(insertPos == std::string::npos)
1640  {
1641  __SS__ << "Could not find the code insert position in the source file '"
1642  << sourceFile << ".' The FE plugin class constructor must be '"
1643  << pluginName << ":" << pluginName << "' - is this the case?" << __E__;
1644  __SS_THROW__;
1645  }
1646  __SUP_COUTV__(insertPos);
1647  // find opening bracket after constructor name
1648  insertPos = contents.find("{", insertPos);
1649  if(insertPos == std::string::npos)
1650  {
1651  __SS__ << "Could not find the code insert position in the source file '"
1652  << sourceFile
1653  << ".' The FE plugin class constructor must begin with '{"
1654  << "' - is this the case?" << __E__;
1655  __SS_THROW__;
1656  }
1657  ++insertPos; // go past {
1658  __SUP_COUTV__(insertPos);
1659 
1660  insert = "\n\t//registration of FEMacro '" + macroName + "' generated, " +
1661  timeBuffer + ", by '" + username + "' using MacroMaker.\n\t" +
1662  "FEVInterface::registerFEMacroFunction(\"" + macroName +
1663  "\",//feMacroName \n\t\t" +
1664  "static_cast<FEVInterface::frontEndMacroFunction_t>(&" + pluginName +
1665  "::" + macroName + "), //feMacroFunction \n\t\t" +
1666  "std::vector<std::string>{";
1667  { // insert input argument names
1668  bool first = true;
1669  for(const auto& inArg : inArgNames)
1670  {
1671  if(first)
1672  first = false;
1673  else
1674  insert += ",";
1675  insert += "\"" + inArg + "\"";
1676  }
1677  }
1678  insert += "}, //namesOfInputArgs \n\t\t";
1679  insert += "std::vector<std::string>{";
1680  { // insert output argument names
1681  bool first = true;
1682  for(const auto& outArg : outArgNames)
1683  {
1684  if(first)
1685  first = false;
1686  else
1687  insert += ",";
1688  insert += "\"" + outArg + "\"";
1689  }
1690  }
1691  insert += "}, //namesOfOutputArgs \n\t\t";
1692  insert += "1); //requiredUserPermissions \n\n";
1693 
1694  __SUP_COUTV__(insert);
1695  contents = contents.substr(0, insertPos) + insert + contents.substr(insertPos);
1696  }
1697 
1698  // find end of source to append FE Macro function
1699  {
1700  auto insertPos = contents.rfind("DEFINE_OTS_INTERFACE");
1701  if(insertPos == std::string::npos)
1702  {
1703  __SS__ << "Could not find the code insert position in the source file '"
1704  << sourceFile
1705  << ".' The FE plugin class must end with a 'DEFINE_OTS_INTERFACE("
1706  << pluginName << ")' - is this the case?" << __E__;
1707  __SS_THROW__;
1708  }
1709  __SUP_COUTV__(insertPos);
1710 
1711  insert =
1712  "\n//"
1713  "============================================================================"
1714  "============================================\n//" +
1715  macroName + "\n" + "//\tFEMacro '" + macroName + "' generated, " +
1716  timeBuffer + ", by '" + username + "' using MacroMaker.\n" +
1717  "//\tMacro Notes: " + macroNotes + "\n" + "void " + pluginName +
1718  "::" + macroName + "(__ARGS__)\n{\n\t" +
1719  "__CFG_COUT__ << \"# of input args = \" << argsIn.size() << __E__; \n\t" +
1720  "__CFG_COUT__ << \"# of output args = \" << argsOut.size() << __E__; \n\t" +
1721  "for(auto &argIn:argsIn) \n\t\t" +
1722  "__CFG_COUT__ << argIn.first << \": \" << argIn.second << __E__; \n\n\t" +
1723  "//macro commands section \n" + codess.str() + "\n\n\t" +
1724  "for(auto &argOut:argsOut) \n\t\t" +
1725  "__CFG_COUT__ << argOut.first << \": \" << argOut.second << __E__; \n\n" +
1726  "} //end " + macroName + "()\n\n";
1727 
1728  //__SUP_COUTV__(insert);
1729  CodeEditor::writeFile(CodeEditor::SOURCE_BASE_PATH,
1730  sourceFile,
1731  contents,
1732  "MacroMaker-" + username,
1733  insertPos,
1734  insert);
1735  }
1736 
1738  // handle include file insertions
1739  CodeEditor::readFile(CodeEditor::SOURCE_BASE_PATH, headerFile, contents);
1740  //__SUP_COUTV__(contents);
1741 
1742  // find end of class by looking for last };
1743  {
1744  auto insertPos = contents.rfind("};");
1745  if(insertPos == std::string::npos)
1746  {
1747  __SS__ << "Could not find the code insert position in the header file '"
1748  << headerFile
1749  << ".' The FE plugin class must end with a '};' - is this the case?"
1750  << __E__;
1751  __SS_THROW__;
1752  }
1753 
1754  __SUP_COUTV__(insertPos);
1755 
1756  insert = "\npublic: // FEMacro '" + macroName + "' generated, " + timeBuffer +
1757  ", by '" + username + "' using MacroMaker.\n\t" + "void " + macroName +
1758  "\t(__ARGS__);\n";
1759 
1760  __SUP_COUTV__(insert);
1761  CodeEditor::writeFile(CodeEditor::SOURCE_BASE_PATH,
1762  headerFile,
1763  contents,
1764  "MacroMaker-" + username,
1765  insertPos,
1766  insert);
1767  }
1768 
1769 } // end exportFEMacro ()
1770 
1771 //==============================================================================
1772 void MacroMakerSupervisor::exportMacro(HttpXmlDocument& xmldoc,
1773  cgicc::Cgicc& cgi,
1774  const std::string& username)
1775 {
1776  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
1777  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
1778  std::string macroNotes =
1779  StringMacros::decodeURIComponent(CgiDataUtilities::postData(cgi, "MacroNotes"));
1780 
1781  __SUP_COUTV__(macroName);
1782  __SUP_COUTV__(macroSequence);
1783 
1784  // replace all special characters with white space
1785  for(unsigned int i = 0; i < macroNotes.length(); ++i)
1786  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
1787  macroNotes[i] = ' ';
1788  __SUP_COUTV__(macroNotes);
1789 
1790  std::stringstream ss(macroSequence);
1791  std::string command;
1792  std::vector<std::string> commands;
1793 
1794  while(getline(ss, command, ','))
1795  commands.push_back(command);
1796 
1797  std::string fileName = macroName + ".cc";
1798 
1799  std::string fullPath =
1800  __ENV__("SERVICE_DATA_PATH") + MACROS_EXPORT_PATH + username + "/" + fileName;
1801  __SUP_COUT__ << fullPath << __E__;
1802  std::ofstream exportFile(fullPath.c_str(), std::ios::trunc);
1803  if(exportFile.is_open())
1804  {
1805  exportFile << "//Generated Macro Name:\t" << macroName << "\n";
1806  exportFile << "//Macro Notes: " << macroNotes << "\n";
1807 
1808  {
1809  time_t rawtime;
1810  struct tm* timeinfo;
1811  char buffer[100];
1812 
1813  time(&rawtime);
1814  timeinfo = localtime(&rawtime);
1815 
1816  strftime(buffer, 100, "%b-%d-%Y %I:%M:%S", timeinfo);
1817  exportFile << "//Generated Time: \t\t" << buffer << "\n";
1818  }
1819 
1820  exportFile << "//Paste this whole file into an interface to transfer Macro "
1821  "functionality.\n";
1822 
1823  createCode(exportFile, commands);
1824 
1825  exportFile.close();
1826 
1827  xmldoc.addTextElementToData(
1828  "ExportFile",
1829  "$USER_DATA/ServiceData/" + MACROS_EXPORT_PATH + username + "/" + fileName);
1830  }
1831  else
1832  __SUP_COUT__ << "Unable to open file" << __E__;
1833 }
1834 
1835 //==============================================================================
1836 // createCode
1837 void MacroMakerSupervisor::createCode(std::ostream& out,
1838  const std::vector<std::string>& commands,
1839  const std::string& tabOffset,
1840  bool forFeMacro,
1841  std::set<std::string>* inArgNames,
1842  std::set<std::string>* outArgNames)
1843 {
1844  //int numOfHexBytes;
1845  std::set<std::string /*argInName*/> argInHasBeenInitializedSet;
1846  bool addressIsVariable, dataIsVariable;
1847 
1848  out << tabOffset << "{";
1849 
1850  out << "\n"
1851  << tabOffset << "\t"
1852  << "char *address \t= new char[universalAddressSize_]{0}; //create address "
1853  "buffer of interface size and init to all 0";
1854  out << "\n"
1855  << tabOffset << "\t"
1856  << "char *data \t\t= new char[universalDataSize_]{0}; //create data buffer "
1857  "of interface size and init to all 0";
1858 
1859  out << "\n"
1860  << tabOffset << "\t"
1861  << "uint64_t macroAddress; //create macro address buffer (size 8 bytes)";
1862  out << "\n"
1863  << tabOffset << "\t"
1864  << "uint64_t macroData; //create macro address buffer (size 8 bytes)";
1865 
1866  out << "\n"
1867  << tabOffset << "\t"
1868  << "std::map<std::string /*arg name*/,uint64_t /*arg val*/> macroArgs; //create "
1869  "map from arg name to 64-bit number";
1870 
1871  // loop through each macro command
1872  for(unsigned int i = 0; i < commands.size(); i++)
1873  {
1874  std::stringstream sst(commands[i]);
1875  std::string tokens;
1876  std::vector<std::string>
1877  oneCommand; // 4 fields: cmd index | cmd type | addr | data
1878  while(getline(sst, tokens, ':'))
1879  oneCommand.push_back(tokens);
1880  while(oneCommand.size() < 4)
1881  oneCommand.push_back(""); // fill out the 4 fields
1882 
1883  __SUP_COUTV__(StringMacros::vectorToString(oneCommand));
1884 
1885  // make this:
1886  // std::map<std::string,uint64_t> macroArgs;
1887  // {
1888  // uint64_t address = 0x1001; //create address buffer
1889  // uint64_t data = 0x100203; //create data buffer
1890  //
1891  // universalWrite(address,data);
1892  // universalRead(address,data);
1893  // }
1894  //
1895  // //if variable, first time init
1896  // {
1897  // address =
1898  // theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode("variableName").getValue<uint64_t>();
1899  // or
1900  // address = __GET_ARG_IN__("variableName",uint64_t);
1901  // }
1902  //
1903  // //if variable, second time use macroArgs
1904  // {
1905  // address = macroArgs["variableName"];
1906  // data = macroArgs["variableName"];
1907  // }
1908 
1909  addressIsVariable = isArgumentVariable(oneCommand[2]);
1910  dataIsVariable = isArgumentVariable(oneCommand[3]);
1911 
1912  __SUP_COUTV__(addressIsVariable);
1913  __SUP_COUTV__(dataIsVariable);
1914 
1915  out << "\n\n" << tabOffset << "\t// command-#" << i << ": ";
1916 
1917  if(oneCommand[1][0] == 'w' || oneCommand[1][0] == 'r')
1918  {
1919  if(oneCommand[1][0] == 'w')
1920  out << "Write(";
1921  else if(oneCommand[1][0] == 'r')
1922  out << "Read(";
1923 
1924  if(addressIsVariable)
1925  out << oneCommand[2];
1926  else // literal hex address
1927  out << "0x" << oneCommand[2];
1928  out << " /*address*/,";
1929 
1930  if(dataIsVariable) // read or write can have variable data, sink or source
1931  // respectively
1932  out << oneCommand[3] << " /*data*/";
1933  else if(oneCommand[1][0] == 'w') // literal hex data
1934  out << "0x" << oneCommand[3] << " /*data*/";
1935  else if(oneCommand[1][0] == 'r') // just reading to buffer
1936  out << "data";
1937  out << ");\n";
1938  }
1939  else if(oneCommand[1][0] == 'd')
1940  {
1941  out << "delay(" << oneCommand[2] << ");\n";
1942  out << tabOffset << "\t"
1943  << "__CFG_COUT__ << \"Sleeping for... \" << " << oneCommand[2]
1944  << " << \" milliseconds \" << __E__;\n";
1945  out << tabOffset << "\t"
1946  << "usleep(" << oneCommand[2] << "*1000 /* microseconds */);\n";
1947  continue;
1948  }
1949  else
1950  {
1951  __SS__ << "FATAL ERROR: Unknown command '" << oneCommand[1]
1952  << "'... command is not w, r or d" << __E__;
1953  __SS_THROW__;
1954  }
1955 
1957  // handle address
1958  if(addressIsVariable) // handle address as variable
1959  {
1960  if(argInHasBeenInitializedSet.find(oneCommand[2]) ==
1961  argInHasBeenInitializedSet.end()) // only initialize input argument once
1962  {
1963  argInHasBeenInitializedSet.emplace(oneCommand[2]);
1964 
1965  if(!forFeMacro)
1966  {
1967  // get address from configuration Tree
1968  out << tabOffset << "\t"
1969  << "macroArgs[\"" << oneCommand[2]
1970  << "\"] = "
1971  "theXDAQContextConfigTree_.getNode(theConfigurationPath_)."
1972  "getNode("
1973  << "\n"
1974  << tabOffset << "\t\t\"" << oneCommand[2]
1975  << "\").getValue<uint64_t>();";
1976  }
1977  else
1978  {
1979  if(inArgNames)
1980  inArgNames->emplace(oneCommand[2]);
1981 
1982  // get address from arguments
1983  out << tabOffset << "\t"
1984  << "macroArgs[\"" << oneCommand[2] << "\"] = __GET_ARG_IN__(\""
1985  << oneCommand[2] << "\", uint64_t);";
1986  }
1987  }
1988  out << "\t//get macro address argument";
1989  out << "\n"
1990  << tabOffset << "\tmemcpy(address,&macroArgs[\"" << oneCommand[2]
1991  << "\"],8); //copy macro address argument to buffer";
1992  }
1993  else // handle address as literal
1994  {
1995  out << tabOffset << "\t"
1996  << "macroAddress = 0x" << oneCommand[2]
1997  << "; memcpy(address,&macroAddress,8);"
1998  << "\t//copy macro address to buffer";
1999  }
2000 
2002  // handle data
2003  if(oneCommand[1] == "w") // if write, handle data too
2004  {
2005  if(dataIsVariable) // handle data as variable
2006  {
2007  if(argInHasBeenInitializedSet.find(oneCommand[3]) ==
2008  argInHasBeenInitializedSet
2009  .end()) // only initialize input argument once
2010  {
2011  argInHasBeenInitializedSet.emplace(oneCommand[3]);
2012 
2013  if(forFeMacro)
2014  {
2015  if(inArgNames)
2016  inArgNames->emplace(oneCommand[3]);
2017 
2018  // get data from arguments
2019  out << "\n"
2020  << tabOffset << "\t"
2021  << "macroArgs[\"" << oneCommand[3]
2022  << "\"] = __GET_ARG_IN__(\"" << oneCommand[3]
2023  << "\", uint64_t); //initialize from input arguments";
2024  }
2025  else
2026  {
2027  // get data from configuration Tree
2028  out << "\n"
2029  << tabOffset << "\t"
2030  << "macroArgs[\"" << oneCommand[3]
2031  << "\"] = "
2032  "theXDAQContextConfigTree_.getNode(theConfigurationPath_)."
2033  "getNode("
2034  << "\n"
2035  << tabOffset << "\t\t\"" << oneCommand[3]
2036  << "\").getValue<uint64_t>(); //initialize from "
2037  "configuration tree";
2038  }
2039  }
2040  out << "\t//get macro data argument";
2041  out << "\n"
2042  << tabOffset << "\tmemcpy(data,&macroArgs[\"" << oneCommand[3]
2043  << "\"],8); //copy macro data argument to buffer";
2044  }
2045  else // handle data as literal
2046  {
2047  out << "\n"
2048  << tabOffset << "\t"
2049  << "macroData = 0x" << oneCommand[3] << "; memcpy(data,&macroData,8);"
2050  << "\t//copy macro data to buffer";
2051  }
2052  out << "\n"
2053  << tabOffset << "\t"
2054  << "universalWrite(address,data);";
2055  }
2056  else
2057  {
2058  out << "\n"
2059  << tabOffset << "\t"
2060  << "universalRead(address,data);";
2061 
2062  std::string outputArgName;
2063 
2064  if(dataIsVariable) // handle data as variable
2065  outputArgName = oneCommand[3];
2066  else // give each read data a unique argument name
2067  {
2068  char str[20];
2069  sprintf(str, "outArg%d", i);
2070  outputArgName = str; // use command index for uniqueness
2071  }
2072  __SUP_COUTV__(outputArgName);
2073 
2074  out << tabOffset << "\t"
2075  << "memcpy(&macroArgs[\"" << outputArgName
2076  << "\"],data,8); //copy buffer to argument map";
2077 
2078  // copy read data to output args
2079  if(forFeMacro)
2080  out << "\n"
2081  << tabOffset << "\t"
2082  << "__SET_ARG_OUT__(\"" << outputArgName << "\",macroArgs[\""
2083  << outputArgName << "\"]); //update output argument result";
2084 
2085  if(outArgNames)
2086  outArgNames->emplace(outputArgName);
2087  argInHasBeenInitializedSet.emplace(
2088  outputArgName); // mark initialized since value has been read
2089  }
2090  } // end command loop
2091 
2092  out << "\n\n" << tabOffset << "\tdelete[] address; //free the memory";
2093  out << "\n" << tabOffset << "\tdelete[] data; //free the memory";
2094  out << "\n" << tabOffset << "}";
2095 
2096  __SUP_COUT__ << "Done with code generation." << __E__;
2097 } // end createCode()
2098 
2099 //==============================================================================
2100 // isArgumentVariable
2101 // returns true if string should be interpreted as a variable for MacroMaker
2102 bool MacroMakerSupervisor::isArgumentVariable(const std::string& argumentString)
2103 {
2104  for(unsigned int i = 0; i < argumentString.length(); ++i)
2105  {
2106  // detect non-hex
2107  if(!((argumentString[i] >= '0' && argumentString[i] <= '9') ||
2108  (argumentString[i] >= 'a' && argumentString[i] <= 'f') ||
2109  (argumentString[i] >= 'A' && argumentString[i] <= 'F')))
2110  return true;
2111  }
2112  return false;
2113 } // end isArgumentVariable()
2114 //==============================================================================
2115 // generateHexArray
2116 // returns a char array initializer
2117 // something like this
2118 // "[8] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09};"
2119 // ..depending a size of source string
2120 //
2121 // FIXME -- identify variables in a better way from macromaker...!
2122 // for now just assume a non hex is a variable name
2123 // return -1 size
2124 std::string MacroMakerSupervisor::generateHexArray(const std::string& sourceHexString,
2125  int& numOfBytes)
2126 {
2127  std::stringstream retSs;
2128 
2129  std::string srcHexStr = sourceHexString;
2130  __SUP_COUT__ << "Translating: \n";
2131  __SUP_COUT__ << srcHexStr << __E__;
2132 
2133  if(srcHexStr.size() % 2) // if odd, make even
2134  srcHexStr = "0" + srcHexStr;
2135 
2136  numOfBytes = srcHexStr.size() / 2;
2137  retSs << "[" << numOfBytes << "] = {";
2138 
2139  for(int i = 0; i < numOfBytes * 2; i += 2)
2140  {
2141  // detect non-hex
2142  if(!((srcHexStr[i] >= '0' && srcHexStr[i] <= '9') ||
2143  (srcHexStr[i] >= 'a' && srcHexStr[i] <= 'f') ||
2144  (srcHexStr[i] >= 'A' && srcHexStr[i] <= 'F')) ||
2145  !((srcHexStr[i + 1] >= '0' && srcHexStr[i + 1] <= '9') ||
2146  (srcHexStr[i + 1] >= 'a' && srcHexStr[i + 1] <= 'f') ||
2147  (srcHexStr[i + 1] >= 'A' && srcHexStr[i + 1] <= 'F')))
2148  {
2149  numOfBytes = -1;
2150  return srcHexStr;
2151  }
2152 
2153  if(i != 0)
2154  retSs << ", ";
2155  retSs << "0x" << srcHexStr[srcHexStr.size() - 1 - i - 1]
2156  << srcHexStr[srcHexStr.size() - 1 - i];
2157  }
2158  retSs << "};";
2159 
2160  __SUP_COUT__ << retSs.str() << __E__;
2161 
2162  return retSs.str();
2163 }
2164 
2165 //==============================================================================
2166 void MacroMakerSupervisor::runFEMacro(HttpXmlDocument& xmldoc,
2167  cgicc::Cgicc& cgi,
2168  const std::string& username) try
2169 {
2170  __SUP_COUT__ << __E__;
2171 
2172  // unsigned int feSupervisorID = CgiDataUtilities::getDataAsInt(cgi,
2173  // "feSupervisorID");
2174  std::string feClassSelected = CgiDataUtilities::getData(cgi, "feClassSelected");
2175  std::string feUIDSelected = CgiDataUtilities::getData(cgi, "feUIDSelected");
2176  std::string macroType = CgiDataUtilities::getData(cgi, "macroType");
2177  std::string macroName = CgiDataUtilities::getData(cgi, "macroName");
2178  std::string inputArgs = CgiDataUtilities::postData(cgi, "inputArgs");
2179  std::string outputArgs = CgiDataUtilities::postData(cgi, "outputArgs");
2180  bool saveOutputs = CgiDataUtilities::getDataAsInt(cgi, "saveOutputs") == 1;
2181 
2182  //__SUP_COUTV__(feSupervisorID);
2183  __SUP_COUTV__(feClassSelected);
2184  __SUP_COUTV__(feUIDSelected);
2185  __SUP_COUTV__(macroType);
2186  __SUP_COUTV__(macroName);
2187  __SUP_COUTV__(inputArgs);
2188  __SUP_COUTV__(outputArgs);
2189  __SUP_COUTV__(saveOutputs);
2190 
2191  std::set<std::string /*feUID*/> feUIDs;
2192 
2193  if(feUIDSelected == "")
2194  feUIDSelected = "*"; // treat empty as all
2195  if(feClassSelected == "")
2196  feClassSelected = "*"; // treat empty as all
2197 
2198  if(feClassSelected == "" || feUIDSelected == "" || macroType == "" || macroName == "")
2199  {
2200  __SUP_SS__ << "Illegal empty front-end parameter." << __E__;
2201  __SUP_SS_THROW__;
2202  }
2203  else if(feUIDSelected != "*")
2204  feUIDs.emplace(feUIDSelected);
2205  else // * all case
2206  {
2207  // add all FEs for type
2208  if(feClassSelected == "*")
2209  {
2210  for(auto& feTypePair : FEPluginTypetoFEsMap_)
2211  for(auto& feUID : feTypePair.second)
2212  feUIDs.emplace(feUID);
2213  }
2214  else
2215  {
2216  auto typeIt = FEPluginTypetoFEsMap_.find(feClassSelected);
2217  if(typeIt == FEPluginTypetoFEsMap_.end())
2218  {
2219  __SUP_SS__ << "Illegal front-end type parameter '" << feClassSelected
2220  << "' not in list of types." << __E__;
2221  __SUP_SS_THROW__;
2222  }
2223 
2224  for(auto& feUID : typeIt->second)
2225  feUIDs.emplace(feUID);
2226  }
2227  }
2228 
2229  __SUP_COUTV__(StringMacros::setToString(feUIDs));
2230 
2231  std::string macroString;
2232  if(macroType == "public")
2233  loadMacro(macroName, macroString);
2234  else if(macroType == "private")
2235  loadMacro(macroName, macroString, username);
2236 
2237  __SUP_COUTV__(macroString);
2238 
2239  FILE* fp = 0;
2240  try
2241  {
2242  if(saveOutputs)
2243  {
2244  std::string filename = "/macroOutput_" + std::to_string(time(0)) + "_" +
2245  std::to_string(clock()) + ".txt";
2246 
2247  __SUP_COUTV__(filename);
2248  fp = fopen((CodeEditor::OTSDAQ_DATA_PATH + filename).c_str(), "w");
2249  if(!fp)
2250  {
2251  __SUP_SS__ << "Failed to open file to save macro output '"
2252  << CodeEditor::OTSDAQ_DATA_PATH << filename << "'..." << __E__;
2253  __SUP_SS_THROW__;
2254  }
2255 
2256  fprintf(fp, "############################\n");
2257  fprintf(fp,
2258  "### Running '%s' at time %s\n",
2259  macroName.c_str(),
2260  StringMacros::getTimestampString().c_str());
2261  fprintf(fp,
2262  "### \t Target front-ends (count=%lu): %s\n",
2263  feUIDs.size(),
2264  StringMacros::setToString(feUIDs).c_str());
2265  fprintf(fp, "### \t\t Inputs: %s\n", inputArgs.c_str());
2266  fprintf(fp, "############################\n\n\n");
2267 
2268  xmldoc.addTextElementToData("outputArgs_name", "Filename");
2269  xmldoc.addTextElementToData("outputArgs_value", "$OTSDAQ_DATA/" + filename);
2270  }
2271 
2272  // do for all target front-ends
2273  for(auto& feUID : feUIDs)
2274  {
2275  auto feIt = FEtoSupervisorMap_.find(feUID);
2276  if(feIt == FEtoSupervisorMap_.end())
2277  {
2278  __SUP_SS__ << "Destination front end interface ID '" << feUID
2279  << "' was not found in the list of front ends." << __E__;
2280  ss << "\n\nHere is the map:\n\n"
2281  << StringMacros::mapToString(FEtoSupervisorMap_) << __E__;
2282  __SUP_SS_THROW__;
2283  }
2284 
2285  unsigned int FESupervisorIndex = feIt->second;
2286  __SUP_COUT__ << "Found supervisor index: " << FESupervisorIndex << __E__;
2287 
2288  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
2289  if(it == allFESupervisorInfo_.end())
2290  {
2291  __SUP_SS__
2292  << "Error transmitting request to FE Supervisor '" << feUID << ":"
2293  << FESupervisorIndex << ".' \n\n"
2294  << "The FE Supervisor Index does not exist. Have you configured "
2295  "the state machine properly?"
2296  << __E__;
2297  __SUP_SS_THROW__;
2298  }
2299 
2300  // send command to chosen FE and await response
2301  SOAPParameters txParameters; // params for xoap to send
2302  if(macroType == "fe")
2303  txParameters.addParameter("Request", "RunInterfaceMacro");
2304  else
2305  txParameters.addParameter("Request", "RunMacroMakerMacro");
2306  txParameters.addParameter("InterfaceID", feUID);
2307  if(macroType == "fe")
2308  txParameters.addParameter("feMacroName", macroName);
2309  else
2310  {
2311  txParameters.addParameter("macroName", macroName);
2312  txParameters.addParameter("macroString", macroString);
2313  }
2314  txParameters.addParameter("inputArgs", inputArgs);
2315  txParameters.addParameter("outputArgs", outputArgs);
2316 
2317  SOAPParameters rxParameters; // params for xoap to recv
2318  // rxParameters.addParameter("success");
2319  rxParameters.addParameter("outputArgs");
2320  rxParameters.addParameter("Error");
2321 
2322  if(saveOutputs)
2323  {
2324  fprintf(fp,
2325  "Running '%s' at time %s\n",
2326  macroName.c_str(),
2327  StringMacros::getTimestampString().c_str());
2328  fprintf(fp,
2329  "\t Target front-end: '%s::%s'\n",
2330  FEtoPluginTypeMap_[feUID].c_str(),
2331  feUID.c_str());
2332  fprintf(fp,
2333  "\t\t Inputs: %s\n",
2334  StringMacros::decodeURIComponent(inputArgs).c_str());
2335  }
2336 
2337  // have FE supervisor descriptor, so send
2338  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
2339  it->second.getDescriptor(), // supervisor descriptor
2340  "MacroMakerSupervisorRequest",
2341  txParameters);
2342 
2343  __SUP_COUT__ << "Received response message: "
2344  << SOAPUtilities::translate(retMsg) << __E__;
2345 
2346  SOAPUtilities::receive(retMsg, rxParameters);
2347 
2348  __SUP_COUT__ << "Received it " << __E__;
2349 
2350  // bool success = rxParameters.getValue("success") == "1";
2351  std::string outputResults = rxParameters.getValue("outputArgs");
2352  std::string error = rxParameters.getValue("Error");
2353 
2354  //__SUP_COUT__ << "rx success = " << success << __E__;
2355  __SUP_COUT__ << "outputArgs = " << outputResults << __E__;
2356 
2357  if(error != "")
2358  {
2359  __SS__ << "Attempted FE Macro Failed. Attempted target "
2360  << "was UID=" << feUID
2361  << " at feSupervisorID=" << FESupervisorIndex << "." << __E__;
2362  ss << "\n\n The error was:\n\n" << error << __E__;
2363  __SUP_COUT_ERR__ << "\n" << ss.str();
2364  xmldoc.addTextElementToData("Error", ss.str());
2365 
2366  return;
2367  }
2368 
2369  // build output arguments
2370  // parse args, colon-separated pairs, and then comma-separated
2371  {
2372  std::istringstream inputStream(outputResults);
2373  std::string splitVal, argName, argValue;
2374  while(getline(inputStream, splitVal, ';'))
2375  {
2376  std::istringstream pairInputStream(splitVal);
2377  getline(pairInputStream, argName, ',');
2378  getline(pairInputStream, argValue, ',');
2379 
2380  if(saveOutputs)
2381  {
2382  fprintf(fp,
2383  "\t\t Output '%s' = %s\n",
2384  argName.c_str(),
2385  StringMacros::decodeURIComponent(argValue).c_str());
2386  }
2387  else
2388  {
2389  xmldoc.addTextElementToData("outputArgs_name", argName);
2390  xmldoc.addTextElementToData("outputArgs_value", argValue);
2391  }
2392  __SUP_COUT__ << argName << ": " << argValue << __E__;
2393  }
2394  }
2395  } // end target front-end loop
2396  }
2397  catch(...) // handle file close on error
2398  {
2399  if(fp)
2400  fclose(fp);
2401  throw;
2402  }
2403 
2404  if(fp)
2405  fclose(fp);
2406 
2407 } // end runFEMacro()
2408 catch(const std::runtime_error& e)
2409 {
2410  __SUP_SS__ << "Error processing FE communication request: " << e.what() << __E__;
2411  __SUP_COUT_ERR__ << ss.str();
2412  xmldoc.addTextElementToData("Error", ss.str());
2413 }
2414 catch(...)
2415 {
2416  __SUP_SS__ << "Unknown error processing FE communication request." << __E__;
2417  __SUP_COUT_ERR__ << ss.str();
2418 
2419  xmldoc.addTextElementToData("Error", ss.str());
2420 } // end runFEMacro() catch
2421 
2422 //==============================================================================
2423 void MacroMakerSupervisor::getFEMacroList(HttpXmlDocument& xmldoc,
2424  const std::string& username)
2425 {
2426  __SUP_COUT__ << "Getting FE Macro list" << __E__;
2427 
2428  SOAPParameters txParameters; // params for xoap to send
2429  txParameters.addParameter("Request", "GetInterfaceMacros");
2430 
2431  SOAPParameters rxParameters; // params for xoap to recv
2432  rxParameters.addParameter("FEMacros");
2433 
2434  std::string oneInterface;
2435  std::string rxFEMacros;
2436 
2437  // for each list of FE Supervisors,
2438  // get all FE specific macros
2439  for(auto& appInfo : allFESupervisorInfo_)
2440  {
2441  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId()
2442  << " name = " << appInfo.second.getName() << __E__;
2443 
2444  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
2445  appInfo.second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
2446  SOAPUtilities::receive(retMsg, rxParameters);
2447 
2448  rxFEMacros = rxParameters.getValue("FEMacros");
2449 
2450  __SUP_COUT__ << "FE Macros received: \n" << rxFEMacros << __E__;
2451 
2452  std::istringstream allInterfaces(rxFEMacros);
2453  while(std::getline(allInterfaces, oneInterface))
2454  {
2455  //__SUP_COUT__ << oneInterface << __E__;
2456  //__SUP_COUT__ << appInfo.second.getId() << __E__;
2457  xmldoc.addTextElementToData("FEMacros", oneInterface);
2458  // xmldoc.outputXmlDocument(0,true);
2459  }
2460  }
2461 
2462  // add macros to response
2463  std::pair<std::vector<std::string> /*public macros*/,
2464  std::vector<std::string> /*private macros*/>
2465  macroNames;
2466  loadMacroNames(username, macroNames);
2467 
2468  __SUP_COUT__ << "Public macro count: " << macroNames.first.size() << __E__;
2469  __SUP_COUT__ << "Private macro count: " << macroNames.second.size() << __E__;
2470 
2471  std::string macroString;
2472  // make xml ':' separated fields:
2473  // macro name
2474  // permissions string
2475  // number of inputs
2476  // inputs separated by :
2477  // number of outputs
2478  // outputs separated by :
2479 
2480  for(int i = 0; i < 2; ++i) // first is public, then private
2481  for(auto& macroName : (i ? macroNames.second : macroNames.first))
2482  {
2483  // get macro string
2484  loadMacro(macroName, macroString, username);
2485 
2486  // extract macro object
2487  FEVInterface::macroStruct_t macro(macroString);
2488 
2489  std::stringstream xmlMacroStream;
2490  xmlMacroStream << macro.macroName_;
2491  xmlMacroStream << ":"
2492  << "1"; // permissions string
2493  xmlMacroStream << ":" << macro.namesOfInputArguments_.size();
2494  for(auto& inputArg : macro.namesOfInputArguments_)
2495  xmlMacroStream << ":" << inputArg;
2496  xmlMacroStream << ":" << macro.namesOfOutputArguments_.size();
2497  for(auto& inputArg : macro.namesOfOutputArguments_)
2498  xmlMacroStream << ":" << inputArg;
2499 
2500  xmldoc.addTextElementToData(i ? "PrivateMacro" : "PublicMacro",
2501  xmlMacroStream.str());
2502  }
2503 
2504  return;
2505 }