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