SimpleChatServer.C 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright (C) 2008 Emweb bvba, Heverlee, Belgium.
  3. *
  4. * See the LICENSE file for terms of use.
  5. */
  6. #include "SimpleChatServer.h"
  7. #include <Wt/WServer>
  8. #include <iostream>
  9. #include <boost/lexical_cast.hpp>
  10. using namespace Wt;
  11. const WString ChatEvent::formattedHTML(const WString& user,
  12. TextFormat format) const
  13. {
  14. switch (type_) {
  15. case Login:
  16. return WString::fromUTF8("<span class='chat-info'>")
  17. + WWebWidget::escapeText(user_) + " joined.</span>";
  18. case Logout:
  19. return WString::fromUTF8("<span class='chat-info'>")
  20. + ((user == user_) ?
  21. WString::fromUTF8("You") :
  22. WWebWidget::escapeText(user_))
  23. + " logged out.</span>";
  24. case Rename:
  25. return "<span class='chat-info'>"
  26. + ((user == data_ || user == user_) ?
  27. "You are" :
  28. (WWebWidget::escapeText(user_) + " is"))
  29. + " now known as " + WWebWidget::escapeText(data_) + ".</span>";
  30. case Message:{
  31. WString result;
  32. result = WString("<span class='")
  33. + ((user == user_) ?
  34. "chat-self" :
  35. "chat-user")
  36. + "'>" + WWebWidget::escapeText(user_) + ":</span>";
  37. WString msg
  38. = (format == XHTMLText ? message_ : WWebWidget::escapeText(message_));
  39. if (message_.toUTF8().find(user.toUTF8()) != std::string::npos)
  40. return result + "<span class='chat-highlight'>" + msg + "</span>";
  41. else
  42. return result + msg;
  43. }
  44. default:
  45. return "";
  46. }
  47. }
  48. SimpleChatServer::SimpleChatServer(WServer& server)
  49. : server_(server)
  50. { }
  51. bool SimpleChatServer::connect(Client *client,
  52. const ChatEventCallback& handleEvent)
  53. {
  54. boost::recursive_mutex::scoped_lock lock(mutex_);
  55. if (clients_.count(client) == 0) {
  56. ClientInfo clientInfo;
  57. clientInfo.sessionId = WApplication::instance()->sessionId();
  58. clientInfo.eventCallback = handleEvent;
  59. clients_[client] = clientInfo;
  60. return true;
  61. } else
  62. return false;
  63. }
  64. bool SimpleChatServer::disconnect(Client *client)
  65. {
  66. boost::recursive_mutex::scoped_lock lock(mutex_);
  67. return clients_.erase(client) == 1;
  68. }
  69. bool SimpleChatServer::login(const WString& user)
  70. {
  71. boost::recursive_mutex::scoped_lock lock(mutex_);
  72. if (users_.find(user) == users_.end()) {
  73. users_.insert(user);
  74. postChatEvent(ChatEvent(ChatEvent::Login, user));
  75. return true;
  76. } else
  77. return false;
  78. }
  79. void SimpleChatServer::logout(const WString& user)
  80. {
  81. boost::recursive_mutex::scoped_lock lock(mutex_);
  82. UserSet::iterator i = users_.find(user);
  83. if (i != users_.end()) {
  84. users_.erase(i);
  85. postChatEvent(ChatEvent(ChatEvent::Logout, user));
  86. }
  87. }
  88. bool SimpleChatServer::changeName(const WString& user, const WString& newUser)
  89. {
  90. if (user == newUser)
  91. return true;
  92. boost::recursive_mutex::scoped_lock lock(mutex_);
  93. UserSet::iterator i = users_.find(user);
  94. if (i != users_.end()) {
  95. if (users_.count(newUser) == 0) {
  96. users_.erase(i);
  97. users_.insert(newUser);
  98. postChatEvent(ChatEvent(ChatEvent::Rename, user, newUser));
  99. return true;
  100. } else
  101. return false;
  102. } else
  103. return false;
  104. }
  105. WString SimpleChatServer::suggestGuest()
  106. {
  107. boost::recursive_mutex::scoped_lock lock(mutex_);
  108. for (int i = 1;; ++i) {
  109. std::string s = "guest " + boost::lexical_cast<std::string>(i);
  110. WString ss = s;
  111. if (users_.find(ss) == users_.end())
  112. return ss;
  113. }
  114. }
  115. void SimpleChatServer::sendMessage(const WString& user, const WString& message)
  116. {
  117. postChatEvent(ChatEvent(user, message));
  118. }
  119. void SimpleChatServer::postChatEvent(const ChatEvent& event)
  120. {
  121. boost::recursive_mutex::scoped_lock lock(mutex_);
  122. WApplication *app = WApplication::instance();
  123. for (ClientMap::const_iterator i = clients_.begin(); i != clients_.end();
  124. ++i) {
  125. /*
  126. * If the user corresponds to the current application, we directly
  127. * call the call back method. This avoids an unnecessary delay for
  128. * the update to the user causing the event.
  129. *
  130. * For other uses, we post it to their session. By posting the
  131. * event, we avoid dead-lock scenarios, race conditions, and
  132. * delivering the event to a session that is just about to be
  133. * terminated.
  134. */
  135. if (app && app->sessionId() == i->second.sessionId)
  136. i->second.eventCallback(event);
  137. else
  138. server_.post(i->second.sessionId,
  139. boost::bind(i->second.eventCallback, event));
  140. }
  141. }
  142. SimpleChatServer::UserSet SimpleChatServer::users()
  143. {
  144. boost::recursive_mutex::scoped_lock lock(mutex_);
  145. UserSet result = users_;
  146. return result;
  147. }