1 #include "otsdaq-utilities/ControlsDashboard/ControlsDashboardSupervisor.h"
6 #include "otsdaq/PluginMakers/MakeSlowControls.h"
7 #include "otsdaq/SlowControlsCore/SlowControlsVInterface.h"
11 #define CONTROLS_SUPERVISOR_DATA_PATH \
12 std::string(__ENV__("SERVICE_DATA_PATH")) + "/ControlsDashboardData/"
13 #define PAGES_DIRECTORY CONTROLS_SUPERVISOR_DATA_PATH + "pages/"
19 : CoreSupervisorBase(stub)
21 __SUP_COUT__ <<
"Constructor." << __E__;
23 INIT_MF(
"ControlsDashboardSupervisor");
26 mkdir(((std::string)(CONTROLS_SUPERVISOR_DATA_PATH)).c_str(), 0755);
27 mkdir(((std::string)(PAGES_DIRECTORY)).c_str(), 0755);
35 __SUP_COUT__ <<
"Constructed." << __E__;
39 ControlsDashboardSupervisor::~ControlsDashboardSupervisor(
void)
41 __SUP_COUT__ <<
"Destructor." << __E__;
43 __SUP_COUT__ <<
"Destructed." << __E__;
47 void ControlsDashboardSupervisor::destroy(
void)
54 void ControlsDashboardSupervisor::init(
void)
59 __SUP_COUT__ << std::endl;
60 ConfigurationTree node = CorePropertySupervisorBase::getSupervisorTableNode();
61 std::string pluginType =
62 CorePropertySupervisorBase::getSupervisorProperty(
"ControlsInterfacePluginType");
64 std::string supervisorConfigurationPath =
65 "/" + CorePropertySupervisorBase::getContextUID() +
"/LinkToApplicationTable/" +
66 CorePropertySupervisorBase::getSupervisorUID();
68 interface_ = makeSlowControls(pluginType,
69 CorePropertySupervisorBase::getSupervisorUID(),
70 CorePropertySupervisorBase::getContextTreeNode(),
71 supervisorConfigurationPath);
72 __COUT__ << std::endl;
81 std::lock_guard<std::mutex> lock(cs->pluginBusyMutex_);
83 cs->interface_->initialize();
89 __SUP_COUT__ <<
"Finished init() w/ interface: " << pluginType << std::endl;
97 void ControlsDashboardSupervisor::setSupervisorPropertyDefaults()
99 CorePropertySupervisorBase::setSupervisorProperty(
100 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.CheckUserLockRequestTypes,
"*");
106 void ControlsDashboardSupervisor::forceSupervisorPropertyValues()
108 CorePropertySupervisorBase::setSupervisorProperty(
109 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
"poll");
113 void ControlsDashboardSupervisor::request(
const std::string& requestType,
115 HttpXmlDocument& xmlOut,
116 const WebUsers::RequestUserInfo& userInfo)
120 if(requestType !=
"getPages" && !pluginBusyMutex_.try_lock())
122 __SUP_SS__ <<
"Controls plugin is still initializing. Please try again in a "
128 __SUP_COUT__ <<
"User name is " << userInfo.username_ <<
"." << __E__;
129 __SUP_COUT__ <<
"User permission level for request '" << requestType <<
"' is "
130 << unsigned(userInfo.permissionLevel_)
131 <<
"(isAdmin=" << (userInfo.isAdmin() ?
"Yes" :
"No") <<
")."
135 handleRequest(requestType, xmlOut, cgiIn, userInfo);
137 catch(
const std::runtime_error& e)
139 __SUP_SS__ <<
"Error occurred handling request '" << requestType
140 <<
"': " << e.what() << __E__;
141 __SUP_COUT__ << ss.str();
142 xmlOut.addTextElementToData(
"Error", ss.str());
146 __SS__ <<
"Unknown error occurred handling request '" << requestType <<
"!'"
148 __SUP_COUT__ << ss.str();
149 xmlOut.addTextElementToData(
"Error", ss.str());
152 pluginBusyMutex_.unlock();
157 void ControlsDashboardSupervisor::handleRequest(
const std::string Command,
158 HttpXmlDocument& xmlOut,
160 const WebUsers::RequestUserInfo& userInfo)
163 __SUP_COUT__ << std::endl;
165 if(Command ==
"poll")
167 std::string uid = CgiDataUtilities::getOrPostData(cgiIn,
"uid");
168 Poll(cgiIn, xmlOut, uid);
170 else if(Command ==
"generateUID")
172 std::string pvList = CgiDataUtilities::getOrPostData(cgiIn,
"PVList");
173 GenerateUID(cgiIn, xmlOut, pvList);
175 else if(Command ==
"isUserAdmin")
177 std::string json = std::string(
"{ \"message\": \"");
178 json += (userInfo.isAdmin() ?
"Yes" :
"No");
180 xmlOut.addTextElementToData(
"JSON", json.c_str());
182 else if(Command ==
"getUserPermissions")
184 GetUserPermissions(cgiIn, xmlOut, userInfo);
186 else if(Command ==
"getPVSettings")
188 __SUP_COUT__ <<
"PV settings requested from server! " << std::endl;
189 GetPVSettings(cgiIn, xmlOut);
190 xmlOut.addTextElementToData(
"id", CgiDataUtilities::getData(cgiIn,
"id"));
192 else if(Command ==
"getPVArchiverData")
194 __SUP_COUT__ <<
"Archived PV data requested from server! " << std::endl;
195 GetPVArchiverData(cgiIn, xmlOut);
197 else if(Command ==
"getList")
199 __SUP_COUT__ <<
"PV List requested from server! " << std::endl;
200 GetList(cgiIn, xmlOut);
202 else if(Command ==
"getPages")
204 __SUP_COUT__ <<
"Requesting pages from server! " << std::endl;
205 GetPages(cgiIn, xmlOut);
207 else if(Command ==
"loadPage")
209 std::string page = CgiDataUtilities::getData(cgiIn,
"Page");
210 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId() <<
" " << page
213 loadPage(cgiIn, xmlOut, page, userInfo);
215 else if(Command ==
"createControlsPage")
217 SaveControlsPage(cgiIn, xmlOut, userInfo);
226 __SUP_COUT__ <<
"" << std::endl;
232 void ControlsDashboardSupervisor::Poll(cgicc::Cgicc& cgiIn,
233 HttpXmlDocument& xmlOut,
236 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId() <<
" "
237 <<
"Polling on UID:" << UID << std::endl;
239 std::map<int, std::set<std::string>>::iterator mapReference;
242 (mapReference = pvDependencyLookupMap_.find(std::stoi(UID))) !=
243 pvDependencyLookupMap_.end())
245 std::string JSONMessage =
"{ ";
247 for(
auto pv : mapReference->second)
249 __SUP_COUT__ << pv << std::endl;
253 std::array<std::string, 4> pvInformation = interface_->getCurrentValue(pv);
254 __SUP_COUT__ << pv <<
": " << pvInformation[1] <<
" : " << pvInformation[3]
257 if(pvInformation[0] !=
"NO_CHANGE")
260 JSONMessage +=
"\"" + pv +
"\": {";
268 JSONMessage +=
"\"Timestamp\":\"" + pvInformation[0] +
"\",";
269 JSONMessage +=
"\"Value\":\"" + pvInformation[1] +
"\",";
270 JSONMessage +=
"\"Status\":\"" + pvInformation[2] +
"\",";
271 JSONMessage +=
"\"Severity\":\"" + pvInformation[3] +
"\"},";
275 __SUP_COUT__ <<
"No change in value since last poll: " << pv << std::endl;
279 if(pvInformation[3] ==
"INVALID")
281 interface_->subscribe(pv);
290 JSONMessage = JSONMessage.substr(0, JSONMessage.length() - 1);
292 __SUP_COUT__ << JSONMessage << std::endl;
293 xmlOut.addTextElementToData(
"JSON", JSONMessage);
317 xmlOut.addTextElementToData(
"JSON",
318 "{ \"message\": \"NOT_FOUND\"}");
322 void ControlsDashboardSupervisor::GetPVSettings(cgicc::Cgicc& cgiIn,
323 HttpXmlDocument& xmlOut)
325 std::string pvList = CgiDataUtilities::postData(cgiIn,
"PVList");
327 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId() <<
" "
328 <<
"Getting settings for " << pvList << std::endl;
330 std::string JSONMessage =
"{ ";
335 size_t lastIndex = pvList.find_last_of(
",");
336 std::cout <<
"**********************" << pvList.size() << std::endl;
337 if(pvList.size() > 0)
339 while((nextPos = pvList.find(
",", pos)) != std::string::npos)
341 pv = pvList.substr(pos, nextPos - pos);
343 __SUP_COUT__ << pv << std::endl;
345 std::array<std::string, 9> pvSettings = interface_->getSettings(pv);
347 JSONMessage +=
"\"" + pv +
"\": {";
348 JSONMessage +=
"\"Units\": \"" + pvSettings[0] +
"\",";
349 JSONMessage +=
"\"Upper_Display_Limit\": \"" + pvSettings[1] +
"\",";
350 JSONMessage +=
"\"Lower_Display_Limit\": \"" + pvSettings[2] +
"\",";
351 JSONMessage +=
"\"Upper_Alarm_Limit\": \"" + pvSettings[3] +
"\",";
352 JSONMessage +=
"\"Upper_Warning_Limit\": \"" + pvSettings[4] +
"\",";
353 JSONMessage +=
"\"Lower_Warning_Limit\": \"" + pvSettings[5] +
"\",";
354 JSONMessage +=
"\"Lower_Alarm_Limit\": \"" + pvSettings[6] +
"\",";
355 JSONMessage +=
"\"Upper_Control_Limit\": \"" + pvSettings[7] +
"\",";
356 JSONMessage +=
"\"Lower_Control_Limit\": \"" + pvSettings[8] +
"\"},";
361 JSONMessage = JSONMessage.substr(0, JSONMessage.length() - 1);
364 __SUP_COUT__ << JSONMessage << std::endl;
365 xmlOut.addTextElementToData(
"JSON", JSONMessage);
369 __SUP_COUT__ <<
"Did not find any settings because PV list is length zero!"
372 xmlOut.addTextElementToData(
373 "JSON",
"{ \"message\": \"GetPVSettings\"}");
378 void ControlsDashboardSupervisor::GetPVArchiverData(cgicc::Cgicc& cgiIn,
379 HttpXmlDocument& xmlOut)
381 __SUP_COUT__ <<
"Requesting archived data!" << std::endl;
412 std::string data_retrieval_url =
"";
413 std::string data_retrieval_servlet =
"";
414 std::string mime_type =
".json";
417 std::string pv, from, to;
424 std::string req = data_retrieval_url + data_retrieval_servlet + mime_type +
"?" +
425 "pv=" + pv +
"&from=" + from +
"&to=" + to;
427 std::string response =
"";
433 void ControlsDashboardSupervisor::GetUserPermissions(
435 HttpXmlDocument& xmlOut,
436 const WebUsers::RequestUserInfo& userInfo)
441 void ControlsDashboardSupervisor::GenerateUID(cgicc::Cgicc& cgiIn,
442 HttpXmlDocument& xmlOut,
445 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId() <<
" "
446 <<
"Generating UID" << std::endl;
448 std::set<std::string> pvDependencies;
453 size_t lastIndex = pvlist.find_last_of(
",");
455 if(pvlist.size() > 0)
458 __SUP_COUT__ << pvlist << std::endl;
460 while((nextPos = pvlist.find(
",", pos)) != std::string::npos)
462 pv = pvlist.substr(pos, nextPos - pos);
465 pvDependencies.insert(pv);
469 pvDependencyLookupMap_.insert(
470 std::pair<
int, std::set<std::string>>(++UID_, pvDependencies));
472 uid = (std::string(
"{ \"message\": \"") + std::to_string(UID_) +
"\"}");
476 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId()
477 <<
" PVList invalid: " << pvlist << std::endl;
478 uid =
"{ \"message\": \"-1\"}";
481 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId() <<
" NEW UID: " << UID_
484 xmlOut.addTextElementToData(
"JSON", uid);
488 void ControlsDashboardSupervisor::GetList(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut)
490 if(interface_ != NULL)
492 __SUP_COUT__ <<
"Interface is defined! Attempting to get list!" << std::endl;
494 std::cout <<
" " << interface_->getList(
"JSON") << std::endl;
496 xmlOut.addTextElementToData(
"JSON",
497 interface_->getList(
"JSON"));
501 __SUP_COUT__ <<
"Interface undefined! Failed to get list!" << std::endl;
502 xmlOut.addTextElementToData(
"JSON",
"[\"None\"]");
507 void ControlsDashboardSupervisor::GetPages(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut)
532 std::vector<std::string> pages;
534 listFiles(
"",
true, &pages);
536 std::string returnJSON =
"[";
537 for(
auto it = pages.begin(); it != pages.end(); it++)
539 if(*it !=
"." && *it !=
"..")
540 returnJSON +=
"\"" + *it +
"\", ";
542 if(returnJSON.size() > 2 && returnJSON.compare(
"[") != 0)
544 __SUP_COUT__ <<
"Found pages on server!" << std::endl;
545 returnJSON.resize(returnJSON.size() - 2);
551 __SUP_COUT__ <<
"No pages found on server!" << std::endl;
552 returnJSON =
"[\"None\"]";
554 std::cout << returnJSON << std::endl;
556 xmlOut.addTextElementToData(
"JSON", returnJSON);
560 void ControlsDashboardSupervisor::loadPage(cgicc::Cgicc& cgiIn,
561 HttpXmlDocument& xmlOut,
563 const WebUsers::RequestUserInfo& userInfo)
565 page = StringMacros::decodeURIComponent(page);
569 if(page.find(
"..") != std::string::npos)
571 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId()
572 <<
"Error! Request using '..': " << page << std::endl;
574 else if(page.find(
"~") != std::string::npos)
576 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId()
577 <<
"Error! Request using '~': " << page << std::endl;
579 else if(!(stat(page.c_str(), &buffer) == 0))
581 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId()
582 <<
"Error! File not found: " << page << std::endl;
586 __SUP_COUT__ << page << std::endl;
588 if(page.at(0) ==
'/')
590 __SUP_COUT__ <<
"First character is '/'" << std::endl;
591 page.erase(page.begin(), page.begin() + 1);
592 __SUP_COUT__ << page << std::endl;
595 std::string file = CONTROLS_SUPERVISOR_DATA_PATH;
597 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId()
598 <<
"Trying to load page: " << page << std::endl;
599 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId()
600 <<
"Trying to load page: " << file << std::endl;
604 std::ifstream infile(file);
607 std::cout <<
"Failed reading file: " << file << std::endl;
609 xmlOut.addTextElementToData(
"Time",
"[\"Not Found\"]");
610 xmlOut.addTextElementToData(
"Notes",
"[\"Not Found\"]");
611 xmlOut.addTextElementToData(
612 "Page", StringMacros::encodeURIComponent(page));
615 std::cout <<
"Reading file" << std::endl;
617 std::string time =
"";
618 std::string notes =
"";
619 std::string controlsPage =
"";
621 for(std::string line; getline(infile, line);)
623 std::cout << line << std::endl;
624 if(!line.substr(0, 5).compare(
"Time:"))
626 time = line.substr(6);
628 else if(!line.substr(0, 6).compare(
"Notes:"))
630 notes = line.substr(7);
632 else if(!line.substr(0, 5).compare(
"Page:"))
634 controlsPage = line.substr(6);
637 std::cout <<
"Finished reading file" << std::endl;
639 __SUP_COUTV__(notes);
640 __SUP_COUTV__(controlsPage);
642 xmlOut.addTextElementToData(
"Time", time);
643 xmlOut.addTextElementToData(
"Notes", notes);
644 xmlOut.addTextElementToData(
"Page", controlsPage);
648 void ControlsDashboardSupervisor::SaveControlsPage(
650 HttpXmlDocument& xmlOut,
651 const WebUsers::RequestUserInfo& userInfo)
653 __SUP_COUT__ <<
"ControlsDashboard wants to create a Controls Page!" << __E__;
655 std::string controlsPageName = CgiDataUtilities::postData(cgiIn,
"Name");
656 std::string pageString = CgiDataUtilities::postData(cgiIn,
"Page");
657 std::string Time = CgiDataUtilities::postData(cgiIn,
"Time");
659 StringMacros::decodeURIComponent(CgiDataUtilities::postData(cgiIn,
"Notes"));
660 std::string isControlsPagePublic = CgiDataUtilities::postData(cgiIn,
"isPublic");
662 __SUP_COUTV__(controlsPageName);
663 __SUP_COUTV__(pageString);
664 __SUP_COUTV__(Notes);
666 __SUP_COUTV__(isControlsPagePublic);
668 if(controlsPageName ==
"")
671 __SUP_COUTV__(CONTROLS_SUPERVISOR_DATA_PATH);
673 std::string fullPath;
674 if(isControlsPagePublic ==
"true")
675 fullPath = (std::string)CONTROLS_SUPERVISOR_DATA_PATH +
"public/";
677 fullPath = (std::string)CONTROLS_SUPERVISOR_DATA_PATH +
"private/";
679 __SUP_COUTV__(fullPath);
681 std::string file = fullPath + controlsPageName;
683 __SUP_COUTV__(
"Saving Controls Page to: " + file);
685 std::string extension = file.substr(file.length() - 4, 4);
686 if(extension !=
".dat")
688 __SUP_COUT__ <<
"Extension : " << extension << std::endl;
689 file += std::string(
".dat");
691 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId()
692 <<
"Trying to save page: " << controlsPageName << std::endl;
693 __SUP_COUT__ << this->getApplicationDescriptor()->getLocalId()
694 <<
"Trying to save page as: " << file << std::endl;
698 std::ofstream outputFile;
699 outputFile.open(file);
700 outputFile <<
"Time: " << Time <<
"\n";
701 outputFile <<
"Notes: " << Notes <<
"\n";
702 outputFile <<
"Page: " << pageString;
705 std::cout <<
"Finished writing file" << std::endl;
711 void ControlsDashboardSupervisor::Subscribe(cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut)
716 void ControlsDashboardSupervisor::Unsubscribe(cgicc::Cgicc& cgiIn,
717 HttpXmlDocument& xmlOut)
726 bool ControlsDashboardSupervisor::isDir(std::string dir)
728 struct stat fileInfo;
729 stat(dir.c_str(), &fileInfo);
730 if(S_ISDIR(fileInfo.st_mode))
740 void ControlsDashboardSupervisor::listFiles(std::string baseDir,
742 std::vector<std::string>* pages)
744 std::string base = CONTROLS_SUPERVISOR_DATA_PATH;
749 if((dp = opendir(base.c_str())) == NULL)
751 std::cout <<
"[ERROR: " << errno <<
" ] Couldn't open " << base <<
"."
757 while((dirp = readdir(dp)) != NULL)
759 if(dirp->d_name != std::string(
".") && dirp->d_name != std::string(
".."))
761 if(isDir(base + dirp->d_name) ==
true && recursive ==
true)
764 std::cout <<
"[DIR]\t" << baseDir << dirp->d_name <<
"/" << std::endl;
765 listFiles(baseDir + dirp->d_name +
"/",
true, pages);
769 pages->push_back(baseDir + dirp->d_name);
770 std::cout <<
"[FILE]\t" << baseDir << dirp->d_name << std::endl;