1 /* 2 * network_metaserver.h - Metaserver client 3 4 Copyright (C) 2004 and beyond by Woody Zenfell, III 5 and the "Aleph One" developers. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 This license is contained in the file "COPYING", 18 which is included with this source code; it is available online at 19 http://www.gnu.org/licenses/gpl.html 20 21 April 15, 2004 (Woody Zenfell): 22 Created. 23 */ 24 25 #ifndef NETWORK_METASERVER_H 26 #define NETWORK_METASERVER_H 27 28 #include "metaserver_messages.h" // RoomDescription 29 30 #include <exception> 31 #include <vector> 32 #include <map> 33 #include <memory> // unique_ptr 34 #include <set> 35 #include <stdexcept> 36 37 #include "Logging.h" 38 39 template <typename tElement> 40 class MetaserverMaintainedList 41 { 42 public: MetaserverMaintainedList()43 MetaserverMaintainedList() : m_target(Element::IdNone) { } 44 typedef tElement Element; 45 typedef typename Element::IDType IDType; 46 clear()47 void clear() { m_entries.clear(); } 48 processUpdates(const std::vector<Element> & updates)49 void processUpdates(const std::vector<Element>& updates) 50 { 51 for(size_t i = 0; i < updates.size(); i++) 52 processUpdate(updates[i].verb(), updates[i].id(), updates[i]); 53 54 if (m_target != Element::IdNone) 55 { 56 typename Map::iterator target = m_entries.find(m_target); 57 if (target != m_entries.end()) 58 { 59 target->second.target(true); 60 } 61 else 62 { 63 m_target = Element::IdNone; 64 } 65 } 66 } 67 entries()68 const std::vector<Element> entries() const 69 { 70 std::vector<Element> result; 71 72 for(typename Map::const_iterator i = m_entries.begin(); i != m_entries.end(); ++i) 73 { 74 result.push_back(i->second); 75 } 76 77 return result; 78 } 79 find(IDType id)80 const Element* find(IDType id) const 81 { 82 typename Map::const_iterator it = m_entries.find(id); 83 if (it != m_entries.end()) 84 { 85 return &it->second; 86 } 87 else 88 { 89 return 0; 90 } 91 } 92 93 enum 94 { 95 kAdd = 0, 96 kDelete = 1, 97 kRefresh = 2 98 }; 99 target()100 IDType target() { return m_target; } target(IDType id)101 void target(IDType id) 102 { 103 // clear the old target 104 typename Map::iterator old_target = (m_target == Element::IdNone) ? m_entries.end() : m_entries.find(m_target); 105 if (old_target != m_entries.end()) 106 { 107 old_target->second.target(false); 108 } 109 110 typename Map::iterator e = (id == Element::IdNone) ? m_entries.end() : m_entries.find(id); 111 if (e == m_entries.end()) 112 { 113 m_target = Element::IdNone; 114 } 115 else 116 { 117 m_target = id; 118 e->second.target(true); 119 } 120 } 121 122 123 private: 124 typedef std::map<IDType, Element> Map; 125 126 Map m_entries; 127 processUpdate(uint8 verb,IDType id,const Element & update)128 void processUpdate(uint8 verb, IDType id, const Element& update) 129 { 130 switch(verb) 131 { 132 case kAdd: 133 if(m_entries.find(id) != m_entries.end()) 134 { 135 logAnomaly("received instruction to add item with same ID (%d) as known item; using the new one only", id); 136 m_entries.erase(id); 137 } 138 m_entries.insert(typename Map::value_type(id, update)); 139 break; 140 141 case kDelete: 142 if(m_entries.erase(id) == 0) 143 { 144 logAnomaly("received instruction to delete unknown item (ID %d)", id); 145 } 146 break; 147 148 case kRefresh: 149 if(m_entries.erase(id) == 0) 150 { 151 logAnomaly("received instruction to refresh unknown item (ID %d); treating it as an add", id); 152 } 153 m_entries.insert(typename Map::value_type(id, update)); 154 break; 155 156 default: 157 logAnomaly("unknown list item verb %d - ignored", verb); 158 break; 159 } 160 } 161 162 IDType m_target; 163 }; 164 165 166 167 class CommunicationsChannel; 168 class MessageInflater; 169 class MessageHandler; 170 class MessageDispatcher; 171 172 class Message; 173 class ChatMessage; 174 class BroadcastMessage; 175 176 class MetaserverClient 177 { 178 public: 179 class NotificationAdapter 180 { 181 public: 182 virtual void playersInRoomChanged(const std::vector<MetaserverPlayerInfo>&) = 0; 183 virtual void gamesInRoomChanged(const std::vector<GameListMessage::GameListEntry>&) = 0; 184 virtual void receivedChatMessage(const std::string& senderName, uint32 senderID, const std::string& message) = 0; 185 virtual void receivedLocalMessage(const std::string& message) = 0; 186 virtual void receivedBroadcastMessage(const std::string& message) = 0; 187 virtual void receivedPrivateMessage(const std::string& senderName, uint32 senderID, const std::string& message) = 0; 188 virtual void roomDisconnected() = 0; ~NotificationAdapter()189 virtual ~NotificationAdapter() {} 190 }; 191 192 class NotificationAdapterInstaller 193 { 194 public: NotificationAdapterInstaller(NotificationAdapter * adapter,MetaserverClient & metaserverClient)195 NotificationAdapterInstaller(NotificationAdapter* adapter, MetaserverClient& metaserverClient) 196 : m_adapter(adapter), m_metaserverClient(metaserverClient) 197 { 198 m_previousAdapter = m_metaserverClient.notificationAdapter(); 199 m_metaserverClient.associateNotificationAdapter(m_adapter); 200 } 201 ~NotificationAdapterInstaller()202 ~NotificationAdapterInstaller() 203 { 204 assert(m_metaserverClient.notificationAdapter() == m_adapter); 205 m_metaserverClient.associateNotificationAdapter(m_previousAdapter); 206 } 207 208 private: 209 NotificationAdapter* m_previousAdapter; 210 NotificationAdapter* m_adapter; 211 MetaserverClient& m_metaserverClient; 212 213 NotificationAdapterInstaller(const NotificationAdapterInstaller&); 214 NotificationAdapterInstaller& operator =(const NotificationAdapterInstaller&); 215 }; 216 217 typedef std::vector<RoomDescription> Rooms; 218 typedef MetaserverMaintainedList<MetaserverPlayerInfo> PlayersInRoom; 219 typedef MetaserverMaintainedList<GameListMessage::GameListEntry> GamesInRoom; 220 221 222 MetaserverClient(); 223 associateNotificationAdapter(NotificationAdapter * adapter)224 void associateNotificationAdapter(NotificationAdapter* adapter) 225 { m_notificationAdapter = adapter; } notificationAdapter()226 NotificationAdapter* notificationAdapter() const { return m_notificationAdapter; } 227 228 class LoginDeniedException : public std::runtime_error 229 { 230 public: 231 enum { 232 SyntaxError, 233 GamesNotAllowed, 234 InvalidVersion, 235 BadUserOrPassword, 236 UserNotLoggedIn, 237 BadMetaserverVersion, 238 UserAlreadyLoggedIn, 239 UnknownGameType, 240 LoginSuccessful, 241 LogoutSuccessful, 242 PlayerNotInRoom, 243 GameAlreadyExists, 244 AccountAlreadyLoggedIn, 245 RoomFull, 246 AccountLocked, 247 NotSupported 248 }; 249 LoginDeniedException(int code,const std::string & arg)250 LoginDeniedException(int code, const std::string& arg) : std::runtime_error(arg), m_code(code) { } code()251 int code() const { return m_code; } 252 private: 253 int m_code; 254 }; 255 class ServerConnectException : public std::runtime_error 256 { 257 public: ServerConnectException(const std::string & arg)258 ServerConnectException(const std::string& arg) : std::runtime_error(arg) { } 259 }; 260 261 void connect(const std::string& serverName, uint16 port, const std::string& userName, const std::string& userPassword); 262 void disconnect(); 263 bool isConnected() const; 264 265 void setPlayerName(const std::string& name); playerName()266 const std::string& playerName() const { return m_playerName; } 267 268 void setAway(bool away, const std::string& away_message); 269 void setMode(uint16 mode, const std::string& session_id); 270 271 void setPlayerTeamName(const std::string& team); 272 273 const Rooms& rooms() const; 274 void setRoom(const RoomDescription& room); 275 playersInRoom()276 const std::vector<MetaserverPlayerInfo> playersInRoom() const { return m_playersInRoom.entries(); } gamesInRoom()277 const std::vector<GameListMessage::GameListEntry> gamesInRoom() const { return m_gamesInRoom.entries(); } 278 279 void pump(); 280 static void pumpAll(); 281 282 void sendChatMessage(const std::string& message); 283 void sendPrivateMessage(MetaserverPlayerInfo::IDType destination, const std::string& message); 284 void announceGame(uint16 gamePort, const GameDescription& description); 285 void announcePlayersInGame(uint8 players); 286 void announceGameStarted(int32 gameTimeInSeconds); 287 void announceGameReset(); 288 void announceGameDeleted(); 289 void ignore(const std::string& name); 290 void ignore(MetaserverPlayerInfo::IDType id); 291 bool is_ignored(MetaserverPlayerInfo::IDType id); 292 void syncGames(); 293 player_target(MetaserverPlayerInfo::IDType id)294 void player_target(MetaserverPlayerInfo::IDType id) { m_playersInRoom.target(id); }; player_target()295 MetaserverPlayerInfo::IDType player_target() { return m_playersInRoom.target(); }; find_player(MetaserverPlayerInfo::IDType id)296 const MetaserverPlayerInfo* find_player(MetaserverPlayerInfo::IDType id) { return m_playersInRoom.find(id); } game_target(GameListMessage::GameListEntry::IDType id)297 void game_target(GameListMessage::GameListEntry::IDType id) { m_gamesInRoom.target(id); } game_target()298 GameListMessage::GameListEntry::IDType game_target() { return m_gamesInRoom.target(); }; find_game(GameListMessage::GameListEntry::IDType id)299 const GameListMessage::GameListEntry* find_game(GameListMessage::GameListEntry::IDType id) { return m_gamesInRoom.find(id); } 300 301 ~MetaserverClient(); 302 303 private: 304 void handleUnexpectedMessage(Message* inMessage, CommunicationsChannel* inChannel); 305 void handleChatMessage(ChatMessage* inMessage, CommunicationsChannel* inChannel); 306 void handlePrivateMessage(PrivateMessage* inMessage, CommunicationsChannel* inChannel); 307 void handleKeepAliveMessage(Message* inMessage, CommunicationsChannel* inChannel); 308 void handleBroadcastMessage(BroadcastMessage* inMessage, CommunicationsChannel* inChannel); 309 void handlePlayerListMessage(PlayerListMessage* inMessage, CommunicationsChannel* inChannel); 310 void handleRoomListMessage(RoomListMessage* inMessage, CommunicationsChannel* inChannel); 311 void handleGameListMessage(GameListMessage* inMessage, CommunicationsChannel* inChannel); handleSetPlayerDataMessage(SetPlayerDataMessage *,CommunicationsChannel *)312 void handleSetPlayerDataMessage(SetPlayerDataMessage*, CommunicationsChannel *) { } 313 314 std::unique_ptr<CommunicationsChannel> m_channel; 315 std::unique_ptr<MessageInflater> m_inflater; 316 std::unique_ptr<MessageDispatcher> m_dispatcher; 317 std::unique_ptr<MessageDispatcher> m_loginDispatcher; 318 std::unique_ptr<MessageHandler> m_unexpectedMessageHandler; 319 std::unique_ptr<MessageHandler> m_chatMessageHandler; 320 std::unique_ptr<MessageHandler> m_keepAliveMessageHandler; 321 std::unique_ptr<MessageHandler> m_broadcastMessageHandler; 322 std::unique_ptr<MessageHandler> m_playerListMessageHandler; 323 std::unique_ptr<MessageHandler> m_roomListMessageHandler; 324 std::unique_ptr<MessageHandler> m_gameListMessageHandler; 325 std::unique_ptr<MessageHandler> m_privateMessageHandler; 326 std::unique_ptr<MessageHandler> m_setPlayerDataMessageHandler; 327 Rooms m_rooms; 328 RoomDescription m_room; 329 PlayersInRoom m_playersInRoom; 330 GamesInRoom m_gamesInRoom; 331 std::string m_playerName; 332 std::string m_teamName; 333 NotificationAdapter* m_notificationAdapter; 334 uint32 m_playerID; 335 336 static std::set<MetaserverClient*> s_instances; 337 static std::set<std::string> s_ignoreNames; 338 339 GameDescription m_gameDescription; 340 uint16 m_gamePort; 341 342 MetaserverPlayerInfo::IDType m_player_target; 343 bool m_player_target_exists; 344 345 bool m_notifiedOfDisconnected; 346 bool m_gameAnnounced; 347 }; 348 349 #endif // NETWORK_METASERVER_H 350