Wt examples  3.7.1
SimpleChatServer.C
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include "SimpleChatServer.h"
8 #include <Wt/WServer>
9 
10 #include <iostream>
11 #include <boost/lexical_cast.hpp>
12 
13 using namespace Wt;
14 
16  TextFormat format) const
17 {
18  switch (type_) {
19  case Login:
20  return WString::fromUTF8("<span class='chat-info'>")
21  + WWebWidget::escapeText(user_) + " joined.</span>";
22  case Logout:
23  return WString::fromUTF8("<span class='chat-info'>")
24  + ((user == user_) ?
25  WString::fromUTF8("You") :
26  WWebWidget::escapeText(user_))
27  + " logged out.</span>";
28  case Rename:
29  return "<span class='chat-info'>"
30  + ((user == data_ || user == user_) ?
31  "You are" :
32  (WWebWidget::escapeText(user_) + " is"))
33  + " now known as " + WWebWidget::escapeText(data_) + ".</span>";
34  case Message:{
35  WString result;
36 
37  result = WString("<span class='")
38  + ((user == user_) ?
39  "chat-self" :
40  "chat-user")
41  + "'>" + WWebWidget::escapeText(user_) + ":</span>";
42 
43  WString msg
44  = (format == XHTMLText ? message_ : WWebWidget::escapeText(message_));
45 
46  if (message_.toUTF8().find(user.toUTF8()) != std::string::npos)
47  return result + "<span class='chat-highlight'>" + msg + "</span>";
48  else
49  return result + msg;
50  }
51  default:
52  return "";
53  }
54 }
55 
56 
58  : server_(server)
59 { }
60 
62  const ChatEventCallback& handleEvent)
63 {
64  boost::recursive_mutex::scoped_lock lock(mutex_);
65 
66  if (clients_.count(client) == 0) {
67  ClientInfo clientInfo;
68 
69  clientInfo.sessionId = WApplication::instance()->sessionId();
70  clientInfo.eventCallback = handleEvent;
71 
72  clients_[client] = clientInfo;
73 
74  return true;
75  } else
76  return false;
77 }
78 
80 {
81  boost::recursive_mutex::scoped_lock lock(mutex_);
82 
83  return clients_.erase(client) == 1;
84 }
85 
87 {
88  boost::recursive_mutex::scoped_lock lock(mutex_);
89 
90  if (users_.find(user) == users_.end()) {
91  users_.insert(user);
92 
94 
95  return true;
96  } else
97  return false;
98 }
99 
101 {
102  boost::recursive_mutex::scoped_lock lock(mutex_);
103 
104  UserSet::iterator i = users_.find(user);
105 
106  if (i != users_.end()) {
107  users_.erase(i);
108 
110  }
111 }
112 
113 bool SimpleChatServer::changeName(const WString& user, const WString& newUser)
114 {
115  if (user == newUser)
116  return true;
117 
118  boost::recursive_mutex::scoped_lock lock(mutex_);
119 
120  UserSet::iterator i = users_.find(user);
121 
122  if (i != users_.end()) {
123  if (users_.count(newUser) == 0) {
124  users_.erase(i);
125  users_.insert(newUser);
126 
127  postChatEvent(ChatEvent(ChatEvent::Rename, user, newUser));
128 
129  return true;
130  } else
131  return false;
132  } else
133  return false;
134 }
135 
137 {
138  boost::recursive_mutex::scoped_lock lock(mutex_);
139 
140  for (int i = 1;; ++i) {
141  std::string s = "guest " + boost::lexical_cast<std::string>(i);
142  WString ss = s;
143 
144  if (users_.find(ss) == users_.end())
145  return ss;
146  }
147 }
148 
149 void SimpleChatServer::sendMessage(const WString& user, const WString& message)
150 {
151  postChatEvent(ChatEvent(user, message));
152 }
153 
155 {
156  boost::recursive_mutex::scoped_lock lock(mutex_);
157 
158  WApplication *app = WApplication::instance();
159 
160  for (ClientMap::const_iterator i = clients_.begin(); i != clients_.end();
161  ++i) {
162  /*
163  * If the user corresponds to the current application, we directly
164  * call the call back method. This avoids an unnecessary delay for
165  * the update to the user causing the event.
166  *
167  * For other uses, we post it to their session. By posting the
168  * event, we avoid dead-lock scenarios, race conditions, and
169  * delivering the event to a session that is just about to be
170  * terminated.
171  */
172  if (app && app->sessionId() == i->second.sessionId)
173  i->second.eventCallback(event);
174  else
175  server_.post(i->second.sessionId,
176  boost::bind(i->second.eventCallback, event));
177  }
178 }
179 
181 {
182  boost::recursive_mutex::scoped_lock lock(mutex_);
183 
184  UserSet result = users_;
185 
186  return result;
187 }
188 
boost::recursive_mutex mutex_
SimpleChatServer(Wt::WServer &server)
Create a new chat server.
void sendMessage(const Wt::WString &user, const Wt::WString &message)
Send a message on behalve of a user.
WT_API void post(const std::string &sessionId, const std::function< void()> &function, const std::function< void()> &fallBackFunction=std::function< void()>())
bool connect(Client *client, const ChatEventCallback &handleEvent)
Connects to the chat server.
Encapsulate a chat event.
static WString fromUTF8(const std::string &value, bool checkValid=false)
UserSet users()
Get the users currently logged in.
std::set< Wt::WString > UserSet
Typedef for a collection of user names.
bool changeName(const Wt::WString &user, const Wt::WString &newUser)
Changes the name.
Wt::WString suggestGuest()
Get a suggestion for a guest user name.
void postChatEvent(const ChatEvent &event)
std::string toUTF8() const
bool login(const Wt::WString &user)
Try to login with given user name.
bool disconnect(Client *client)
Disconnect from the chat server.
boost::function< void(const ChatEvent &)> ChatEventCallback
Wt::WServer & server_
std::string sessionId() const
void logout(const Wt::WString &user)
Logout from the server.
const Wt::WString formattedHTML(const Wt::WString &user, Wt::TextFormat format) const
Get the message formatted as HTML, rendered for the given user.
TextFormat

Generated on Tue Dec 15 2020 for the C++ Web Toolkit (Wt) by doxygen 1.8.13