otsdaq_utilities  v2_05_02_indev
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)
20 
21  : CoreSupervisorBase(stub)
22 {
23  INIT_MF("." /*directory used is USER_DATA/LOG/.*/);
24 
25  ChatLastUpdateIndex = 1; // skip 0
26 }
27 
28 //==============================================================================
29 ChatSupervisor::~ChatSupervisor(void) { destroy(); }
30 
31 //==============================================================================
32 void ChatSupervisor::destroy(void)
33 {
34  // called by destructor
35 }
36 
38 //void ChatSupervisor::defaultPage(xgi::Input* cgiIn, xgi::Output* out)
39 //{
40 // out->getHTTPResponseHeader().addHeader("Access-Control-Allow-Origin","http://correlator2.fnal.gov");
41 // out->getHTTPResponseHeader().addHeader("Pragma", "no-cache");
42 //
43 //
44 //
45 // *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame "
46 // "src='/WebPath/html/Chat.html?urn="
47 // << this->getApplicationDescriptor()->getLocalId() << "'></frameset></html>";
48 //} //end defaultPage()
49 
50 //==============================================================================
51 // forceSupervisorPropertyValues
52 // override to force supervisor property values (and ignore user settings)
53 void ChatSupervisor::forceSupervisorPropertyValues()
54 {
55  CorePropertySupervisorBase::setSupervisorProperty(
56  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
57  "RefreshChat");
58 }
59 
60 //==============================================================================
61 // request
62 // Handles Web Interface requests to chat supervisor.
63 // Does not refresh cookie for automatic update checks.
64 void ChatSupervisor::request(const std::string& requestType,
65  cgicc::Cgicc& cgiIn,
66  HttpXmlDocument& xmlOut,
67  const WebUsers::RequestUserInfo& /*userInfo*/)
68 {
69  //__COUT__ << "requestType: " << requestType << std::endl;
70 
71  // Commands:
72  // RefreshChat
73  // RefreshUsers
74  // SendChat
75 
76  cleanupExpiredChats();
77 
78  if(requestType == "RefreshChat")
79  {
80  std::string lastUpdateIndexString =
81  CgiDataUtilities::postData(cgiIn, "lastUpdateIndex");
82  std::string user = CgiDataUtilities::postData(cgiIn, "user");
83  uint64_t lastUpdateIndex;
84  sscanf(lastUpdateIndexString.c_str(), "%lu", &lastUpdateIndex);
85 
86  insertChatRefresh(&xmlOut, lastUpdateIndex, user);
87  }
88  else if(requestType == "RefreshUsers")
89  {
90  insertActiveUsers(&xmlOut);
91  }
92  else if(requestType == "SendChat")
93  {
94  std::string chat = CgiDataUtilities::postData(cgiIn, "chat");
95  std::string user = CgiDataUtilities::postData(cgiIn, "user");
96 
97  escapeChat(chat);
98 
99  newChat(chat, user);
100  }
101  else if(requestType == "PageUser")
102  {
103  std::string topage = CgiDataUtilities::postData(cgiIn, "topage");
104  unsigned int topageId = CgiDataUtilities::postDataAsInt(cgiIn, "topageId");
105  std::string user = CgiDataUtilities::postData(cgiIn, "user");
106 
107  __COUT__ << "Paging = " << topage.substr(0, 10)
108  << "... from user = " << user.substr(0, 10) << std::endl;
109 
110  __COUTV__(topageId);
111 
112  theRemoteWebUsers_.sendSystemMessage(topage,
113  user + " is paging you to come chat.");
114  }
115  else
116  __COUT__ << "requestType request not recognized." << std::endl;
117 
118 } // end request()
119 
120 //==============================================================================
121 // ChatSupervisor::escapeChat()
122 // replace html/xhtml reserved characters with equivalent.
123 // reserved: ", ', &, <, >
124 void ChatSupervisor::escapeChat(std::string& /*chat*/)
125 {
126  // char reserved[] = {'"','\'','&','<','>'};
127  // std::string replace[] = {"&#34;","&#39;","&#38;","&#60;","&#62;"};
128  // for(uint64_t i=0;i<chat.size();++i)
129  // for(uint64_t j=0;j<chat.size();++j)
130  // if(chat[i] ==
131 } //end escapeChat()
132 
133 //==============================================================================
134 // ChatSupervisor::insertActiveUsers()
135 void ChatSupervisor::insertActiveUsers(HttpXmlDocument* xmlOut)
136 {
137  xmlOut->addTextElementToData(
138  "active_users",
139  theRemoteWebUsers_.getActiveUserList());
140 } //end insertActiveUsers()
141 
142 //==============================================================================
143 // ChatSupervisor::insertChatRefresh()
144 // check if user is new to list (may cause update)
145 // each new user causes update to last index
146 // if lastUpdateIndex is current, return nothing
147 // else return full chat user list and new chats
148 // (note: lastUpdateIndex==0 first time and returns only user list. no chats)
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) // lastUpdateIndex == 0, so just give the <user> entered chat
170  // message only
171  lastUpdateIndex = ChatHistoryIndex_[ChatHistoryIndex_.size() - 1] -
172  1; // new user will then get future chats
173 
174  // get all accounts
175  xmlOut->addTextElementToData("chat_history", "");
176  for(uint64_t i = 0; i < ChatHistoryEntry_.size(); ++i) // output oldest to new
177  {
178  if(isChatOld(ChatHistoryIndex_[i], lastUpdateIndex))
179  continue;
180 
181  xmlOut->addTextElementToParent(
182  "chat_entry", ChatHistoryEntry_[i], "chat_history");
183  xmlOut->addTextElementToParent(
184  "chat_author", ChatHistoryAuthor_[i], "chat_history");
185  sprintf(tempStr, "%lu", ChatHistoryTime_[i]);
186  xmlOut->addTextElementToParent("chat_time", tempStr, "chat_history");
187  }
188 } //end insertChatRefresh()
189 
190 //==============================================================================
191 // ChatSupervisor::newUser()
192 // create new user if needed, and increment update
193 void ChatSupervisor::newUser(const std::string& user)
194 {
195  for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
196  if(ChatUsers_[i] == user)
197  {
198  ChatUsersTime_[i] = time(0); // update time
199  return; // do not add new if found
200  }
201 
202  __COUT__ << "New user: " << user << std::endl;
203  // add and increment
204  ChatUsers_.push_back(user);
205  ChatUsersTime_.push_back(time(0));
206  newChat(user + " joined the chat.",
207  "ots"); // add status message to chat, increment update
208 } //end newUser()
209 
210 //==============================================================================
211 // ChatSupervisor::newChat()
212 // create new chat, and increment update
213 void ChatSupervisor::newChat(const std::string& chat, const std::string& user)
214 {
215  ChatHistoryEntry_.push_back(chat);
216  ChatHistoryAuthor_.push_back(user);
217  ChatHistoryTime_.push_back(time(0));
218  ChatHistoryIndex_.push_back(incrementAndGetLastUpdate());
219 }
220 
221 //==============================================================================
222 // ChatSupervisor::isChatNew()
223 // return true if chatIndex is older than lastUpdateIndex
224 bool ChatSupervisor::isChatOld(uint64_t chatIndex, uint64_t last)
225 {
226  return (last - chatIndex < (uint64_t(1) << 62));
227 }
228 
229 //==============================================================================
230 // ChatSupervisor::isLastUpdateIndexStale()
231 bool ChatSupervisor::isLastUpdateIndexStale(uint64_t last)
232 {
233  return ChatLastUpdateIndex != last;
234 }
235 
236 //==============================================================================
237 // ChatSupervisor::incrementAndGetLastUpdate()
238 uint64_t ChatSupervisor::incrementAndGetLastUpdate()
239 {
240  if(!++ChatLastUpdateIndex)
241  ++ChatLastUpdateIndex; // skip 0
242  return ChatLastUpdateIndex;
243 }
244 
245 //==============================================================================
246 // ChatSupervisor::cleanupExpiredChats()
247 // remove expired entries from Chat history and user list
248 void ChatSupervisor::cleanupExpiredChats()
249 {
250  for(uint64_t i = 0; i < ChatHistoryEntry_.size(); ++i)
251  if(i >= CHAT_HISTORY_MAX_ENTRIES ||
252  ChatHistoryTime_[i] + CHAT_HISTORY_EXPIRATION_TIME < time(0)) // expired
253  {
254  removeChatHistoryEntry(i);
255  --i; // rewind loop
256  }
257  else
258  break; // chronological order, so first encountered that is still valid exit
259  // loop
260 
261  for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
262  if(ChatUsersTime_[i] + CHAT_HISTORY_EXPIRATION_TIME < time(0)) // expired
263  {
264  removeChatUserEntry(i);
265  --i; // rewind loop
266  }
267  else
268  break; // chronological order, so first encountered that is still valid exit
269  // loop
270 }
271 
272 //==============================================================================
273 // ChatSupervisor::removeChatHistoryEntry()
274 void ChatSupervisor::removeChatHistoryEntry(uint64_t i)
275 {
276  ChatHistoryEntry_.erase(ChatHistoryEntry_.begin() + i);
277  ChatHistoryTime_.erase(ChatHistoryTime_.begin() + i);
278  ChatHistoryAuthor_.erase(ChatHistoryAuthor_.begin() + i);
279  ChatHistoryIndex_.erase(ChatHistoryIndex_.begin() + i);
280 }
281 
282 //==============================================================================
283 // ChatSupervisor::removeChatHistoryEntry()
284 void ChatSupervisor::removeChatUserEntry(uint64_t i)
285 {
286  newChat(ChatUsers_[i] + " left the chat.",
287  "ots"); // add status message to chat, increment update
288  ChatUsers_.erase(ChatUsers_.begin() + i);
289  ChatUsersTime_.erase(ChatUsersTime_.begin() + i);
290 }
virtual void request(const std::string &requestType, cgicc::Cgicc &cgiIn, HttpXmlDocument &xmlOut, const WebUsers::RequestUserInfo &userInfo) override
end forceSupervisorPropertyValues()