otsdaq_utilities  v2_04_01
ChatSupervisor.cc
1 #include "otsdaq-utilities/Chat/ChatSupervisor.h"
2 #include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h"
3 #include "otsdaq-core/Macros/CoutMacros.h"
4 #include "otsdaq-core/MessageFacility/MessageFacility.h"
5 #include "otsdaq-core/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  // //return xml doc holding server response
112  // xmlOut.outputXmlDocument((std::ostringstream*)out);
113 }
114 
115 //========================================================================================================================
116 // ChatSupervisor::escapeChat()
117 // replace html/xhtml reserved characters with equivalent.
118 // reserved: ", ', &, <, >
119 void ChatSupervisor::escapeChat(std::string& chat)
120 {
121  // char reserved[] = {'"','\'','&','<','>'};
122  // std::string replace[] = {"&#34;","&#39;","&#38;","&#60;","&#62;"};
123  // for(uint64_t i=0;i<chat.size();++i)
124  // for(uint64_t j=0;j<chat.size();++j)
125  // if(chat[i] ==
126 }
127 
128 //========================================================================================================================
129 // ChatSupervisor::insertActiveUsers()
130 void ChatSupervisor::insertActiveUsers(HttpXmlDocument* xmlOut)
131 {
132  xmlOut->addTextElementToData(
133  "active_users",
134  theRemoteWebUsers_.getActiveUserList(allSupervisorInfo_.getGatewayDescriptor()));
135 }
136 
137 //========================================================================================================================
138 // ChatSupervisor::insertChatRefresh()
139 // check if user is new to list (may cause update)
140 // each new user causes update to last index
141 // if lastUpdateIndex is current, return nothing
142 // else return full chat user list and new chats
143 // (note: lastUpdateIndex==0 first time and returns only user list. no chats)
144 void ChatSupervisor::insertChatRefresh(HttpXmlDocument* xmlOut,
145  uint64_t lastUpdateIndex,
146  std::string user)
147 {
148  newUser(user);
149 
150  if(!isLastUpdateIndexStale(lastUpdateIndex))
151  return; // if lastUpdateIndex is current, return nothing
152 
153  // return new update index, full chat user list, and new chats!
154 
155  char tempStr[50];
156  sprintf(tempStr, "%lu", ChatLastUpdateIndex);
157  xmlOut->addTextElementToData("last_update_index", tempStr);
158 
159  // get all users
160  xmlOut->addTextElementToData("chat_users", "");
161  for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
162  xmlOut->addTextElementToParent("chat_user", ChatUsers_[i], "chat_users");
163 
164  if(!lastUpdateIndex) // lastUpdateIndex == 0, so just give the <user> entered chat
165  // message only
166  lastUpdateIndex = ChatHistoryIndex_[ChatHistoryIndex_.size() - 1] -
167  1; // new user will then get future chats
168 
169  // get all accounts
170  xmlOut->addTextElementToData("chat_history", "");
171  for(uint64_t i = 0; i < ChatHistoryEntry_.size(); ++i) // output oldest to new
172  {
173  if(isChatOld(ChatHistoryIndex_[i], lastUpdateIndex))
174  continue;
175 
176  xmlOut->addTextElementToParent(
177  "chat_entry", ChatHistoryEntry_[i], "chat_history");
178  xmlOut->addTextElementToParent(
179  "chat_author", ChatHistoryAuthor_[i], "chat_history");
180  sprintf(tempStr, "%lu", ChatHistoryTime_[i]);
181  xmlOut->addTextElementToParent("chat_time", tempStr, "chat_history");
182  }
183 }
184 
185 //========================================================================================================================
186 // ChatSupervisor::newUser()
187 // create new user if needed, and increment update
188 void ChatSupervisor::newUser(std::string user)
189 {
190  for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
191  if(ChatUsers_[i] == user)
192  {
193  ChatUsersTime_[i] = time(0); // update time
194  return; // do not add new if found
195  }
196 
197  __COUT__ << "New user: " << user << std::endl;
198  // add and increment
199  ChatUsers_.push_back(user);
200  ChatUsersTime_.push_back(time(0));
201  newChat(user + " joined the chat.",
202  "ots"); // add status message to chat, increment update
203 }
204 
205 //========================================================================================================================
206 // ChatSupervisor::newChat()
207 // create new chat, and increment update
208 void ChatSupervisor::newChat(std::string chat, std::string user)
209 {
210  ChatHistoryEntry_.push_back(chat);
211  ChatHistoryAuthor_.push_back(user);
212  ChatHistoryTime_.push_back(time(0));
213  ChatHistoryIndex_.push_back(incrementAndGetLastUpdate());
214 }
215 
216 //========================================================================================================================
217 // ChatSupervisor::isChatNew()
218 // return true if chatIndex is older than lastUpdateIndex
219 bool ChatSupervisor::isChatOld(uint64_t chatIndex, uint64_t last)
220 {
221  return (last - chatIndex < (uint64_t(1) << 62));
222 }
223 
224 //========================================================================================================================
225 // ChatSupervisor::isLastUpdateIndexStale()
226 bool ChatSupervisor::isLastUpdateIndexStale(uint64_t last)
227 {
228  return ChatLastUpdateIndex != last;
229 }
230 
231 //========================================================================================================================
232 // ChatSupervisor::incrementAndGetLastUpdate()
233 uint64_t ChatSupervisor::incrementAndGetLastUpdate()
234 {
235  if(!++ChatLastUpdateIndex)
236  ++ChatLastUpdateIndex; // skip 0
237  return ChatLastUpdateIndex;
238 }
239 
240 //========================================================================================================================
241 // ChatSupervisor::cleanupExpiredChats()
242 // remove expired entries from Chat history and user list
243 void ChatSupervisor::cleanupExpiredChats()
244 {
245  for(uint64_t i = 0; i < ChatHistoryEntry_.size(); ++i)
246  if(i >= CHAT_HISTORY_MAX_ENTRIES ||
247  ChatHistoryTime_[i] + CHAT_HISTORY_EXPIRATION_TIME < time(0)) // expired
248  {
249  removeChatHistoryEntry(i);
250  --i; // rewind loop
251  }
252  else
253  break; // chronological order, so first encountered that is still valid exit
254  // loop
255 
256  for(uint64_t i = 0; i < ChatUsers_.size(); ++i)
257  if(ChatUsersTime_[i] + CHAT_HISTORY_EXPIRATION_TIME < time(0)) // expired
258  {
259  removeChatUserEntry(i);
260  --i; // rewind loop
261  }
262  else
263  break; // chronological order, so first encountered that is still valid exit
264  // loop
265 }
266 
267 //========================================================================================================================
268 // ChatSupervisor::removeChatHistoryEntry()
269 void ChatSupervisor::removeChatHistoryEntry(uint64_t i)
270 {
271  ChatHistoryEntry_.erase(ChatHistoryEntry_.begin() + i);
272  ChatHistoryTime_.erase(ChatHistoryTime_.begin() + i);
273  ChatHistoryAuthor_.erase(ChatHistoryAuthor_.begin() + i);
274  ChatHistoryIndex_.erase(ChatHistoryIndex_.begin() + i);
275 }
276 
277 //========================================================================================================================
278 // ChatSupervisor::removeChatHistoryEntry()
279 void ChatSupervisor::removeChatUserEntry(uint64_t i)
280 {
281  newChat(ChatUsers_[i] + " left the chat.",
282  "ots"); // add status message to chat, increment update
283  ChatUsers_.erase(ChatUsers_.begin() + i);
284  ChatUsersTime_.erase(ChatUsersTime_.begin() + i);
285 }