otsdaq_utilities  v2_02_00
ControlsDashboardSupervisor.cc
1 #include "otsdaq-utilities/ControlsDashboard/ControlsDashboardSupervisor.h"
2 
3 #include <sys/stat.h> //for stat() quickly checking if file exists
4 #include <dirent.h> //for DIR
5 
6 //
7 //#include "otsdaq-core/MessageFacility/MessageFacility.h"
8 //#include "otsdaq-core/Macros/CoutMacros.h"
9 //
10 //#include <xdaq/NamespaceURI.h>
11 //#include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h"
12 //#include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
13 //#include "otsdaq-core/WebUsersUtilities/WebUsers.h"
14 //#include "otsdaq-core/SOAPUtilities/SOAPParameters.h"
15 //#include "otsdaq-core/ConfigurationPluginDataFormats/XDAQContextConfiguration.h"
16 //
17 //#include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
18 //
19 //
20 //#include <iostream>
21 //#include <fstream>
22 //#include <string>
23 //#include <thread> // std::this_thread::sleep_for
24 //#include <chrono> // std::chrono::seconds
25 //#include <errno.h>
26 
27 //#include "EpicsInterface.h.bkup"
28 #include "otsdaq-core/ControlsCore/ControlsVInterface.h"
29 #include "otsdaq-core/PluginMakers/MakeControls.h"
30 
31 
32 
33 using namespace ots;
34 
35 
36 #define PAGES_DIRECTORY std::string(getenv("SERVICE_DATA_PATH")) + "/ControlsDashboardData/pages/";
37 
38 
39 XDAQ_INSTANTIATOR_IMPL(ControlsDashboardSupervisor)
40 
41 //========================================================================================================================
42 ControlsDashboardSupervisor::ControlsDashboardSupervisor(xdaq::ApplicationStub* stub)
43 : CoreSupervisorBase(stub)
44 {
45  INIT_MF("ControlsDashboardSupervisor");
46 
47  init();
48 
49 }
50 
51 //========================================================================================================================
52 ControlsDashboardSupervisor::~ControlsDashboardSupervisor(void)
53 {
54  destroy();
55 }
56 
57 //========================================================================================================================
58 //setSupervisorPropertyDefaults
59 // override to set defaults for supervisor property values (before user settings override)
60 void ControlsDashboardSupervisor::setSupervisorPropertyDefaults()
61 {
62  CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.CheckUserLockRequestTypes,
63  "*");
64 }
65 
66 //========================================================================================================================
67 //forceSupervisorPropertyValues
68 // override to force supervisor property values (and ignore user settings)
69 void ControlsDashboardSupervisor::forceSupervisorPropertyValues()
70 {
71  CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
72  "poll");
73 }
74 
75 //========================================================================================================================
76 void ControlsDashboardSupervisor::request(const std::string& requestType, cgicc::Cgicc& cgiIn,
77  HttpXmlDocument& xmlOut, const WebUsers::RequestUserInfo& userInfo)
78 {
79 // __COUT__ << std::endl;
80 // cgicc::Cgicc cgi(in);
81 // __COUT__ << std::endl;
82 // std::string requestType = CgiDataUtilities::getData(cgi,"RequestType");
83 // __COUT__ << request << std::endl;
84 // __COUT__ << this->getApplicationDescriptor()->getLocalId() << " " << requestType << " : end"<< std::endl;
85 
86 
87 // if(requestType == "")
88 // {
89 // Default(in, out);
90 // return;
91 // }
92 //
93 // HttpXmlDocument xmldoc;
94 // uint64_t activeSessionIndex;
95 // std::string user;
96 // uint8_t userPermissions;
97 //
98 // //**** start LOGIN GATEWAY CODE ***//
99 // {
100 // bool automaticCommand = requestType == "poll"; //automatic commands should not refresh cookie code.. only user initiated commands should!
101 // bool checkLock = true;
102 // bool getUser = false;
103 // bool requireLock = false;
104 //
105 // if(!theRemoteWebUsers_.xmlRequestToGateway(
106 // cgi,
107 // out,
108 // &xmldoc,
109 // allSupervisorInfo_,
110 // &userPermissions, //acquire user's access level (optionally null pointer)
111 // !automaticCommand, //true/false refresh cookie code
112 // 1, //set access level requirement to pass gateway
113 // checkLock, //true/false enable check that system is unlocked or this user has the lock
114 // requireLock, //true/false requires this user has the lock to proceed
115 // 0,//&userWithLock, //acquire username with lock (optionally null pointer)
116 // //(getUser?&user:0), //acquire username of this user (optionally null pointer)
117 // &username,
118 // 0, //acquire user's Display Name
119 // &activeSessionIndex //acquire user's session index associated with the cookieCode
120 // ))
121 // { //failure
122 // __COUT__ << "Failed Login Gateway: " <<
123 // out->str() << std::endl; //print out return string on failure
124 // return;
125 // }
126 // }
127 // //**** end LOGIN GATEWAY CODE ***//
128 //
129 //
130 
131 
132  //return xml doc holding server response
133  __COUT__ << std::endl;
134 
135  if(requestType == "poll")
136  {
137  std::string uid = CgiDataUtilities::getOrPostData(cgiIn,"uid");
138  Poll(cgiIn, xmlOut, uid);
139  }
140  else if(requestType == "generateUID")
141  {
142  std::string pvList = CgiDataUtilities::getOrPostData(cgiIn,"PVList");
143  GenerateUID(cgiIn, xmlOut, pvList);
144  }
145  else if(requestType == "GetPVSettings")
146  {
147  std::string pvList = CgiDataUtilities::getOrPostData(cgiIn,"PVList");
148  GetPVSettings(cgiIn, xmlOut, pvList);
149  xmlOut.addTextElementToData("id", CgiDataUtilities::getData(cgiIn,"id"));
150  }
151  else if(requestType == "getList")
152  {
153  GetList(cgiIn, xmlOut);
154  }
155  else if(requestType == "getPages")
156  {
157  GetPages(cgiIn, xmlOut);
158  }
159  else if(requestType == "loadPage")
160  {
161  std::string page = CgiDataUtilities::getData(cgiIn,"Page");
162  __COUT__ << this->getApplicationDescriptor()->getLocalId() << " " << page << std::endl;
163 
164  loadPage(cgiIn, xmlOut, page);
165  }
166  __COUT__ << std::endl;
167 
168 
169  //xmlOut.outputXmlDocument((std::ostringstream*) out, true);
170 
171 
172 }
173 //========================================================================================================================
174 void ControlsDashboardSupervisor::init(void)
175 //called by constructor
176 {
177  UID_= 0;
178 
179  __COUT__ << std::endl;
180  std::string t = "test";
181  std::string nodeName = theConfigurationManager_->__GET_CONFIG__(XDAQContextConfiguration)->getConfigurationName();
182  __COUT__ << nodeName << std::endl;
183  ConfigurationTree node = theConfigurationManager_->getNode(nodeName);
184  __COUT__ << node << std::endl;
185 
186  interface_ = makeControls(
187  "ControlsOtsInterface"
188  , t /*Key Value*/
189  , node
190  , nodeName);
191  __COUT__ << std::endl;
192  //interface_->initialize();
193  //std::thread([&](){interface_->initialize();}).detach(); //thread completes after creating, subscribing, and getting parameters for all pvs
194 
195 }
196 //========================================================================================================================
197 void ControlsDashboardSupervisor::destroy(void)
198 {
199  //called by destructor
200  delete interface_;
201 }
202 
203 //========================================================================================================================
204 void ControlsDashboardSupervisor::Poll(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut, std::string UID )
205 {
206 
207  __COUT__ << this->getApplicationDescriptor()->getLocalId() << " " << "Polling on UID:" << UID << std::endl;
208 
209  std::map<int, std::set<std::string>>::iterator mapReference;
210 
211  if( UID != "" && (mapReference = pvDependencyLookupMap_.find(std::stoi(UID))) != pvDependencyLookupMap_.end()) //We have their current list of PV Dependencies
212  {
213  std::string JSONMessage = "{ ";
214 
215  for(auto pv : mapReference->second)
216  {
217  __COUT__ << pv << std::endl;
218  //PVInfo * pvInfo = interface_->mapOfPVInfo_.find(pv)->second;
219  //__COUT__ << pv << ":" << (pvInfo?"Good":"Bad") << std::endl;
220  //interface_->getCurrentPVValue(pv);
221  std::array<std::string, 4> pvInformation = interface_->getCurrentValue(pv);
222 
223  __COUT__ << pv << ": " << pvInformation[1] << " : " << pvInformation[3] << std::endl;
224 
225 
226  if(pvInformation[0] != "NO_CHANGE")
227  {
228  //__COUT__ << "Reached" << std::endl;
229  JSONMessage += "\"" + pv + "\": {";
230 
231  /*if(pvInfo->mostRecentBufferIndex - 1 < 0)
232  {
233  std::string value = pvInfo->dataCache[pvInfo->dataCache.size()].second
234  std::string time =
235  }*/
236 
237  JSONMessage += "\"Timestamp\" : \"" + pvInformation[0] + "\",";
238  JSONMessage += "\"Value\" : \"" + pvInformation[1] + "\",";
239  JSONMessage += "\"Status\" : \"" + pvInformation[2] + "\",";
240  JSONMessage += "\"Severity\" : \"" + pvInformation[3] + "\"},";
241 
242  }
243  else
244  {
245  __COUT__ << "No change in value since last poll: " << pv << std::endl;
246  }
247 
248  //Handle Channels that disconnect, etc
249  if(pvInformation[3] == "INVALID")
250  {
251  interface_->subscribe(pv);
252  }
253 
254 
255  //__COUT__ << pv << ":" << (pvInfo?"Good":"Bad") << std::endl;
256  //__COUT__ << pv << ":" << pvInfo->mostRecentBufferIndex -1 << std::endl;
257  //__COUT__ << pv << " : " << pvInfo->dataCache[(pvInfo->mostRecentBufferIndex -1)].second << std::endl;
258 
259  }
260 
261  JSONMessage = JSONMessage.substr(0, JSONMessage.length() - 1);
262  JSONMessage += "}";
263  __COUT__ << JSONMessage << std::endl;
264  xmlOut.addTextElementToData("JSON", JSONMessage); //add to response
265 
266  /*for (std::set<unsigned long>::iterator it = mapReference->second->begin(); it != mapReference->second.end(); ++it)
267  {
268  //__COUT__ << this->getApplicationDescriptor()->getLocalId() << it << std::endl;
269 
270 
271  }*/
272  /*std::string fakeData = std::string("{")
273  + "\"Mu2e_CompStatus_daq01/system_temperature\": \"40.5\","
274  + "\"Mu2e_CompStatus_daq01/load_one\": \"378.2\","
275  + "\"Mu2e_Weather_2/timestamp\": \"11.14.45.2016.4.8\","
276  + "\"Mu2e_CompStatus_daq01/system_temperature\": \"43.4\","
277  + "\"Mu2e_CompStatus_daq01/load_one\":\"80\","
278  + "\"Mu2e_Weather_2/timestamp\": \"11.14.45.2016.4.8\""
279  + "}";
280  xmlOut.addTextElementToData("JSON", fakeData); //add to response*/
281 
282 
283 
284 
285 
286  }
287  else // UID is not in our map so force them to generate a new one
288  {
289  xmlOut.addTextElementToData("JSON", "{ \"message\": \"NOT_FOUND\"}"); //add to response
290  }
291 }
292 //========================================================================================================================
293 void ControlsDashboardSupervisor::GetPVSettings(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut, std::string pvList )
294 {
295  __COUT__ << this->getApplicationDescriptor()->getLocalId() << " " << "Getting settings for " << pvList << std::endl;
296 
297  std::string JSONMessage = "{ ";
298 
299  std::string pv;
300  size_t pos = 0;
301  size_t nextPos;
302  size_t lastIndex = pvList.find_last_of(",");
303  std::cout << "**********************" << pvList.size() << std::endl;
304  if(pvList.size() > 0)
305  {
306 
307  while((nextPos = pvList.find(",", pos)) != std::string::npos)
308  {
309  pv = pvList.substr(pos, nextPos-pos);
310 
311 
312  __COUT__ << pv << std::endl;
313 
314  std::array<std::string, 9> pvSettings = interface_->getSettings(pv);
315 
316 
317  JSONMessage += "\"" + pv + "\": {";
318  JSONMessage += "\"Units \": \"" + pvSettings[0] + "\",";
319  JSONMessage += "\"Upper_Display_Limit\": \"" + pvSettings[1] + "\",";
320  JSONMessage += "\"Lower_Display_Limit\": \"" + pvSettings[2] + "\",";
321  JSONMessage += "\"Upper_Alarm_Limit \": \"" + pvSettings[3] + "\",";
322  JSONMessage += "\"Upper_Warning_Limit\": \"" + pvSettings[4] + "\",";
323  JSONMessage += "\"Lower_Warning_Limit\": \"" + pvSettings[5] + "\",";
324  JSONMessage += "\"Lower_Alarm_Limit \": \"" + pvSettings[6] + "\",";
325  JSONMessage += "\"Upper_Control_Limit\": \"" + pvSettings[7] + "\",";
326  JSONMessage += "\"Lower_Control_Limit\": \"" + pvSettings[8] + "\"},";
327 
328  pos = nextPos + 1;
329  }
330 
331  JSONMessage = JSONMessage.substr(0, JSONMessage.length() - 1);
332  JSONMessage += "}";
333 
334  __COUT__ << JSONMessage << std::endl;
335  xmlOut.addTextElementToData("JSON", JSONMessage); //add to response
336 
337  }
338  else
339  {
340  xmlOut.addTextElementToData("JSON", "{ \"message\": \"GetPVSettings\"}"); //add to response
341  }
342 
343 
344 
345 
346 }
347 //========================================================================================================================
348 void ControlsDashboardSupervisor::GenerateUID(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut, std::string pvlist )
349 {
350 
351  __COUT__ << this->getApplicationDescriptor()->getLocalId() << " " << "Generating UID" << std::endl;
352 
353  std::set<std::string> pvDependencies;
354  std::string uid;
355  std::string pv;
356  size_t pos = 0;
357  size_t nextPos;
358  size_t lastIndex = pvlist.find_last_of(",");
359 
360  if(pvlist.size() > 0)
361  {
362  //pvlist.substr(2);
363  __COUT__ << pvlist << std::endl;
364 
365  while((nextPos = pvlist.find(",", pos)) != std::string::npos)
366  {
367  pv = pvlist.substr(pos, nextPos-pos);
368  //__COUT__ << UID_ << ":" << pos << "-" << nextPos << " ->" << pv << std::endl;
369  pvDependencies.insert(pv);
370  pos = nextPos + 1;
371  }
372 
373  pvDependencyLookupMap_.insert(std::pair<int, std::set<std::string>> (++UID_, pvDependencies) );
374 
375  uid = (std::string("{ \"message\": \"") + std::to_string(UID_) +"\"}");
376  }else
377  {
378  __COUT__ << this->getApplicationDescriptor()->getLocalId() << " PVList invalid: " << pvlist << std::endl;
379  uid = "{ \"message\": \"-1\"}";
380  }
381 
382 
383  __COUT__ << this->getApplicationDescriptor()->getLocalId() << " NEW UID: " << UID_ << std::endl;
384 
385  xmlOut.addTextElementToData("JSON", uid); //add to response
386 
387 
388 }
389 //========================================================================================================================
390 void ControlsDashboardSupervisor::GetList(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut)
391 {
392 
393  __COUT__ << this->getApplicationDescriptor()->getLocalId() << std::endl;
394  std::cout << " " << interface_->getList("JSON") << std::endl;
395 
396  xmlOut.addTextElementToData("JSON", interface_->getList("JSON")); //add to response
397 
398 }
399 //========================================================================================================================
400 void ControlsDashboardSupervisor::GetPages(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut)
401 {
402  /*DIR * dir;
403  struct dirent * ent;
404  std::string pathToPages = PAGES_DIRECTORY;
405 
406  std::vector<std::string> pages;
407 
408  __COUT__ << this->getApplicationDescriptor()->getLocalId() << "Path to pages: " << pathToPages << std::endl;
409  if((dir = opendir (pathToPages.c_str())) != NULL)
410  {
411  while((ent = readdir(dir)) != NULL)
412  {
413  pages.push_back(ent->d_name);
414  __COUT__ << this->getApplicationDescriptor()->getLocalId() << " GetPages" << ent->d_name << std::endl;
415  }
416  closedir(dir);
417  }
418  else
419  {
420  __COUT__ << this->getApplicationDescriptor()->getLocalId() << "Could not open directory: " << pathToPages << std::endl;
421  return;
422  }*/
423  std::vector<std::string> pages;
424 
425  listFiles("", true, &pages);
426 
427  std::string returnJSON = "[";
428  for(auto it = pages.begin(); it != pages.end(); it++)
429  {
430  if(*it != "." && *it != "..")
431  returnJSON += "\"" + *it + "\", ";
432  }
433  if(returnJSON.size() > 2 && returnJSON.compare("[") != 0)
434  {
435  __COUT__ << "Found pages on server!" << std::endl;
436  returnJSON.resize(returnJSON.size()-2);
437  returnJSON += "]";
438  }
439  else
440  {
441  //No pages on the server
442  __COUT__ << "No pages found on server!" << std::endl;
443  returnJSON = "[\"None\"]";
444  }
445  std::cout << returnJSON << std::endl;
446 
447  xmlOut.addTextElementToData("JSON", returnJSON); //add to response
448 
449 }
450 //========================================================================================================================
451 void ControlsDashboardSupervisor::loadPage(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut, std::string page )
452 {
453  //FIXME Filter out malicious attacks i.e. ../../../../../ stuff
454  struct stat buffer;
455  if(page.find("..") != std::string::npos)
456  {
457  __COUT__ << this->getApplicationDescriptor()->getLocalId() << "Error! Request using '..': " << page << std::endl;
458  }
459  else if (page.find("~") != std::string::npos)
460  {
461  __COUT__ << this->getApplicationDescriptor()->getLocalId() << "Error! Request using '~': " << page << std::endl;
462  }
463  else if(!(stat(page.c_str(), &buffer) == 0))
464  {
465  __COUT__ << this->getApplicationDescriptor()->getLocalId() << "Error! File not found: " << page << std::endl;
466  }
467 
468  std::string file = PAGES_DIRECTORY
469  file += "/" + page;
470  __COUT__ << this->getApplicationDescriptor()->getLocalId() << "Trying to load page: " << page << std::endl;
471  __COUT__ << this->getApplicationDescriptor()->getLocalId() << "Trying to load page: " << file << std::endl;
472  //read file
473  //for each line in file
474 
475  std::ifstream infile(file);
476  std::cout << "Reading file" << std::endl;
477  std::string JSONpage = "";
478  for(std::string line; getline(infile, line);)
479  {
480  std::cout << line << std::endl;
481  JSONpage += line;
482  }
483  std::cout << "Finished reading file" << std::endl;
484 
485  xmlOut.addTextElementToData("JSON", JSONpage); //add to response
486 
487 }
488 //========================================================================================================================
489 void ControlsDashboardSupervisor::Subscribe(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut)
490 {
491 
492 
493 }
494 //========================================================================================================================
495 void ControlsDashboardSupervisor::Unsubscribe(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut)
496 {
497 
498 
499 }
500 //========================================================================================================================
501 //========================================================================================================================
502 //================================================== UTILITIES ===========================================================
503 //========================================================================================================================
504 bool ControlsDashboardSupervisor::isDir(std::string dir)
505 {
506  struct stat fileInfo;
507  stat(dir.c_str(), &fileInfo);
508  if (S_ISDIR(fileInfo.st_mode))
509  {
510  return true;
511  }
512  else
513  {
514  return false;
515  }
516 }
517 //========================================================================================================================
518 void ControlsDashboardSupervisor::listFiles(std::string baseDir, bool recursive, std::vector<std::string> * pages )
519 {
520  std::string base = PAGES_DIRECTORY;
521  base += baseDir;
522 
523  DIR *dp;
524  struct dirent *dirp;
525  if ((dp = opendir(base.c_str())) == NULL) {
526  std::cout << "[ERROR: " << errno << " ] Couldn't open " << base << "." << std::endl;
527  return;
528  }
529  else
530  {
531  while ((dirp = readdir(dp)) != NULL) {
532  if (dirp->d_name != std::string(".") && dirp->d_name != std::string(".."))
533  {
534  if (isDir(base + dirp->d_name) == true && recursive == true)
535  {
536  //pages->push_back(baseDir + dirp->d_name);
537  std::cout << "[DIR]\t" << baseDir << dirp->d_name << "/" << std::endl;
538  listFiles(baseDir + dirp->d_name + "/", true, pages);
539  }
540  else
541  {
542  pages->push_back(baseDir + dirp->d_name);
543  std::cout << "[FILE]\t" << baseDir << dirp->d_name << std::endl;
544  }
545  }
546  }
547  closedir(dp);
548  }
549 }
550 
551 
552