otsdaq-utilities  3.02.00
ChatSupervisor.cc
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"
6 
7 #include <xdaq/NamespaceURI.h>
8 
9 #include <iostream>
10 
11 using namespace ots;
12 
13 #undef __MF_SUBJECT__
14 #define __MF_SUBJECT__ "Chat"
15 
16 XDAQ_INSTANTIATOR_IMPL(ChatSupervisor)
17 
18 //==============================================================================
19 ChatSupervisor::ChatSupervisor(xdaq::ApplicationStub* stub) : CoreSupervisorBase(stub)
20 {
21  INIT_MF("." /*directory used is USER_DATA/LOG/.*/);
22 
23  ChatLastUpdateIndex = 1; // skip 0
24 }
25 
26 //==============================================================================
27 ChatSupervisor::~ChatSupervisor(void) { destroy(); }
28 
29 //==============================================================================
30 void ChatSupervisor::destroy(void)
31 {
32  // called by destructor
33 }
34 
35 //==============================================================================
36 void ChatSupervisor::defaultPage(xgi::Input* /* cgiIn */, xgi::Output* out)
37 {
38  out->getHTTPResponseHeader().addHeader("Access-Control-Allow-Origin", "*");
39  out->getHTTPResponseHeader().addHeader("Pragma", "no-cache");
40 
41  *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame "
42  "src='/WebPath/html/Chat.html?urn="
43  << this->getApplicationDescriptor()->getLocalId() << "'></frameset></html>";
44 } //end defaultPage()
45 
46 //==============================================================================
50 {
51  CorePropertySupervisorBase::setSupervisorProperty(
52  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
53  "RefreshChat");
54 }
55 
56 //==============================================================================
60 void ChatSupervisor::request(const std::string& requestType,
61  cgicc::Cgicc& cgiIn,
62  HttpXmlDocument& xmlOut,
63  const WebUsers::RequestUserInfo& /*userInfo*/)
64 {
65  __COUTVS__(40, requestType);
66 
67  // Commands:
68  // RefreshChat
69  // RefreshUsers
70  // SendChat
71 
72  cleanupExpiredChats();
73 
74  if(requestType == "RefreshChat")
75  {
76  std::string lastUpdateIndexString =
77  CgiDataUtilities::postData(cgiIn, "lastUpdateIndex");
78  std::string user = CgiDataUtilities::postData(cgiIn, "user");
79  uint64_t lastUpdateIndex;
80  sscanf(lastUpdateIndexString.c_str(), "%lu", &lastUpdateIndex);
81 
82  insertChatRefresh(&xmlOut, lastUpdateIndex, user);
83  }
84  else if(requestType == "RefreshUsers")
85  {
86  insertActiveUsers(&xmlOut);
87  }
88  else if(requestType == "SendChat")
89  {
90  std::string chat = CgiDataUtilities::postData(cgiIn, "chat");
91  std::string user = CgiDataUtilities::postData(cgiIn, "user");
92 
93  escapeChat(chat);
94 
95  newChat(chat, user);
96  }
97  else if(requestType == "PageUser")
98  {
99  std::string topage = CgiDataUtilities::postData(cgiIn, "topage");
100  unsigned int topageId = CgiDataUtilities::postDataAsInt(cgiIn, "topageId");
101  std::string user = CgiDataUtilities::postData(cgiIn, "user");
102 
103  __COUT__ << "Paging = " << topage.substr(0, 10)
104  << "... from user = " << user.substr(0, 10) << std::endl;
105 
106  __COUTV__(topageId);
107 
108  theRemoteWebUsers_.sendSystemMessage(topage,
109  user + " is paging you to come chat.");
110  }
111  else
112  {
113  __SUP_SS__ << "requestType Request, " << requestType
114  << ", not recognized by the Chat Editor Supervisor (was it intended "
115  "for another Supervisor?)."
116  << __E__;
117  __SUP_SS_THROW__;
118  }
119 
120 } // end request()
121 
122 //==============================================================================
126 void ChatSupervisor::escapeChat(std::string& /*chat*/)
127 {
128  // char reserved[] = {'"','\'','&','<','>'};
129  // std::string replace[] = {"&#34;","&#39;","&#38;","&#60;","&#62;"};
130  // for(uint64_t i=0;i<chat.size();++i)
131  // for(uint64_t j=0;j<chat.size();++j)
132  // if(chat[i] ==
133 } // end escapeChat()
134 
135 //==============================================================================
137 void ChatSupervisor::insertActiveUsers(HttpXmlDocument* xmlOut)
138 {
139  xmlOut->addTextElementToData("active_users", theRemoteWebUsers_.getActiveUserList());
140 } // end insertActiveUsers()
141 
142 //==============================================================================
149 void ChatSupervisor::insertChatRefresh(HttpXmlDocument* xmlOut,
150  uint64_t lastUpdateIndex,
151  const std::string& user)
152 {
153  newUser(user);
154 
155  if(!isLastUpdateIndexStale(lastUpdateIndex))
156  return; // if lastUpdateIndex is current, return nothing
157 
158  // return new update index, full chat user list, and new chats!
159 
160  char tempStr[50];
161  sprintf(tempStr, "%lu", ChatLastUpdateIndex);
162  xmlOut->addTextElementToData("last_update_index", tempStr);
163 
164  // get all users
165  xmlOut->addTextElementToData("chat_users", "");
166  for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
167  xmlOut->addTextElementToParent("chat_user", ChatUsers_[i], "chat_users");
168 
169  //if lastUpdateIndex == 0, first request, so give give full history!
170 
171  // get all accounts
172  xmlOut->addTextElementToData("chat_history", "");
173  for(uint64_t i = 0; i < ChatHistoryEntry_.size(); ++i) // output oldest to new
174  {
175  __COUTT__ << "Chat[" << i << "]: " << ChatHistoryIndex_[i] << " vs "
176  << lastUpdateIndex << __E__;
177  if(isChatOld(ChatHistoryIndex_[i], lastUpdateIndex))
178  continue;
179 
180  xmlOut->addTextElementToParent(
181  "chat_entry", ChatHistoryEntry_[i], "chat_history");
182  xmlOut->addTextElementToParent(
183  "chat_author", ChatHistoryAuthor_[i], "chat_history");
184  sprintf(tempStr, "%lu", ChatHistoryTime_[i]);
185  xmlOut->addTextElementToParent("chat_time", tempStr, "chat_history");
186  }
187 } // end insertChatRefresh()
188 
189 //==============================================================================
192 void ChatSupervisor::newUser(const std::string& user)
193 {
194  for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
195  if(ChatUsers_[i] == user)
196  {
197  ChatUsersTime_[i] = time(0); // update time
198  return; // do not add new if found
199  }
200 
201  __COUT__ << "New user: " << user << std::endl;
202  // add and increment
203  ChatUsers_.push_back(user);
204  ChatUsersTime_.push_back(time(0));
205  newChat(user + " joined the chat.",
206  "ots"); // add status message to chat, increment update
207 } // end newUser()
208 
209 //==============================================================================
212 void ChatSupervisor::newChat(const std::string& chat, const std::string& user)
213 {
214  ChatHistoryEntry_.push_back(chat);
215  ChatHistoryAuthor_.push_back(user);
216  ChatHistoryTime_.push_back(time(0));
217  ChatHistoryIndex_.push_back(incrementAndGetLastUpdate());
218 }
219 
220 //==============================================================================
223 bool ChatSupervisor::isChatOld(uint64_t chatIndex, uint64_t last)
224 {
225  return (last - chatIndex < (uint64_t(1) << 62));
226 }
227 
228 //==============================================================================
230 bool ChatSupervisor::isLastUpdateIndexStale(uint64_t last)
231 {
232  return ChatLastUpdateIndex != last;
233 }
234 
235 //==============================================================================
237 uint64_t ChatSupervisor::incrementAndGetLastUpdate()
238 {
239  if(!++ChatLastUpdateIndex)
240  ++ChatLastUpdateIndex; // skip 0
241  return ChatLastUpdateIndex;
242 }
243 
244 //==============================================================================
247 void ChatSupervisor::cleanupExpiredChats()
248 {
249  for(uint64_t i = 0; i < ChatHistoryEntry_.size(); ++i)
250  if(i >= CHAT_HISTORY_MAX_ENTRIES ||
251  ChatHistoryTime_[i] + CHAT_HISTORY_EXPIRATION_TIME < time(0)) // expired
252  {
253  removeChatHistoryEntry(i);
254  --i; // rewind loop
255  }
256  else
257  break; // chronological order, so first encountered that is still valid exit
258  // loop
259 
260  for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
261  if(ChatUsersTime_[i] + CHAT_HISTORY_EXPIRATION_TIME < time(0)) // expired
262  {
263  removeChatUserEntry(i);
264  --i; // rewind loop
265  }
266  else
267  break; // chronological order, so first encountered that is still valid exit
268  // loop
269 }
270 
271 //==============================================================================
273 void ChatSupervisor::removeChatHistoryEntry(uint64_t i)
274 {
275  ChatHistoryEntry_.erase(ChatHistoryEntry_.begin() + i);
276  ChatHistoryTime_.erase(ChatHistoryTime_.begin() + i);
277  ChatHistoryAuthor_.erase(ChatHistoryAuthor_.begin() + i);
278  ChatHistoryIndex_.erase(ChatHistoryIndex_.begin() + i);
279 }
280 
281 //==============================================================================
283 void ChatSupervisor::removeChatUserEntry(uint64_t i)
284 {
285  newChat(ChatUsers_[i] + " left the chat.",
286  "ots"); // add status message to chat, increment update
287  ChatUsers_.erase(ChatUsers_.begin() + i);
288  ChatUsersTime_.erase(ChatUsersTime_.begin() + i);
289 }
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)