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