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