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