Wt examples
3.2.2
|
00001 /* 00002 * Copyright (C) 2008 Emweb bvba, Heverlee, Belgium. 00003 * 00004 * See the LICENSE file for terms of use. 00005 */ 00006 00007 #include "SimpleChatServer.h" 00008 #include <Wt/WServer> 00009 00010 #include <iostream> 00011 #include <boost/lexical_cast.hpp> 00012 00013 using namespace Wt; 00014 00015 const WString ChatEvent::formattedHTML(const WString& user, 00016 TextFormat format) const 00017 { 00018 switch (type_) { 00019 case Login: 00020 return WString::fromUTF8("<span class='chat-info'>") 00021 + WWebWidget::escapeText(user_) + " joined.</span>"; 00022 case Logout: 00023 return WString::fromUTF8("<span class='chat-info'>") 00024 + ((user == user_) ? 00025 WString::fromUTF8("You") : 00026 WWebWidget::escapeText(user_)) 00027 + " logged out.</span>"; 00028 case Rename: 00029 return "<span class='chat-info'>" 00030 + ((user == data_ || user == user_) ? 00031 "You are" : 00032 (WWebWidget::escapeText(user_) + " is")) 00033 + " now known as " + WWebWidget::escapeText(data_) + ".</span>"; 00034 case Message:{ 00035 WString result; 00036 00037 result = WString("<span class='") 00038 + ((user == user_) ? 00039 "chat-self" : 00040 "chat-user") 00041 + "'>" + WWebWidget::escapeText(user_) + ":</span>"; 00042 00043 WString msg 00044 = (format == XHTMLText ? message_ : WWebWidget::escapeText(message_)); 00045 00046 if (message_.toUTF8().find(user.toUTF8()) != std::string::npos) 00047 return result + "<span class='chat-highlight'>" + msg + "</span>"; 00048 else 00049 return result + msg; 00050 } 00051 default: 00052 return ""; 00053 } 00054 } 00055 00056 00057 SimpleChatServer::SimpleChatServer(WServer& server) 00058 : server_(server) 00059 { } 00060 00061 bool SimpleChatServer::connect(Client *client, 00062 const ChatEventCallback& handleEvent) 00063 { 00064 boost::recursive_mutex::scoped_lock lock(mutex_); 00065 00066 if (clients_.count(client) == 0) { 00067 ClientInfo clientInfo; 00068 00069 clientInfo.sessionId = WApplication::instance()->sessionId(); 00070 clientInfo.eventCallback = handleEvent; 00071 00072 clients_[client] = clientInfo; 00073 00074 return true; 00075 } else 00076 return false; 00077 } 00078 00079 bool SimpleChatServer::disconnect(Client *client) 00080 { 00081 boost::recursive_mutex::scoped_lock lock(mutex_); 00082 00083 return clients_.erase(client) == 1; 00084 } 00085 00086 bool SimpleChatServer::login(const WString& user) 00087 { 00088 boost::recursive_mutex::scoped_lock lock(mutex_); 00089 00090 if (users_.find(user) == users_.end()) { 00091 users_.insert(user); 00092 00093 postChatEvent(ChatEvent(ChatEvent::Login, user)); 00094 00095 return true; 00096 } else 00097 return false; 00098 } 00099 00100 void SimpleChatServer::logout(const WString& user) 00101 { 00102 boost::recursive_mutex::scoped_lock lock(mutex_); 00103 00104 UserSet::iterator i = users_.find(user); 00105 00106 if (i != users_.end()) { 00107 users_.erase(i); 00108 00109 postChatEvent(ChatEvent(ChatEvent::Logout, user)); 00110 } 00111 } 00112 00113 bool SimpleChatServer::changeName(const WString& user, const WString& newUser) 00114 { 00115 if (user == newUser) 00116 return true; 00117 00118 boost::recursive_mutex::scoped_lock lock(mutex_); 00119 00120 UserSet::iterator i = users_.find(user); 00121 00122 if (i != users_.end()) { 00123 if (users_.count(newUser) == 0) { 00124 users_.erase(i); 00125 users_.insert(newUser); 00126 00127 postChatEvent(ChatEvent(ChatEvent::Rename, user, newUser)); 00128 00129 return true; 00130 } else 00131 return false; 00132 } else 00133 return false; 00134 } 00135 00136 WString SimpleChatServer::suggestGuest() 00137 { 00138 boost::recursive_mutex::scoped_lock lock(mutex_); 00139 00140 for (int i = 1;; ++i) { 00141 std::string s = "guest " + boost::lexical_cast<std::string>(i); 00142 WString ss = s; 00143 00144 if (users_.find(ss) == users_.end()) 00145 return ss; 00146 } 00147 } 00148 00149 void SimpleChatServer::sendMessage(const WString& user, const WString& message) 00150 { 00151 postChatEvent(ChatEvent(user, message)); 00152 } 00153 00154 void SimpleChatServer::postChatEvent(const ChatEvent& event) 00155 { 00156 boost::recursive_mutex::scoped_lock lock(mutex_); 00157 00158 WApplication *app = WApplication::instance(); 00159 00160 for (ClientMap::const_iterator i = clients_.begin(); i != clients_.end(); 00161 ++i) { 00162 /* 00163 * If the user corresponds to the current application, we directly 00164 * call the call back method. This avoids an unnecessary delay for 00165 * the update to the user causing the event. 00166 * 00167 * For other uses, we post it to their session. By posting the 00168 * event, we avoid dead-lock scenarios, race conditions, and 00169 * delivering the event to a session that is just about to be 00170 * terminated. 00171 */ 00172 if (app && app->sessionId() == i->second.sessionId) 00173 i->second.eventCallback(event); 00174 else 00175 server_.post(i->second.sessionId, 00176 boost::bind(i->second.eventCallback, event)); 00177 } 00178 } 00179 00180 SimpleChatServer::UserSet SimpleChatServer::users() 00181 { 00182 boost::recursive_mutex::scoped_lock lock(mutex_); 00183 00184 UserSet result = users_; 00185 00186 return result; 00187 } 00188