1 #include "otsdaq-utilities/Chat/ChatSupervisor.h"
2 #include "otsdaq/CgiDataUtilities/CgiDataUtilities.h"
3 #include "otsdaq/Macros/CoutMacros.h"
4 #include "otsdaq/MessageFacility/MessageFacility.h"
5 #include "otsdaq/XmlUtilities/HttpXmlDocument.h"
7 #include <xdaq/NamespaceURI.h>
14 #define __MF_SUBJECT__ "Chat"
23 ChatLastUpdateIndex = 1;
26 enableSlackChat = (std::getenv(
"OTS_EN_SLACK") !=
nullptr &&
27 std::string(std::getenv(
"OTS_EN_SLACK")) ==
"1");
30 const char* env = std::getenv(
"OTSDAQ_UTILITIES_DIR");
31 chatSupervisorToolsPath_ = env ? env :
"";
33 if(chatSupervisorToolsPath_.empty())
34 enableSlackChat =
false;
35 if(chatSupervisorToolsPath_.back() !=
'/')
36 chatSupervisorToolsPath_ +=
'/';
37 chatSupervisorToolsPath_ +=
"tools/";
39 __COUT__ <<
"ChatSupervisor: Slack chat "
40 << (enableSlackChat ?
"enabled" :
"disabled") << __E__;
41 __COUT__ <<
"ChatSupervisor path: " << chatSupervisorToolsPath_ << __E__;
46 ChatSupervisor::~ChatSupervisor(
void) { destroy(); }
49 void ChatSupervisor::destroy(
void)
55 void ChatSupervisor::defaultPage(xgi::Input* , xgi::Output* out)
57 out->getHTTPResponseHeader().addHeader(
"Access-Control-Allow-Origin",
"*");
58 out->getHTTPResponseHeader().addHeader(
"Pragma",
"no-cache");
60 *out <<
"<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame "
61 "src='/WebPath/html/Chat.html?urn="
62 << this->getApplicationDescriptor()->getLocalId() <<
"'></frameset></html>";
70 CorePropertySupervisorBase::setSupervisorProperty(
71 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
82 const WebUsers::RequestUserInfo& )
84 __COUTVS__(40, requestType);
91 cleanupExpiredChats();
93 if(requestType ==
"RefreshChat")
95 std::string lastUpdateIndexString =
98 uint64_t lastUpdateIndex;
99 sscanf(lastUpdateIndexString.c_str(),
"%lu", &lastUpdateIndex);
101 insertChatRefresh(&xmlOut, lastUpdateIndex, user);
103 else if(requestType ==
"RefreshUsers")
105 insertActiveUsers(&xmlOut);
107 else if(requestType ==
"SendChat")
116 else if(requestType ==
"PageUser")
119 unsigned int topageId = CgiDataUtilities::postDataAsInt(cgiIn,
"topageId");
122 __COUT__ <<
"Paging = " << topage.substr(0, 10)
123 <<
"... from user = " << user.substr(0, 10) << std::endl;
127 theRemoteWebUsers_.sendSystemMessage(topage,
128 user +
" is paging you to come chat.");
132 __SUP_SS__ <<
"requestType Request, " << requestType
133 <<
", not recognized by the Chat Editor Supervisor (was it intended "
134 "for another Supervisor?)."
145 void ChatSupervisor::escapeChat(std::string& )
158 xmlOut->addTextElementToData(
"active_users", theRemoteWebUsers_.getActiveUserList());
169 uint64_t lastUpdateIndex,
170 const std::string& user)
174 if(!isLastUpdateIndexStale(lastUpdateIndex))
180 sprintf(tempStr,
"%lu", ChatLastUpdateIndex);
181 xmlOut->addTextElementToData(
"last_update_index", tempStr);
184 xmlOut->addTextElementToData(
"chat_users",
"");
185 for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
191 xmlOut->addTextElementToData(
"chat_history",
"");
192 for(uint64_t i = 0; i < ChatHistoryEntry_.size(); ++i)
194 __COUTT__ <<
"Chat[" << i <<
"]: " << ChatHistoryIndex_[i] <<
" vs "
195 << lastUpdateIndex << __E__;
196 if(isChatOld(ChatHistoryIndex_[i], lastUpdateIndex))
200 "chat_entry", ChatHistoryEntry_[i],
"chat_history");
202 "chat_author", ChatHistoryAuthor_[i],
"chat_history");
203 sprintf(tempStr,
"%lu", ChatHistoryTime_[i]);
211 void ChatSupervisor::newUser(
const std::string& user)
213 for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
214 if(ChatUsers_[i] == user)
216 ChatUsersTime_[i] = time(0);
220 __COUT__ <<
"New user: " << user << std::endl;
222 ChatUsers_.push_back(user);
223 ChatUsersTime_.push_back(time(0));
224 newChat(user +
" joined the chat.",
231 void ChatSupervisor::newChat(
const std::string& chat,
const std::string& user)
233 ChatHistoryEntry_.push_back(chat);
234 ChatHistoryAuthor_.push_back(user);
235 ChatHistoryTime_.push_back(time(0));
236 ChatHistoryIndex_.push_back(incrementAndGetLastUpdate());
238 sendToSlack(user, chat);
244 bool ChatSupervisor::isChatOld(uint64_t chatIndex, uint64_t last)
246 return (last - chatIndex < (uint64_t(1) << 62));
251 bool ChatSupervisor::isLastUpdateIndexStale(uint64_t last)
253 return ChatLastUpdateIndex != last;
258 uint64_t ChatSupervisor::incrementAndGetLastUpdate()
260 if(!++ChatLastUpdateIndex)
261 ++ChatLastUpdateIndex;
262 return ChatLastUpdateIndex;
268 void ChatSupervisor::cleanupExpiredChats()
270 for(uint64_t i = 0; i < ChatHistoryEntry_.size(); ++i)
271 if(i >= CHAT_HISTORY_MAX_ENTRIES ||
272 ChatHistoryTime_[i] + CHAT_HISTORY_EXPIRATION_TIME < time(0))
274 removeChatHistoryEntry(i);
281 for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
282 if(ChatUsersTime_[i] + CHAT_HISTORY_EXPIRATION_TIME < time(0))
284 removeChatUserEntry(i);
294 void ChatSupervisor::removeChatHistoryEntry(uint64_t i)
296 ChatHistoryEntry_.erase(ChatHistoryEntry_.begin() + i);
297 ChatHistoryTime_.erase(ChatHistoryTime_.begin() + i);
298 ChatHistoryAuthor_.erase(ChatHistoryAuthor_.begin() + i);
299 ChatHistoryIndex_.erase(ChatHistoryIndex_.begin() + i);
304 void ChatSupervisor::removeChatUserEntry(uint64_t i)
306 newChat(ChatUsers_[i] +
" left the chat.",
308 ChatUsers_.erase(ChatUsers_.begin() + i);
309 ChatUsersTime_.erase(ChatUsersTime_.begin() + i);
314 void ChatSupervisor::sendToSlack(
const std::string& user,
const std::string& message)
316 std::string command =
"python3 " + chatSupervisorToolsPath_ +
"SendSlackChat.py " +
317 "--message \"" + message +
"\" --user " + user;
318 __COUT__ <<
"Executing command: " << command << __E__;
324 if(!result.empty() && result.find(
"Error:") != std::string::npos)
325 __COUT__ <<
"Error from SendSlackChat.py: " << result << __E__;
326 else if(!result.empty())
327 __COUT__ <<
"Response from SendSlackChat.py: " << result << __E__;
329 catch(
const std::exception& e)
331 __COUT__ <<
"Exception while executing command: " << e.what() << __E__;
static std::string postData(cgicc::Cgicc &cgi, const std::string &needle)
virtual void request(const std::string &requestType, cgicc::Cgicc &cgiIn, HttpXmlDocument &xmlOut, const WebUsers::RequestUserInfo &userInfo) override
end forceSupervisorPropertyValues()
virtual void forceSupervisorPropertyValues(void) override
override to force supervisor property values (and ignore user settings)
xercesc::DOMElement * addTextElementToParent(const std::string &childName, const std::string &childText, xercesc::DOMElement *parent)
void INIT_MF(const char *name)
static std::string exec(const char *cmd)