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