otsdaq_utilities  v2_04_01
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(
742  "frontEndError"); // if there were errors recorded (during
743  // configuration, e.g. in Macro Maker only
744  // mode)
745 
746  SupervisorInfoMap::const_iterator it;
747  std::string oneInterface;
748  std::string rxFEList;
749  std::string rxFrontEndError;
750 
751  size_t lastColonIndex;
752 
753  // for each list of FE Supervisors,
754  // loop through each FE Supervisors and get FE interfaces list
755  for(auto& appInfo : allFESupervisorInfo_)
756  {
757  // __SUP_COUT__ << "Number of " << listPair.first << " = " <<
758  // listPair.second.size() << __E__;
759  //
760  // for (it = listPair.second.begin(); it != listPair.second.end(); it++)
761  // {
762 
763  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId()
764  << " name = " << appInfo.second.getName() << __E__;
765 
766  try
767  {
768  xoap::MessageReference retMsg =
769  SOAPMessenger::sendWithSOAPReply(appInfo.second.getDescriptor(),
770  "MacroMakerSupervisorRequest",
771  txParameters);
772  SOAPUtilities::receive(retMsg, rxParameters);
773  }
774  catch(const xdaq::exception::Exception& e)
775  {
776  __SUP_SS__ << "Error transmitting request to FE Supervisor LID = "
777  << appInfo.second.getId() << " name = " << appInfo.second.getName()
778  << ". \n\n"
779  << e.what() << __E__;
780  __SUP_SS_THROW__;
781  }
782 
783  rxFEList = rxParameters.getValue("FEList");
784  rxFrontEndError = rxParameters.getValue("frontEndError");
785 
786  __SUP_COUT__ << "FE List received: \n" << rxFEList << __E__;
787 
788  if(rxFrontEndError != "")
789  {
790  __SUP_SS__ << "FE Errors received: \n" << rxFrontEndError << __E__;
791  __SUP_SS_THROW__;
792  }
793 
794  std::istringstream allInterfaces(rxFEList);
795  while(std::getline(allInterfaces, oneInterface))
796  {
797  __SUP_COUTV__(oneInterface);
798  xmldoc.addTextElementToData("FE", oneInterface);
799 
800  lastColonIndex = oneInterface.rfind(':');
801  if(lastColonIndex == std::string::npos)
802  {
803  __SUP_SS__ << "Last colon could not be found in " << oneInterface
804  << __E__;
805  __SUP_SS_THROW__;
806  }
807  oneInterface = oneInterface.substr(lastColonIndex);
808 
809  __SUP_COUTV__(oneInterface);
810  } // end FE extract loop
811 
812  } // end ask Supervisors for their FE list loop
813 
814 } // end getFEList()
815 
816 //========================================================================================================================
817 void MacroMakerSupervisor::writeData(HttpXmlDocument& xmldoc,
818  cgicc::Cgicc& cgi,
819  const std::string& username)
820 {
821  __SUP_COUT__ << "MacroMaker writing..." << __E__;
822 
823  std::string Address = CgiDataUtilities::getData(cgi, "Address");
824  std::string Data = CgiDataUtilities::getData(cgi, "Data");
825  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
826  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
827  std::string time =
828  CgiDataUtilities::decodeURIComponent(CgiDataUtilities::getData(cgi, "time"));
829  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
830  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
831 
832  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
833 
834  __SUP_COUT__ << "Write Address: " << Address << " Data: " << Data << __E__;
835  __SUP_COUTV__(interfaces);
836 
837  std::string command = "w:" + Address + ":" + Data;
838  std::string format = addressFormatStr + ":" + dataFormatStr;
839  appendCommandToHistory(command, format, time, interfaces, username);
840 
841  SOAPParameters txParameters; // params for xoap to send
842  txParameters.addParameter("Request", "UniversalWrite");
843  txParameters.addParameter("Address", Address);
844  txParameters.addParameter("Data", Data);
845 
846  __SUP_COUT__ << "Here comes the array from multiselect box for WRITE, behold: \n"
847  << supervisorIndexArray << "\n"
848  << interfaceIndexArray << __E__;
849 
852  std::vector<std::string> interfaceIndices;
853  std::istringstream f(interfaceIndexArray);
854  std::string s;
855  while(getline(f, s, ','))
856  interfaceIndices.push_back(s);
857  std::vector<int> supervisorIndices;
858  std::istringstream g(supervisorIndexArray);
859  std::string t;
860  while(getline(g, t, ','))
861  supervisorIndices.push_back(std::stoi(t));
862 
863  for(unsigned int i = 0; i < supervisorIndices.size(); i++)
864  {
865  unsigned int FESupervisorIndex = supervisorIndices[i];
866  std::string interfaceIndex = interfaceIndices[i];
867 
868  txParameters.addParameter("InterfaceID", interfaceIndex);
869 
870  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex
871  << __E__;
872  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
873 
874  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
875  if(it == allFESupervisorInfo_.end())
876  {
877  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
878  << interfaceIndex << ":" << FESupervisorIndex << ".' \n\n"
879  << "The FE Index doesn't exist. Have you configured the state "
880  "machine properly?"
881  << __E__;
882  __SUP_SS_THROW__;
883  }
884 
885  try
886  {
887  xoap::MessageReference replyMessage = SOAPMessenger::sendWithSOAPReply(
888  it->second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
889 
890  __SUP_COUT__ << "Response received: "
891  << SOAPUtilities::translate(replyMessage) << __E__;
892 
893  SOAPParameters rxParameters;
894  rxParameters.addParameter("Error");
895  SOAPUtilities::receive(replyMessage, rxParameters);
896 
897  std::string error = rxParameters.getValue("Error");
898  __SUP_COUTV__(error);
899 
900  if(error != "")
901  {
902  // error occurred!
903  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
904  << interfaceIndex << ":" << FESupervisorIndex << ".' "
905  << "Have you configured the state machine properly?\n\n"
906  << error << __E__;
907  __SUP_SS_THROW__;
908  }
909  }
910  catch(const xdaq::exception::Exception& e)
911  {
912  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
913  << interfaceIndex << ":" << FESupervisorIndex << ".' "
914  << "Have you configured the state machine properly?\n\n"
915  << e.what() << __E__;
916  __SUP_SS_THROW__;
917  }
918 
919  } // end FE Supervisor loop
920 } // end writeData()
921 
922 //========================================================================================================================
923 void MacroMakerSupervisor::readData(HttpXmlDocument& xmldoc,
924  cgicc::Cgicc& cgi,
925  const std::string& username)
926 {
927  __SUP_COUT__ << "@@@@@@@ MacroMaker wants to read data @@@@@@@@" << __E__;
928  std::string Address = CgiDataUtilities::getData(cgi, "Address");
929  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
930  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
931  std::string time =
932  CgiDataUtilities::decodeURIComponent(CgiDataUtilities::getData(cgi, "time"));
933  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
934  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
935 
936  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
937 
938  __SUP_COUT__ << "Read Address: " << Address << __E__;
939  __SUP_COUTV__(interfaces);
940 
941  SOAPParameters txParameters; // params for xoap to send
942  txParameters.addParameter("Request", "UniversalRead");
943  txParameters.addParameter("Address", Address);
944 
945  SOAPParameters rxParameters;
946  rxParameters.addParameter("dataResult");
947  rxParameters.addParameter("Error");
948  __SUP_COUT__ << "Here comes the array from multiselect box for READ, behold: "
949  << supervisorIndexArray << "," << interfaceIndexArray << __E__;
950 
953  std::vector<std::string> interfaceIndices;
954  std::istringstream f(interfaceIndexArray);
955  std::string s;
956  while(getline(f, s, ','))
957  interfaceIndices.push_back(s);
958  std::vector<int> supervisorIndices;
959  std::istringstream g(supervisorIndexArray);
960  std::string t;
961  while(getline(g, t, ','))
962  supervisorIndices.push_back(std::stoi(t));
963 
964  for(unsigned int i = 0; i < supervisorIndices.size(); i++)
965  {
966  unsigned int FESupervisorIndex = supervisorIndices[i];
967  std::string interfaceIndex = interfaceIndices[i];
968 
969  txParameters.addParameter("InterfaceID", interfaceIndex);
970 
971  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex
972  << __E__;
973  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
974 
975  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
976  if(it == allFESupervisorInfo_.end())
977  {
978  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
979  << interfaceIndex << ":" << FESupervisorIndex << ".' \n\n"
980  << "The FE Index doesn't exist. Have you configured the state "
981  "machine properly?"
982  << __E__;
983  __SUP_SS_THROW__;
984  }
985 
986  try
987  {
988  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
989  it->second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
990 
991  __SUP_COUT__ << "Response received: " << SOAPUtilities::translate(retMsg)
992  << __E__;
993 
994  // SOAPParameters rxParameters;
995  // rxParameters.addParameter("Error");
996  SOAPUtilities::receive(retMsg, rxParameters);
997 
998  std::string error = rxParameters.getValue("Error");
999  __SUP_COUTV__(error);
1000 
1001  if(error != "")
1002  {
1003  // error occurred!
1004  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1005  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1006  << "Have you configured the state machine properly?\n\n"
1007  << error << __E__;
1008  __SUP_SS_THROW__;
1009  }
1010  }
1011  catch(const xdaq::exception::Exception& e)
1012  {
1013  __SUP_SS__ << "Error transmitting request to FE Supervisor '"
1014  << interfaceIndex << ":" << FESupervisorIndex << ".' "
1015  << "Have you configured the state machine properly?\n\n"
1016  << e.what() << __E__;
1017  __SUP_SS_THROW__;
1018  }
1019 
1020  std::string dataReadResult = rxParameters.getValue("dataResult");
1021  __SUP_COUT__ << "Data reading result received: " << dataReadResult << __E__;
1022  xmldoc.addTextElementToData("readData", dataReadResult);
1023  std::string command = "r:" + Address + ":" + dataReadResult;
1024  std::string format = addressFormatStr + ":" + dataFormatStr;
1025  appendCommandToHistory(command, format, time, interfaces, username);
1026  }
1027 }
1028 
1029 //========================================================================================================================
1030 void MacroMakerSupervisor::createMacro(HttpXmlDocument& xmldoc,
1031  cgicc::Cgicc& cgi,
1032  const std::string& username)
1033 {
1034  __SUP_COUT__ << "MacroMaker wants to create a macro!!!!!!!!!" << __E__;
1035  std::string Name = CgiDataUtilities::postData(cgi, "Name");
1036  std::string Sequence = CgiDataUtilities::postData(cgi, "Sequence");
1037  std::string Time = CgiDataUtilities::postData(cgi, "Time");
1038  std::string Notes =
1039  CgiDataUtilities::decodeURIComponent(CgiDataUtilities::postData(cgi, "Notes"));
1040  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
1041  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
1042 
1043  __SUP_COUTV__(Name);
1044  __SUP_COUTV__(Sequence);
1045  __SUP_COUTV__(Notes);
1046  __SUP_COUTV__(Time);
1047  __SUP_COUTV__(isMacroPublic);
1048  __SUP_COUTV__(isMacroLSBF);
1049 
1050  __SUP_COUTV__(MACROS_DB_PATH);
1051 
1052  std::string fileName = Name + ".dat";
1053  std::string fullPath;
1054  if(isMacroPublic == "true")
1055  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
1056  else
1057  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
1058 
1059  __SUP_COUTV__(fullPath);
1060 
1061  std::ofstream macrofile(fullPath.c_str());
1062  if(macrofile.is_open())
1063  {
1064  macrofile << "{\n";
1065  macrofile << "\"name\":\"" << Name << "\",\n";
1066  macrofile << "\"sequence\":\"" << Sequence << "\",\n";
1067  macrofile << "\"time\":\"" << Time << "\",\n";
1068  macrofile << "\"notes\":\"" << Notes << "\",\n";
1069  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
1070  macrofile << "}@" << __E__;
1071  macrofile.close();
1072  }
1073  else
1074  __SUP_COUT__ << "Unable to open file" << __E__;
1075 } // end createMacro()
1076 
1077 //========================================================================================================================
1078 // loadMacro
1079 // Load macro string from file.
1080 // look in public macros and username (if given)
1081 // for the macroName.
1082 //
1083 // If found, return by reference
1084 // Else, throw exception
1085 void MacroMakerSupervisor::loadMacro(const std::string& macroName,
1086  std::string& macroString,
1087  const std::string& username /*=""*/)
1088 {
1089  __SUP_COUTV__(macroName);
1090 
1091  // first check public folder, then user
1092  std::string fullPath, line;
1093  macroString = "";
1094  for(unsigned int i = 0; i < 2; ++i)
1095  {
1096  if(i == 1)
1097  fullPath = (std::string)MACROS_DB_PATH + username + "/";
1098  else
1099  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1100 
1101  fullPath += macroName;
1102  if(macroName.find(".dat") != macroName.size() - 4)
1103  fullPath += ".dat";
1104  __SUP_COUTV__(fullPath);
1105 
1106  std::ifstream read(fullPath.c_str()); // reading a file
1107  if(read.is_open())
1108  {
1109  while(!read.eof())
1110  {
1111  getline(read, line);
1112  macroString += line;
1113  }
1114 
1115  read.close();
1116  }
1117  else // file does not exist
1118  {
1119  __SUP_COUT__ << "Unable to open file: " << fullPath << __E__;
1120  continue;
1121  }
1122 
1123  if(macroString != "")
1124  break; // macro has been found!
1125  } // end load from path loop
1126 
1127  if(macroString == "")
1128  {
1129  __SUP_SS__ << "Unable to locate file for macro '" << macroName
1130  << "'... does it exist?" << __E__;
1131  if(username != "")
1132  ss << " Attempted username was '" << username << ".'" << __E__;
1133  __SUP_SS_THROW__;
1134  }
1135 
1136  __SUP_COUTV__(macroString);
1137 } // end loadMacro()
1138 
1139 //========================================================================================================================
1140 void MacroMakerSupervisor::loadMacroNames(
1141  const std::string& username,
1142  std::pair<std::vector<std::string> /*public macros*/,
1143  std::vector<std::string> /*private macros*/>& returnMacroNames)
1144 {
1145  DIR* dir;
1146  struct dirent* ent;
1147  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
1148  if((dir = opendir(fullPath.c_str())) != NULL)
1149  {
1150  /* print all the files and directories within directory */
1151  while((ent = readdir(dir)) != NULL)
1152  {
1153  /* File name validation check */
1154  if((unsigned)strlen(ent->d_name) > 4)
1155  {
1156  std::string line;
1157  std::ifstream read(
1158  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1159  if(read.is_open())
1160  {
1161  read.close();
1162  // private macro found
1163  returnMacroNames.second.push_back(ent->d_name);
1164  }
1165  else
1166  __SUP_COUT__ << "Unable to open file" << __E__;
1167  }
1168  }
1169  closedir(dir);
1170  }
1171  else
1172  {
1173  __SUP_COUT__ << "Looping through privateMacros folder failed! Wrong directory"
1174  << __E__;
1175  }
1176  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1177  if((dir = opendir(fullPath.c_str())) != NULL)
1178  {
1179  /* print all the files and directories within directory */
1180  while((ent = readdir(dir)) != NULL)
1181  {
1182  /* File name validation check */
1183  if((unsigned)strlen(ent->d_name) > 4)
1184  {
1185  std::string line;
1186  std::ifstream read(
1187  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1188  if(read.is_open())
1189  {
1190  // public macro found
1191  returnMacroNames.first.push_back(ent->d_name);
1192  read.close();
1193  }
1194  else
1195  __SUP_COUT__ << "Unable to open file" << __E__;
1196  }
1197  }
1198  closedir(dir);
1199  }
1200  else
1201  {
1202  __SUP_COUT__ << fullPath << __E__;
1203  __SUP_COUT__ << "Looping through MacroData folder failed! Wrong directory"
1204  << __E__;
1205  }
1206 
1207 } // end loadMacroNames
1208 
1209 //========================================================================================================================
1210 void MacroMakerSupervisor::loadMacros(HttpXmlDocument& xmldoc,
1211  const std::string& username)
1212 {
1213  DIR* dir;
1214  struct dirent* ent;
1215  std::string returnStr = "";
1216  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
1217  if((dir = opendir(fullPath.c_str())) != NULL)
1218  {
1219  /* print all the files and directories within directory */
1220  while((ent = readdir(dir)) != NULL)
1221  {
1222  /* File name validation check */
1223  if((unsigned)strlen(ent->d_name) > 4)
1224  {
1225  std::string line;
1226  std::ifstream read(
1227  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1228  if(read.is_open())
1229  {
1230  std::stringstream buffer;
1231  while(!read.eof())
1232  {
1233  getline(read, line);
1234  buffer << line;
1235  //__SUP_COUT__ << line << __E__;
1236  }
1237  returnStr += buffer.str();
1238 
1239  read.close();
1240  }
1241  else
1242  __SUP_COUT__ << "Unable to open file" << __E__;
1243  }
1244  }
1245  std::string returnMacroStr = returnStr.substr(0, returnStr.size() - 1);
1246 
1247  __SUP_COUT__ << "Loading existing macros! " << returnMacroStr << __E__;
1248 
1249  closedir(dir);
1250  xmldoc.addTextElementToData("returnMacroStr", returnMacroStr);
1251  }
1252  else
1253  {
1254  __SUP_COUT__ << "Looping through privateMacros folder failed! Wrong directory"
1255  << __E__;
1256  }
1257  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
1258  returnStr = "";
1259  if((dir = opendir(fullPath.c_str())) != NULL)
1260  {
1261  /* print all the files and directories within directory */
1262  while((ent = readdir(dir)) != NULL)
1263  {
1264  /* File name validation check */
1265  if((unsigned)strlen(ent->d_name) > 4)
1266  {
1267  std::string line;
1268  std::ifstream read(
1269  ((fullPath + (std::string)ent->d_name)).c_str()); // reading a file
1270  if(read.is_open())
1271  {
1272  std::stringstream buffer;
1273  while(!read.eof())
1274  {
1275  getline(read, line);
1276  buffer << line;
1277  //__SUP_COUT__ << line << __E__;
1278  }
1279  returnStr += buffer.str();
1280  read.close();
1281  }
1282  else
1283  __SUP_COUT__ << "Unable to open file" << __E__;
1284  }
1285  }
1286  std::string returnPublicStr = returnStr.substr(0, returnStr.size() - 1);
1287  __SUP_COUT__ << "Loading existing public macros: " << returnPublicStr << __E__;
1288  closedir(dir);
1289  xmldoc.addTextElementToData("returnPublicStr", returnPublicStr);
1290  }
1291  else
1292  {
1293  __SUP_COUT__ << fullPath << __E__;
1294  __SUP_COUT__ << "Looping through MacroData folder failed! Wrong directory"
1295  << __E__;
1296  }
1297 } // end loadMacros()
1298 
1299 //========================================================================================================================
1300 void MacroMakerSupervisor::appendCommandToHistory(std::string Command,
1301  std::string Format,
1302  std::string Time,
1303  std::string Interfaces,
1304  const std::string& username)
1305 {
1306  std::string fileName = "history.hist";
1307  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
1308  __SUP_COUT__ << fullPath << __E__;
1309  std::ofstream histfile(fullPath.c_str(), std::ios::app);
1310  if(histfile.is_open())
1311  {
1312  histfile << "{\n";
1313  histfile << "\"Command\":\"" << Command << "\",\n";
1314  histfile << "\"Format\":\"" << Format << "\",\n";
1315  histfile << "\"Time\":\"" << Time << "\",\n";
1316  histfile << "\"Interfaces\":\"" << Interfaces << "\"\n";
1317  histfile << "}#" << __E__;
1318  histfile.close();
1319  }
1320  else
1321  __SUP_COUT__ << "Unable to open history.hist" << __E__;
1322 }
1323 
1324 //========================================================================================================================
1325 void MacroMakerSupervisor::loadHistory(HttpXmlDocument& xmldoc,
1326  const std::string& username)
1327 {
1328  std::string fileName = MACROS_HIST_PATH + username + "/" + "history.hist";
1329 
1330  std::ifstream read(fileName.c_str()); // reading a file
1331  __SUP_COUT__ << fileName << __E__;
1332 
1333  if(read.is_open())
1334  {
1335  std::string line;
1336  char* returnStr;
1337  unsigned long long fileSz, i = 0, MAX_HISTORY_SIZE = 100000;
1338 
1339  // get length of file to reserve the string size
1340  // and to cap history size
1341  read.seekg(0, std::ios::end);
1342  fileSz = read.tellg();
1343  returnStr = new char[fileSz + 1];
1344  returnStr[fileSz] = '\0';
1345  read.seekg(0, std::ios::beg);
1346 
1347  // read data as a block:
1348  read.read(returnStr, fileSz);
1349  read.close();
1350 
1351  // find i such that new string size is less than
1352  if(fileSz > MAX_HISTORY_SIZE)
1353  {
1354  i = fileSz - MAX_HISTORY_SIZE;
1355  for(; i < fileSz; ++i)
1356  if(returnStr[i] == '#')
1357  {
1358  i += 2;
1359  break; // skip new line character also to get to next record
1360  }
1361  if(i > fileSz)
1362  i = fileSz;
1363 
1364  // write back to file truncated history
1365  FILE* fp = fopen(fileName.c_str(), "w");
1366  if(!fp)
1367  {
1368  __SS__ << "Big problem with macromaker history file: " << fileName
1369  << __E__;
1370  __SS_THROW__;
1371  }
1372  fwrite(&returnStr[i], fileSz - i, 1, fp);
1373  fclose(fp);
1374  }
1375 
1376  __SUP_COUT__ << "Loading user history! " << __E__;
1377 
1378  if(fileSz > 1)
1379  returnStr[fileSz - 2] = '\0'; // remove final newline and last #
1380 
1381  xmldoc.addTextElementToData("returnHistStr", &returnStr[i]);
1382 
1383  delete[] returnStr;
1384  }
1385  else
1386 
1387  __SUP_COUT__ << "Unable to open history.hist" << __E__;
1388 }
1389 
1390 //========================================================================================================================
1391 void MacroMakerSupervisor::deleteMacro(HttpXmlDocument& xmldoc,
1392  cgicc::Cgicc& cgi,
1393  const std::string& username)
1394 {
1395  std::string MacroName = CgiDataUtilities::getData(cgi, "MacroName");
1396  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
1397 
1398  std::string fileName = MacroName + ".dat";
1399  std::string fullPath;
1400  if(isMacroPublic == "true")
1401  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
1402  else
1403  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
1404 
1405  __SUP_COUT__ << fullPath << __E__;
1406 
1407  std::remove(fullPath.c_str());
1408  __SUP_COUT__ << "Successfully deleted " << MacroName;
1409  xmldoc.addTextElementToData("deletedMacroName", MacroName);
1410 }
1411 
1412 //========================================================================================================================
1413 void MacroMakerSupervisor::editMacro(HttpXmlDocument& xmldoc,
1414  cgicc::Cgicc& cgi,
1415  const std::string& username)
1416 {
1417  std::string oldMacroName = CgiDataUtilities::postData(cgi, "oldMacroName");
1418  std::string newMacroName = CgiDataUtilities::postData(cgi, "newMacroName");
1419  std::string Sequence = CgiDataUtilities::postData(cgi, "Sequence");
1420  std::string Time = CgiDataUtilities::postData(cgi, "Time");
1421  std::string Notes =
1422  CgiDataUtilities::decodeURIComponent(CgiDataUtilities::postData(cgi, "Notes"));
1423 
1424  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
1425  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
1426 
1427  __SUP_COUTV__(oldMacroName);
1428  __SUP_COUTV__(newMacroName);
1429  __SUP_COUTV__(Sequence);
1430  __SUP_COUTV__(Notes);
1431  __SUP_COUTV__(Time);
1432  __SUP_COUTV__(isMacroPublic);
1433  __SUP_COUTV__(isMacroLSBF);
1434 
1435  __SUP_COUTV__(MACROS_DB_PATH);
1436 
1437  std::string fileName = oldMacroName + ".dat";
1438  std::string fullPath;
1439  if(isMacroPublic == "true")
1440  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
1441  else
1442  fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
1443 
1444  __SUP_COUTV__(fullPath);
1445 
1446  std::ofstream macrofile(fullPath.c_str());
1447  if(macrofile.is_open())
1448  {
1449  macrofile << "{\n";
1450  macrofile << "\"name\":\"" << newMacroName << "\",\n";
1451  macrofile << "\"sequence\":\"" << Sequence << "\",\n";
1452  macrofile << "\"time\":\"" << Time << "\",\n";
1453  macrofile << "\"notes\":\"" << Notes << "\",\n";
1454  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
1455  macrofile << "}@" << __E__;
1456  macrofile.close();
1457  }
1458  else
1459  __SUP_COUT__ << "Unable to open file" << __E__;
1460 
1461  if(oldMacroName != newMacroName) // renaming macro
1462  {
1463  int result;
1464  result =
1465  rename((MACROS_DB_PATH + username + "/" + oldMacroName + ".dat").c_str(),
1466  (MACROS_DB_PATH + username + "/" + newMacroName + ".dat").c_str());
1467  if(result == 0)
1468  xmldoc.addTextElementToData("newMacroName", newMacroName);
1469  else
1470  xmldoc.addTextElementToData("newMacroName", "ERROR");
1471  }
1472 }
1473 
1474 //========================================================================================================================
1475 void MacroMakerSupervisor::clearHistory(const std::string& username)
1476 {
1477  std::string fileName = "history.hist";
1478  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
1479 
1480  std::remove(fullPath.c_str());
1481  __SUP_COUT__ << "Successfully deleted " << fullPath;
1482 }
1483 
1484 //========================================================================================================================
1485 void MacroMakerSupervisor::exportFEMacro(HttpXmlDocument& xmldoc,
1486  cgicc::Cgicc& cgi,
1487  const std::string& username)
1488 {
1489  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
1490  std::string pluginName = CgiDataUtilities::getData(cgi, "PluginName");
1491  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
1492  std::string macroNotes = CgiDataUtilities::decodeURIComponent(
1493  CgiDataUtilities::postData(cgi, "MacroNotes"));
1494 
1495  __SUP_COUTV__(pluginName);
1496  __SUP_COUTV__(macroName);
1497  __SUP_COUTV__(macroSequence);
1498 
1499  // replace all special characters with white space
1500  for(unsigned int i = 0; i < macroNotes.length(); ++i)
1501  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
1502  macroNotes[i] = ' ';
1503  __SUP_COUTV__(macroNotes);
1504 
1505  std::stringstream ss(macroSequence);
1506  std::string command;
1507  std::vector<std::string> commands;
1508 
1509  while(getline(ss, command, ','))
1510  commands.push_back(command);
1511 
1512  __SUP_COUTV__(StringMacros::vectorToString(commands));
1513 
1514  std::map<std::string /*special type*/, std::set<std::string> /*special file paths*/>
1515  specialsCodeMap = CodeEditor::getSpecialsMap();
1516 
1517  //__SUP_COUTV__(StringMacros::mapToString(specialsCodeMap));
1518  auto specialsCodeMapIt = specialsCodeMap.find(CodeEditor::SPECIAL_TYPE_FEInterface);
1519  if(specialsCodeMapIt == specialsCodeMap.end())
1520  {
1521  __SS__
1522  << "Could not find any FE Interface plugins in source code. Does MacroMaker "
1523  << "have access to the source code? Check that the Supervisor context places "
1524  "MacroMaker in a "
1525  << "location with access to the source code." << __E__;
1526  __SS_THROW__;
1527  }
1528 
1529  // find first .h and .cc with the plugin name
1530  std::string headerFile = pluginName + ".h";
1531  std::string sourceFile = pluginName + "_interface.cc";
1532  bool foundHeaderFile = false;
1533  bool foundSourceFile = false;
1534  for(const auto& filePath : specialsCodeMapIt->second)
1535  {
1536  if(!foundHeaderFile && filePath.find(headerFile) != std::string::npos)
1537  {
1538  foundHeaderFile = true;
1539  headerFile = filePath;
1540  __SUP_COUT__ << "found headerFile=" << filePath << __E__;
1541  }
1542  if(!foundSourceFile && filePath.find(sourceFile) != std::string::npos)
1543  {
1544  foundSourceFile = true;
1545  sourceFile = filePath;
1546  __SUP_COUT__ << "found sourceFile=" << filePath << __E__;
1547  }
1548 
1549  if(foundSourceFile && foundHeaderFile)
1550  break;
1551  } // end file search loop
1552 
1553  if(!foundHeaderFile)
1554  {
1555  __SS__ << "Could not find the header file for the FE Interface plugins at '"
1556  << headerFile << ".' Does MacroMaker "
1557  << "have access to the source code? Check that the Supervisor context "
1558  "places MacroMaker in a "
1559  << "location with access to the source code." << __E__;
1560  __SS_THROW__;
1561  }
1562  if(!foundSourceFile)
1563  {
1564  __SS__ << "Could not find the source file for the FE Interface plugins at '"
1565  << sourceFile << ".' Does MacroMaker "
1566  << "have access to the source code? Check that the Supervisor context "
1567  "places MacroMaker in a "
1568  << "location with access to the source code." << __E__;
1569  __SS_THROW__;
1570  }
1571 
1572  // at this point have header and source file, now add FE Macro
1573  // Steps for each file:
1574  // - read current file
1575  // - find insert point
1576  // - open file for writing
1577  // - write original file up to insert point
1578  // - insert new code
1579  // - write remaining original file
1580 
1581  char timeBuffer[100];
1582  { // get time string
1583  time_t rawtime;
1584  struct tm* timeinfo;
1585 
1586  time(&rawtime);
1587  timeinfo = localtime(&rawtime);
1588 
1589  strftime(timeBuffer, 100, "%b-%d-%Y %I:%M:%S", timeinfo);
1590  }
1591 
1592  std::string contents;
1593  std::string insert;
1594 
1596  // handle source file modifications
1597  CodeEditor::readFile(CodeEditor::SOURCE_BASE_PATH, sourceFile, contents);
1598  //__SUP_COUTV__(contents);
1599 
1600  // return file locations, for the user to inspect on error
1601  xmldoc.addTextElementToData("sourceFile", sourceFile);
1602  xmldoc.addTextElementToData("headerFile", headerFile);
1603 
1604  // check for duplicate functions
1605  if(contents.find(pluginName + "::" + macroName) != std::string::npos)
1606  {
1607  __SS__ << "The function definition '" << (pluginName + "::" + macroName)
1608  << "(...)' already exists in the source file '" << sourceFile
1609  << ".' Duplicate functions are not allowed - please rename the macro or "
1610  "modify the source file."
1611  << __E__;
1612  __SS_THROW__;
1613  }
1614 
1615  std::stringstream codess;
1616  std::set<std::string> inArgNames, outArgNames;
1617  createCode(codess,
1618  commands,
1619  "\t" /*tabOffset*/,
1620  true /*forFeMacro*/,
1621  &inArgNames,
1622  &outArgNames);
1623  __SUP_COUTV__(StringMacros::setToString(inArgNames));
1624  __SUP_COUTV__(StringMacros::setToString(outArgNames));
1625 
1626  // find start of constructor and register macro
1627  {
1628  auto insertPos = contents.find(pluginName + "::" + pluginName);
1629  if(insertPos == std::string::npos)
1630  {
1631  __SS__ << "Could not find the code insert position in the source file '"
1632  << sourceFile << ".' The FE plugin class constructor must be '"
1633  << pluginName << ":" << pluginName << "' - is this the case?" << __E__;
1634  __SS_THROW__;
1635  }
1636  __SUP_COUTV__(insertPos);
1637  // find opening bracket after constructor name
1638  insertPos = contents.find("{", insertPos);
1639  if(insertPos == std::string::npos)
1640  {
1641  __SS__ << "Could not find the code insert position in the source file '"
1642  << sourceFile
1643  << ".' The FE plugin class constructor must begin with '{"
1644  << "' - is this the case?" << __E__;
1645  __SS_THROW__;
1646  }
1647  ++insertPos; // go past {
1648  __SUP_COUTV__(insertPos);
1649 
1650  insert = "\n\t//registration of FEMacro '" + macroName + "' generated, " +
1651  timeBuffer + ", by '" + username + "' using MacroMaker.\n\t" +
1652  "FEVInterface::registerFEMacroFunction(\"" + macroName +
1653  "\",//feMacroName \n\t\t" +
1654  "static_cast<FEVInterface::frontEndMacroFunction_t>(&" + pluginName +
1655  "::" + macroName + "), //feMacroFunction \n\t\t" +
1656  "std::vector<std::string>{";
1657  { // insert input argument names
1658  bool first = true;
1659  for(const auto& inArg : inArgNames)
1660  {
1661  if(first)
1662  first = false;
1663  else
1664  insert += ",";
1665  insert += "\"" + inArg + "\"";
1666  }
1667  }
1668  insert += "}, //namesOfInputArgs \n\t\t";
1669  insert += "std::vector<std::string>{";
1670  { // insert output argument names
1671  bool first = true;
1672  for(const auto& outArg : outArgNames)
1673  {
1674  if(first)
1675  first = false;
1676  else
1677  insert += ",";
1678  insert += "\"" + outArg + "\"";
1679  }
1680  }
1681  insert += "}, //namesOfOutputArgs \n\t\t";
1682  insert += "1); //requiredUserPermissions \n\n";
1683 
1684  __SUP_COUTV__(insert);
1685  contents = contents.substr(0, insertPos) + insert + contents.substr(insertPos);
1686  }
1687 
1688  // find end of source to append FE Macro function
1689  {
1690  auto insertPos = contents.rfind("DEFINE_OTS_INTERFACE");
1691  if(insertPos == std::string::npos)
1692  {
1693  __SS__ << "Could not find the code insert position in the source file '"
1694  << sourceFile
1695  << ".' The FE plugin class must end with a 'DEFINE_OTS_INTERFACE("
1696  << pluginName << ")' - is this the case?" << __E__;
1697  __SS_THROW__;
1698  }
1699  __SUP_COUTV__(insertPos);
1700 
1701  insert =
1702  "\n//"
1703  "============================================================================"
1704  "============================================\n//" +
1705  macroName + "\n" + "//\tFEMacro '" + macroName + "' generated, " +
1706  timeBuffer + ", by '" + username + "' using MacroMaker.\n" +
1707  "//\tMacro Notes: " + macroNotes + "\n" + "void " + pluginName +
1708  "::" + macroName + "(__ARGS__)\n{\n\t" +
1709  "__CFG_COUT__ << \"# of input args = \" << argsIn.size() << __E__; \n\t" +
1710  "__CFG_COUT__ << \"# of output args = \" << argsOut.size() << __E__; \n\t" +
1711  "for(auto &argIn:argsIn) \n\t\t" +
1712  "__CFG_COUT__ << argIn.first << \": \" << argIn.second << __E__; \n\n\t" +
1713  "//macro commands section \n" + codess.str() + "\n\n\t" +
1714  "for(auto &argOut:argsOut) \n\t\t" +
1715  "__CFG_COUT__ << argOut.first << \": \" << argOut.second << __E__; \n\n" +
1716  "} //end " + macroName + "()\n\n";
1717 
1718  //__SUP_COUTV__(insert);
1719  CodeEditor::writeFile(CodeEditor::SOURCE_BASE_PATH,
1720  sourceFile,
1721  contents,
1722  "MacroMaker-" + username,
1723  insertPos,
1724  insert);
1725  }
1726 
1728  // handle include file insertions
1729  CodeEditor::readFile(CodeEditor::SOURCE_BASE_PATH, headerFile, contents);
1730  //__SUP_COUTV__(contents);
1731 
1732  // find end of class by looking for last };
1733  {
1734  auto insertPos = contents.rfind("};");
1735  if(insertPos == std::string::npos)
1736  {
1737  __SS__ << "Could not find the code insert position in the header file '"
1738  << headerFile
1739  << ".' The FE plugin class must end with a '};' - is this the case?"
1740  << __E__;
1741  __SS_THROW__;
1742  }
1743 
1744  __SUP_COUTV__(insertPos);
1745 
1746  insert = "\npublic: // FEMacro '" + macroName + "' generated, " + timeBuffer +
1747  ", by '" + username + "' using MacroMaker.\n\t" + "void " + macroName +
1748  "\t(__ARGS__);\n";
1749 
1750  __SUP_COUTV__(insert);
1751  CodeEditor::writeFile(CodeEditor::SOURCE_BASE_PATH,
1752  headerFile,
1753  contents,
1754  "MacroMaker-" + username,
1755  insertPos,
1756  insert);
1757  }
1758 
1759 } // end exportFEMacro ()
1760 
1761 //========================================================================================================================
1762 void MacroMakerSupervisor::exportMacro(HttpXmlDocument& xmldoc,
1763  cgicc::Cgicc& cgi,
1764  const std::string& username)
1765 {
1766  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
1767  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
1768  std::string macroNotes = CgiDataUtilities::decodeURIComponent(
1769  CgiDataUtilities::postData(cgi, "MacroNotes"));
1770 
1771  __SUP_COUTV__(macroName);
1772  __SUP_COUTV__(macroSequence);
1773 
1774  // replace all special characters with white space
1775  for(unsigned int i = 0; i < macroNotes.length(); ++i)
1776  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
1777  macroNotes[i] = ' ';
1778  __SUP_COUTV__(macroNotes);
1779 
1780  std::stringstream ss(macroSequence);
1781  std::string command;
1782  std::vector<std::string> commands;
1783 
1784  while(getline(ss, command, ','))
1785  commands.push_back(command);
1786 
1787  std::string fileName = macroName + ".cc";
1788 
1789  std::string fullPath = (std::string)MACROS_EXPORT_PATH + username + "/" + fileName;
1790  __SUP_COUT__ << fullPath << __E__;
1791  std::ofstream exportFile(fullPath.c_str(), std::ios::trunc);
1792  if(exportFile.is_open())
1793  {
1794  exportFile << "//Generated Macro Name:\t" << macroName << "\n";
1795  exportFile << "//Macro Notes: " << macroNotes << "\n";
1796 
1797  {
1798  time_t rawtime;
1799  struct tm* timeinfo;
1800  char buffer[100];
1801 
1802  time(&rawtime);
1803  timeinfo = localtime(&rawtime);
1804 
1805  strftime(buffer, 100, "%b-%d-%Y %I:%M:%S", timeinfo);
1806  exportFile << "//Generated Time: \t\t" << buffer << "\n";
1807  }
1808 
1809  exportFile << "//Paste this whole file into an interface to transfer Macro "
1810  "functionality.\n";
1811 
1812  createCode(exportFile, commands);
1813 
1814  exportFile.close();
1815 
1816  xmldoc.addTextElementToData("ExportFile", fullPath);
1817  }
1818  else
1819  __SUP_COUT__ << "Unable to open file" << __E__;
1820 }
1821 
1822 //========================================================================================================================
1823 // createCode
1824 void MacroMakerSupervisor::createCode(std::ostream& out,
1825  const std::vector<std::string>& commands,
1826  const std::string& tabOffset,
1827  bool forFeMacro,
1828  std::set<std::string>* inArgNames,
1829  std::set<std::string>* outArgNames)
1830 {
1831  int numOfHexBytes;
1832  std::set<std::string /*argInName*/> argInHasBeenInitializedSet;
1833  bool addressIsVariable, dataIsVariable;
1834 
1835  out << tabOffset << "{";
1836 
1837  out << "\n"
1838  << tabOffset << "\t"
1839  << "char *address \t= new char[universalAddressSize_]{0}; //create address "
1840  "buffer of interface size and init to all 0";
1841  out << "\n"
1842  << tabOffset << "\t"
1843  << "char *data \t\t= new char[universalDataSize_]{0}; //create data buffer "
1844  "of interface size and init to all 0";
1845 
1846  out << "\n"
1847  << tabOffset << "\t"
1848  << "uint64_t macroAddress; //create macro address buffer (size 8 bytes)";
1849  out << "\n"
1850  << tabOffset << "\t"
1851  << "uint64_t macroData; //create macro address buffer (size 8 bytes)";
1852 
1853  out << "\n"
1854  << tabOffset << "\t"
1855  << "std::map<std::string /*arg name*/,uint64_t /*arg val*/> macroArgs; //create "
1856  "map from arg name to 64-bit number";
1857 
1858  // loop through each macro command
1859  for(unsigned int i = 0; i < commands.size(); i++)
1860  {
1861  std::stringstream sst(commands[i]);
1862  std::string tokens;
1863  std::vector<std::string>
1864  oneCommand; // 4 fields: cmd index | cmd type | addr | data
1865  while(getline(sst, tokens, ':'))
1866  oneCommand.push_back(tokens);
1867  while(oneCommand.size() < 4)
1868  oneCommand.push_back(""); // fill out the 4 fields
1869 
1870  __SUP_COUTV__(StringMacros::vectorToString(oneCommand));
1871 
1872  // make this:
1873  // std::map<std::string,uint64_t> macroArgs;
1874  // {
1875  // uint64_t address = 0x1001; //create address buffer
1876  // uint64_t data = 0x100203; //create data buffer
1877  //
1878  // universalWrite(address,data);
1879  // universalRead(address,data);
1880  // }
1881  //
1882  // //if variable, first time init
1883  // {
1884  // address =
1885  // theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode("variableName").getValue<uint64_t>();
1886  // or
1887  // address = __GET_ARG_IN__("variableName",uint64_t);
1888  // }
1889  //
1890  // //if variable, second time use macroArgs
1891  // {
1892  // address = macroArgs["variableName"];
1893  // data = macroArgs["variableName"];
1894  // }
1895 
1896  addressIsVariable = isArgumentVariable(oneCommand[2]);
1897  dataIsVariable = isArgumentVariable(oneCommand[3]);
1898 
1899  __SUP_COUTV__(addressIsVariable);
1900  __SUP_COUTV__(dataIsVariable);
1901 
1902  out << "\n\n" << tabOffset << "\t// command-#" << i << ": ";
1903 
1904  if(oneCommand[1][0] == 'w' || oneCommand[1][0] == 'r')
1905  {
1906  if(oneCommand[1][0] == 'w')
1907  out << "Write(";
1908  else if(oneCommand[1][0] == 'r')
1909  out << "Read(";
1910 
1911  if(addressIsVariable)
1912  out << oneCommand[2];
1913  else // literal hex address
1914  out << "0x" << oneCommand[2];
1915  out << " /*address*/,";
1916 
1917  if(dataIsVariable) // read or write can have variable data, sink or source
1918  // respectively
1919  out << oneCommand[3] << " /*data*/";
1920  else if(oneCommand[1][0] == 'w') // literal hex data
1921  out << "0x" << oneCommand[3] << " /*data*/";
1922  else if(oneCommand[1][0] == 'r') // just reading to buffer
1923  out << "data";
1924  out << ");\n";
1925  }
1926  else if(oneCommand[1][0] == 'd')
1927  {
1928  out << "delay(" << oneCommand[2] << ");\n";
1929  out << tabOffset << "\t"
1930  << "__CFG_COUT__ << \"Sleeping for... \" << " << oneCommand[2]
1931  << " << \" milliseconds \" << __E__;\n";
1932  out << tabOffset << "\t"
1933  << "usleep(" << oneCommand[2] << "*1000 /* microseconds */);\n";
1934  continue;
1935  }
1936  else
1937  {
1938  __SS__ << "FATAL ERROR: Unknown command '" << oneCommand[1]
1939  << "'... command is not w, r or d" << __E__;
1940  __SS_THROW__;
1941  }
1942 
1944  // handle address
1945  if(addressIsVariable) // handle address as variable
1946  {
1947  if(argInHasBeenInitializedSet.find(oneCommand[2]) ==
1948  argInHasBeenInitializedSet.end()) // only initialize input argument once
1949  {
1950  argInHasBeenInitializedSet.emplace(oneCommand[2]);
1951 
1952  if(!forFeMacro)
1953  {
1954  // get address from configuration Tree
1955  out << tabOffset << "\t"
1956  << "macroArgs[\"" << oneCommand[2]
1957  << "\"] = "
1958  "theXDAQContextConfigTree_.getNode(theConfigurationPath_)."
1959  "getNode("
1960  << "\n"
1961  << tabOffset << "\t\t\"" << oneCommand[2]
1962  << "\").getValue<uint64_t>();";
1963  }
1964  else
1965  {
1966  if(inArgNames)
1967  inArgNames->emplace(oneCommand[2]);
1968 
1969  // get address from arguments
1970  out << tabOffset << "\t"
1971  << "macroArgs[\"" << oneCommand[2] << "\"] = __GET_ARG_IN__(\""
1972  << oneCommand[2] << "\", uint64_t);";
1973  }
1974  }
1975  out << "\t//get macro address argument";
1976  out << "\n"
1977  << tabOffset << "\tmemcpy(address,&macroArgs[\"" << oneCommand[2]
1978  << "\"],8); //copy macro address argument to buffer";
1979  }
1980  else // handle address as literal
1981  {
1982  out << tabOffset << "\t"
1983  << "macroAddress = 0x" << oneCommand[2]
1984  << "; memcpy(address,&macroAddress,8);"
1985  << "\t//copy macro address to buffer";
1986  }
1987 
1989  // handle data
1990  if(oneCommand[1] == "w") // if write, handle data too
1991  {
1992  if(dataIsVariable) // handle data as variable
1993  {
1994  if(argInHasBeenInitializedSet.find(oneCommand[3]) ==
1995  argInHasBeenInitializedSet
1996  .end()) // only initialize input argument once
1997  {
1998  argInHasBeenInitializedSet.emplace(oneCommand[3]);
1999 
2000  if(forFeMacro)
2001  {
2002  if(inArgNames)
2003  inArgNames->emplace(oneCommand[3]);
2004 
2005  // get data from arguments
2006  out << "\n"
2007  << tabOffset << "\t"
2008  << "macroArgs[\"" << oneCommand[3]
2009  << "\"] = __GET_ARG_IN__(\"" << oneCommand[3]
2010  << "\", uint64_t); //initialize from input arguments";
2011  }
2012  else
2013  {
2014  // get data from configuration Tree
2015  out << "\n"
2016  << tabOffset << "\t"
2017  << "macroArgs[\"" << oneCommand[3]
2018  << "\"] = "
2019  "theXDAQContextConfigTree_.getNode(theConfigurationPath_)."
2020  "getNode("
2021  << "\n"
2022  << tabOffset << "\t\t\"" << oneCommand[3]
2023  << "\").getValue<uint64_t>(); //initialize from "
2024  "configuration tree";
2025  }
2026  }
2027  out << "\t//get macro data argument";
2028  out << "\n"
2029  << tabOffset << "\tmemcpy(data,&macroArgs[\"" << oneCommand[3]
2030  << "\"],8); //copy macro data argument to buffer";
2031  }
2032  else // handle data as literal
2033  {
2034  out << "\n"
2035  << tabOffset << "\t"
2036  << "macroData = 0x" << oneCommand[3] << "; memcpy(data,&macroData,8);"
2037  << "\t//copy macro data to buffer";
2038  }
2039  out << "\n"
2040  << tabOffset << "\t"
2041  << "universalWrite(address,data);";
2042  }
2043  else
2044  {
2045  out << "\n"
2046  << tabOffset << "\t"
2047  << "universalRead(address,data);";
2048 
2049  std::string outputArgName;
2050 
2051  if(dataIsVariable) // handle data as variable
2052  outputArgName = oneCommand[3];
2053  else // give each read data a unique argument name
2054  {
2055  char str[20];
2056  sprintf(str, "outArg%d", i);
2057  outputArgName = str; // use command index for uniqueness
2058  }
2059  __SUP_COUTV__(outputArgName);
2060 
2061  out << tabOffset << "\t"
2062  << "memcpy(&macroArgs[\"" << outputArgName
2063  << "\"],data,8); //copy buffer to argument map";
2064 
2065  // copy read data to output args
2066  if(forFeMacro)
2067  out << "\n"
2068  << tabOffset << "\t"
2069  << "__SET_ARG_OUT__(\"" << outputArgName << "\",macroArgs[\""
2070  << outputArgName << "\"]); //update output argument result";
2071 
2072  if(outArgNames)
2073  outArgNames->emplace(outputArgName);
2074  argInHasBeenInitializedSet.emplace(
2075  outputArgName); // mark initialized since value has been read
2076  }
2077  } // end command loop
2078 
2079  out << "\n\n" << tabOffset << "\tdelete[] address; //free the memory";
2080  out << "\n" << tabOffset << "\tdelete[] data; //free the memory";
2081  out << "\n" << tabOffset << "}";
2082 
2083  __SUP_COUT__ << "Done with code generation." << __E__;
2084 } // end createCode()
2085 
2086 //========================================================================================================================
2087 // isArgumentVariable
2088 // returns true if string should be interpreted as a variable for MacroMaker
2089 bool MacroMakerSupervisor::isArgumentVariable(const std::string& argumentString)
2090 {
2091  for(unsigned int i = 0; i < argumentString.length(); ++i)
2092  {
2093  // detect non-hex
2094  if(!((argumentString[i] >= '0' && argumentString[i] <= '9') ||
2095  (argumentString[i] >= 'a' && argumentString[i] <= 'f') ||
2096  (argumentString[i] >= 'A' && argumentString[i] <= 'F')))
2097  return true;
2098  }
2099  return false;
2100 } // end isArgumentVariable()
2101 //========================================================================================================================
2102 // generateHexArray
2103 // returns a char array initializer
2104 // something like this
2105 // "[8] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09};"
2106 // ..depending a size of source string
2107 //
2108 // FIXME -- identify variables in a better way from macromaker...!
2109 // for now just assume a non hex is a variable name
2110 // return -1 size
2111 std::string MacroMakerSupervisor::generateHexArray(const std::string& sourceHexString,
2112  int& numOfBytes)
2113 {
2114  std::stringstream retSs;
2115 
2116  std::string srcHexStr = sourceHexString;
2117  __SUP_COUT__ << "Translating: \n";
2118  __SUP_COUT__ << srcHexStr << __E__;
2119 
2120  if(srcHexStr.size() % 2) // if odd, make even
2121  srcHexStr = "0" + srcHexStr;
2122 
2123  numOfBytes = srcHexStr.size() / 2;
2124  retSs << "[" << numOfBytes << "] = {";
2125 
2126  for(int i = 0; i < numOfBytes * 2; i += 2)
2127  {
2128  // detect non-hex
2129  if(!((srcHexStr[i] >= '0' && srcHexStr[i] <= '9') ||
2130  (srcHexStr[i] >= 'a' && srcHexStr[i] <= 'f') ||
2131  (srcHexStr[i] >= 'A' && srcHexStr[i] <= 'F')) ||
2132  !((srcHexStr[i + 1] >= '0' && srcHexStr[i + 1] <= '9') ||
2133  (srcHexStr[i + 1] >= 'a' && srcHexStr[i + 1] <= 'f') ||
2134  (srcHexStr[i + 1] >= 'A' && srcHexStr[i + 1] <= 'F')))
2135  {
2136  numOfBytes = -1;
2137  return srcHexStr;
2138  }
2139 
2140  if(i != 0)
2141  retSs << ", ";
2142  retSs << "0x" << srcHexStr[srcHexStr.size() - 1 - i - 1]
2143  << srcHexStr[srcHexStr.size() - 1 - i];
2144  }
2145  retSs << "};";
2146 
2147  __SUP_COUT__ << retSs.str() << __E__;
2148 
2149  return retSs.str();
2150 }
2151 
2152 //========================================================================================================================
2153 void MacroMakerSupervisor::runFEMacro(HttpXmlDocument& xmldoc,
2154  cgicc::Cgicc& cgi,
2155  const std::string& username) try
2156 {
2157  __SUP_COUT__ << __E__;
2158 
2159  // unsigned int feSupervisorID = CgiDataUtilities::getDataAsInt(cgi,
2160  // "feSupervisorID");
2161  std::string feClassSelected = CgiDataUtilities::getData(cgi, "feClassSelected");
2162  std::string feUIDSelected = CgiDataUtilities::getData(cgi, "feUIDSelected");
2163  std::string macroType = CgiDataUtilities::getData(cgi, "macroType");
2164  std::string macroName = CgiDataUtilities::getData(cgi, "macroName");
2165  std::string inputArgs = CgiDataUtilities::postData(cgi, "inputArgs");
2166  std::string outputArgs = CgiDataUtilities::postData(cgi, "outputArgs");
2167  bool saveOutputs = CgiDataUtilities::getDataAsInt(cgi, "saveOutputs") == 1;
2168 
2169  //__SUP_COUTV__(feSupervisorID);
2170  __SUP_COUTV__(feClassSelected);
2171  __SUP_COUTV__(feUIDSelected);
2172  __SUP_COUTV__(macroType);
2173  __SUP_COUTV__(macroName);
2174  __SUP_COUTV__(inputArgs);
2175  __SUP_COUTV__(outputArgs);
2176  __SUP_COUTV__(saveOutputs);
2177 
2178  std::set<std::string /*feUID*/> feUIDs;
2179 
2180  if(feUIDSelected == "")
2181  feUIDSelected = "*"; // treat empty as all
2182  if(feClassSelected == "")
2183  feClassSelected = "*"; // treat empty as all
2184 
2185  if(feClassSelected == "" || feUIDSelected == "" || macroType == "" || macroName == "")
2186  {
2187  __SUP_SS__ << "Illegal empty front-end parameter." << __E__;
2188  __SUP_SS_THROW__;
2189  }
2190  else if(feUIDSelected != "*")
2191  feUIDs.emplace(feUIDSelected);
2192  else // * all case
2193  {
2194  // add all FEs for type
2195  if(feClassSelected == "*")
2196  {
2197  for(auto& feTypePair : FEPluginTypetoFEsMap_)
2198  for(auto& feUID : feTypePair.second)
2199  feUIDs.emplace(feUID);
2200  }
2201  else
2202  {
2203  auto typeIt = FEPluginTypetoFEsMap_.find(feClassSelected);
2204  if(typeIt == FEPluginTypetoFEsMap_.end())
2205  {
2206  __SUP_SS__ << "Illegal front-end type parameter '" << feClassSelected
2207  << "' not in list of types." << __E__;
2208  __SUP_SS_THROW__;
2209  }
2210 
2211  for(auto& feUID : typeIt->second)
2212  feUIDs.emplace(feUID);
2213  }
2214  }
2215 
2216  __SUP_COUTV__(StringMacros::setToString(feUIDs));
2217 
2218  std::string macroString;
2219  if(macroType == "public")
2220  loadMacro(macroName, macroString);
2221  else if(macroType == "private")
2222  loadMacro(macroName, macroString, username);
2223 
2224  __SUP_COUTV__(macroString);
2225 
2226  FILE* fp = 0;
2227  try
2228  {
2229  if(saveOutputs)
2230  {
2231  std::string filename = "/macroOutput_" + std::to_string(time(0)) + "_" +
2232  std::to_string(clock()) + ".txt";
2233 
2234  __SUP_COUTV__(filename);
2235  fp = fopen((CodeEditor::OTSDAQ_DATA_PATH + filename).c_str(), "w");
2236  if(!fp)
2237  {
2238  __SUP_SS__ << "Failed to open file to save macro output '"
2239  << CodeEditor::OTSDAQ_DATA_PATH << filename << "'..." << __E__;
2240  __SUP_SS_THROW__;
2241  }
2242 
2243  fprintf(fp, "############################\n");
2244  fprintf(fp,
2245  "### Running '%s' at time %s\n",
2246  macroName.c_str(),
2247  StringMacros::getTimestampString().c_str());
2248  fprintf(fp,
2249  "### \t Target front-ends (count=%lu): %s\n",
2250  feUIDs.size(),
2251  StringMacros::setToString(feUIDs).c_str());
2252  fprintf(fp, "### \t\t Inputs: %s\n", inputArgs.c_str());
2253  fprintf(fp, "############################\n\n\n");
2254 
2255  xmldoc.addTextElementToData("outputArgs_name", "Filename");
2256  xmldoc.addTextElementToData("outputArgs_value", "$OTSDAQ_DATA/" + filename);
2257  }
2258 
2259  // do for all target front-ends
2260  for(auto& feUID : feUIDs)
2261  {
2262  auto feIt = FEtoSupervisorMap_.find(feUID);
2263  if(feIt == FEtoSupervisorMap_.end())
2264  {
2265  __SUP_SS__ << "Destination front end interface ID '" << feUID
2266  << "' was not found in the list of front ends." << __E__;
2267  ss << "\n\nHere is the map:\n\n"
2268  << StringMacros::mapToString(FEtoSupervisorMap_) << __E__;
2269  __SUP_SS_THROW__;
2270  }
2271 
2272  unsigned int FESupervisorIndex = feIt->second;
2273  __SUP_COUT__ << "Found supervisor index: " << FESupervisorIndex << __E__;
2274 
2275  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
2276  if(it == allFESupervisorInfo_.end())
2277  {
2278  __SUP_SS__
2279  << "Error transmitting request to FE Supervisor '" << feUID << ":"
2280  << FESupervisorIndex << ".' \n\n"
2281  << "The FE Supervisor Index does not exist. Have you configured "
2282  "the state machine properly?"
2283  << __E__;
2284  __SUP_SS_THROW__;
2285  }
2286 
2287  // send command to chosen FE and await response
2288  SOAPParameters txParameters; // params for xoap to send
2289  if(macroType == "fe")
2290  txParameters.addParameter("Request", "RunInterfaceMacro");
2291  else
2292  txParameters.addParameter("Request", "RunMacroMakerMacro");
2293  txParameters.addParameter("InterfaceID", feUID);
2294  if(macroType == "fe")
2295  txParameters.addParameter("feMacroName", macroName);
2296  else
2297  {
2298  txParameters.addParameter("macroName", macroName);
2299  txParameters.addParameter("macroString", macroString);
2300  }
2301  txParameters.addParameter("inputArgs", inputArgs);
2302  txParameters.addParameter("outputArgs", outputArgs);
2303 
2304  SOAPParameters rxParameters; // params for xoap to recv
2305  // rxParameters.addParameter("success");
2306  rxParameters.addParameter("outputArgs");
2307  rxParameters.addParameter("Error");
2308 
2309  if(saveOutputs)
2310  {
2311  fprintf(fp,
2312  "Running '%s' at time %s\n",
2313  macroName.c_str(),
2314  StringMacros::getTimestampString().c_str());
2315  fprintf(fp,
2316  "\t Target front-end: '%s::%s'\n",
2317  FEtoPluginTypeMap_[feUID].c_str(),
2318  feUID.c_str());
2319  fprintf(fp, "\t\t Inputs: %s\n", inputArgs.c_str());
2320  }
2321 
2322  // have FE supervisor descriptor, so send
2323  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
2324  it->second.getDescriptor(), // supervisor descriptor
2325  "MacroMakerSupervisorRequest",
2326  txParameters);
2327 
2328  __SUP_COUT__ << "Received response message: "
2329  << SOAPUtilities::translate(retMsg) << __E__;
2330 
2331  SOAPUtilities::receive(retMsg, rxParameters);
2332 
2333  __SUP_COUT__ << "Received it " << __E__;
2334 
2335  // bool success = rxParameters.getValue("success") == "1";
2336  std::string outputResults = rxParameters.getValue("outputArgs");
2337  std::string error = rxParameters.getValue("Error");
2338 
2339  //__SUP_COUT__ << "rx success = " << success << __E__;
2340  __SUP_COUT__ << "outputArgs = " << outputResults << __E__;
2341 
2342  if(error != "")
2343  {
2344  __SS__ << "Attempted FE Macro Failed. Attempted target "
2345  << "was UID=" << feUID
2346  << " at feSupervisorID=" << FESupervisorIndex << "." << __E__;
2347  ss << "\n\n The error was:\n\n" << error << __E__;
2348  __SUP_COUT_ERR__ << "\n" << ss.str();
2349  xmldoc.addTextElementToData("Error", ss.str());
2350 
2351  return;
2352  }
2353 
2354  // build output arguments
2355  // parse args, colon-separated pairs, and then comma-separated
2356  {
2357  std::istringstream inputStream(outputResults);
2358  std::string splitVal, argName, argValue;
2359  while(getline(inputStream, splitVal, ';'))
2360  {
2361  std::istringstream pairInputStream(splitVal);
2362  getline(pairInputStream, argName, ',');
2363  getline(pairInputStream, argValue, ',');
2364 
2365  if(saveOutputs)
2366  {
2367  fprintf(fp,
2368  "\t\t Output '%s' = %s\n",
2369  argName.c_str(),
2370  argValue.c_str());
2371  }
2372  else
2373  {
2374  xmldoc.addTextElementToData("outputArgs_name", argName);
2375  xmldoc.addTextElementToData("outputArgs_value", argValue);
2376  }
2377  __SUP_COUT__ << argName << ": " << argValue << __E__;
2378  }
2379  }
2380  } // end target front-end loop
2381  }
2382  catch(...) // handle file close on error
2383  {
2384  if(fp)
2385  fclose(fp);
2386  throw;
2387  }
2388 
2389  if(fp)
2390  fclose(fp);
2391 
2392 } // end runFEMacro()
2393 catch(const std::runtime_error& e)
2394 {
2395  __SUP_SS__ << "Error processing FE communication request: " << e.what() << __E__;
2396  __SUP_COUT_ERR__ << ss.str();
2397  xmldoc.addTextElementToData("Error", ss.str());
2398 }
2399 catch(...)
2400 {
2401  __SUP_SS__ << "Unknown error processing FE communication request." << __E__;
2402  __SUP_COUT_ERR__ << ss.str();
2403 
2404  xmldoc.addTextElementToData("Error", ss.str());
2405 } // end runFEMacro() catch
2406 
2407 //========================================================================================================================
2408 void MacroMakerSupervisor::getFEMacroList(HttpXmlDocument& xmldoc,
2409  const std::string& username)
2410 {
2411  __SUP_COUT__ << "Getting FE Macro list" << __E__;
2412 
2413  SOAPParameters txParameters; // params for xoap to send
2414  txParameters.addParameter("Request", "GetInterfaceMacros");
2415 
2416  SOAPParameters rxParameters; // params for xoap to recv
2417  rxParameters.addParameter("FEMacros");
2418 
2419  std::string oneInterface;
2420  std::string rxFEMacros;
2421 
2422  // for each list of FE Supervisors,
2423  // get all FE specific macros
2424  for(auto& appInfo : allFESupervisorInfo_)
2425  {
2426  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId()
2427  << " name = " << appInfo.second.getName() << __E__;
2428 
2429  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
2430  appInfo.second.getDescriptor(), "MacroMakerSupervisorRequest", txParameters);
2431  SOAPUtilities::receive(retMsg, rxParameters);
2432 
2433  rxFEMacros = rxParameters.getValue("FEMacros");
2434 
2435  __SUP_COUT__ << "FE Macros received: \n" << rxFEMacros << __E__;
2436 
2437  std::istringstream allInterfaces(rxFEMacros);
2438  while(std::getline(allInterfaces, oneInterface))
2439  {
2440  //__SUP_COUT__ << oneInterface << __E__;
2441  //__SUP_COUT__ << appInfo.second.getId() << __E__;
2442  xmldoc.addTextElementToData("FEMacros", oneInterface);
2443  // xmldoc.outputXmlDocument(0,true);
2444  }
2445  }
2446 
2447  // add macros to response
2448  std::pair<std::vector<std::string> /*public macros*/,
2449  std::vector<std::string> /*private macros*/>
2450  macroNames;
2451  loadMacroNames(username, macroNames);
2452 
2453  __SUP_COUT__ << "Public macro count: " << macroNames.first.size() << __E__;
2454  __SUP_COUT__ << "Private macro count: " << macroNames.second.size() << __E__;
2455 
2456  std::string macroString;
2457  // make xml ':' separated fields:
2458  // macro name
2459  // permissions string
2460  // number of inputs
2461  // inputs separated by :
2462  // number of outputs
2463  // outputs separated by :
2464 
2465  for(int i = 0; i < 2; ++i) // first is public, then private
2466  for(auto& macroName : (i ? macroNames.second : macroNames.first))
2467  {
2468  // get macro string
2469  loadMacro(macroName, macroString, username);
2470 
2471  // extract macro object
2472  FEVInterface::macroStruct_t macro(macroString);
2473 
2474  std::stringstream xmlMacroStream;
2475  xmlMacroStream << macro.macroName_;
2476  xmlMacroStream << ":"
2477  << "1"; // permissions string
2478  xmlMacroStream << ":" << macro.namesOfInputArguments_.size();
2479  for(auto& inputArg : macro.namesOfInputArguments_)
2480  xmlMacroStream << ":" << inputArg;
2481  xmlMacroStream << ":" << macro.namesOfOutputArguments_.size();
2482  for(auto& inputArg : macro.namesOfOutputArguments_)
2483  xmlMacroStream << ":" << inputArg;
2484 
2485  xmldoc.addTextElementToData(i ? "PrivateMacro" : "PublicMacro",
2486  xmlMacroStream.str());
2487  }
2488 
2489  return;
2490 }