room_member.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <atomic>
  5. #include <list>
  6. #include <mutex>
  7. #include <set>
  8. #include <thread>
  9. #include "common/assert.h"
  10. #include "enet/enet.h"
  11. #include "network/packet.h"
  12. #include "network/room_member.h"
  13. namespace Network {
  14. constexpr u32 ConnectionTimeoutMs = 5000;
  15. class RoomMember::RoomMemberImpl {
  16. public:
  17. ENetHost* client = nullptr; ///< ENet network interface.
  18. ENetPeer* server = nullptr; ///< The server peer the client is connected to
  19. /// Information about the clients connected to the same room as us.
  20. MemberList member_information;
  21. /// Information about the room we're connected to.
  22. RoomInformation room_information;
  23. /// The current game name, id and version
  24. GameInfo current_game_info;
  25. std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
  26. void SetState(const State new_state);
  27. void SetError(const Error new_error);
  28. bool IsConnected() const;
  29. std::string nickname; ///< The nickname of this member.
  30. std::string username; ///< The username of this member.
  31. mutable std::mutex username_mutex; ///< Mutex for locking username.
  32. MacAddress mac_address; ///< The mac_address of this member.
  33. std::mutex network_mutex; ///< Mutex that controls access to the `client` variable.
  34. /// Thread that receives and dispatches network packets
  35. std::unique_ptr<std::thread> loop_thread;
  36. std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable.
  37. std::list<Packet> send_list; ///< A list that stores all packets to send the async
  38. template <typename T>
  39. using CallbackSet = std::set<CallbackHandle<T>>;
  40. std::mutex callback_mutex; ///< The mutex used for handling callbacks
  41. class Callbacks {
  42. public:
  43. template <typename T>
  44. CallbackSet<T>& Get();
  45. private:
  46. CallbackSet<WifiPacket> callback_set_wifi_packet;
  47. CallbackSet<ChatEntry> callback_set_chat_messages;
  48. CallbackSet<StatusMessageEntry> callback_set_status_messages;
  49. CallbackSet<RoomInformation> callback_set_room_information;
  50. CallbackSet<State> callback_set_state;
  51. CallbackSet<Error> callback_set_error;
  52. CallbackSet<Room::BanList> callback_set_ban_list;
  53. };
  54. Callbacks callbacks; ///< All CallbackSets to all events
  55. void MemberLoop();
  56. void StartLoop();
  57. /**
  58. * Sends data to the room. It will be send on channel 0 with flag RELIABLE
  59. * @param packet The data to send
  60. */
  61. void Send(Packet&& packet);
  62. /**
  63. * Sends a request to the server, asking for permission to join a room with the specified
  64. * nickname and preferred mac.
  65. * @params nickname The desired nickname.
  66. * @params console_id_hash A hash of the Console ID.
  67. * @params preferred_mac The preferred MAC address to use in the room, the NoPreferredMac tells
  68. * @params password The password for the room
  69. * the server to assign one for us.
  70. */
  71. void SendJoinRequest(const std::string& nickname_, const std::string& console_id_hash,
  72. const MacAddress& preferred_mac = NoPreferredMac,
  73. const std::string& password = "", const std::string& token = "");
  74. /**
  75. * Extracts a MAC Address from a received ENet packet.
  76. * @param event The ENet event that was received.
  77. */
  78. void HandleJoinPacket(const ENetEvent* event);
  79. /**
  80. * Extracts RoomInformation and MemberInformation from a received ENet packet.
  81. * @param event The ENet event that was received.
  82. */
  83. void HandleRoomInformationPacket(const ENetEvent* event);
  84. /**
  85. * Extracts a WifiPacket from a received ENet packet.
  86. * @param event The ENet event that was received.
  87. */
  88. void HandleWifiPackets(const ENetEvent* event);
  89. /**
  90. * Extracts a chat entry from a received ENet packet and adds it to the chat queue.
  91. * @param event The ENet event that was received.
  92. */
  93. void HandleChatPacket(const ENetEvent* event);
  94. /**
  95. * Extracts a system message entry from a received ENet packet and adds it to the system message
  96. * queue.
  97. * @param event The ENet event that was received.
  98. */
  99. void HandleStatusMessagePacket(const ENetEvent* event);
  100. /**
  101. * Extracts a ban list request response from a received ENet packet.
  102. * @param event The ENet event that was received.
  103. */
  104. void HandleModBanListResponsePacket(const ENetEvent* event);
  105. /**
  106. * Disconnects the RoomMember from the Room
  107. */
  108. void Disconnect();
  109. template <typename T>
  110. void Invoke(const T& data);
  111. template <typename T>
  112. CallbackHandle<T> Bind(std::function<void(const T&)> callback);
  113. };
  114. // RoomMemberImpl
  115. void RoomMember::RoomMemberImpl::SetState(const State new_state) {
  116. if (state != new_state) {
  117. state = new_state;
  118. Invoke<State>(state);
  119. }
  120. }
  121. void RoomMember::RoomMemberImpl::SetError(const Error new_error) {
  122. Invoke<Error>(new_error);
  123. }
  124. bool RoomMember::RoomMemberImpl::IsConnected() const {
  125. return state == State::Joining || state == State::Joined || state == State::Moderator;
  126. }
  127. void RoomMember::RoomMemberImpl::MemberLoop() {
  128. // Receive packets while the connection is open
  129. while (IsConnected()) {
  130. std::lock_guard lock(network_mutex);
  131. ENetEvent event;
  132. if (enet_host_service(client, &event, 16) > 0) {
  133. switch (event.type) {
  134. case ENET_EVENT_TYPE_RECEIVE:
  135. switch (event.packet->data[0]) {
  136. case IdWifiPacket:
  137. HandleWifiPackets(&event);
  138. break;
  139. case IdChatMessage:
  140. HandleChatPacket(&event);
  141. break;
  142. case IdStatusMessage:
  143. HandleStatusMessagePacket(&event);
  144. break;
  145. case IdRoomInformation:
  146. HandleRoomInformationPacket(&event);
  147. break;
  148. case IdJoinSuccess:
  149. case IdJoinSuccessAsMod:
  150. // The join request was successful, we are now in the room.
  151. // If we joined successfully, there must be at least one client in the room: us.
  152. ASSERT_MSG(member_information.size() > 0,
  153. "We have not yet received member information.");
  154. HandleJoinPacket(&event); // Get the MAC Address for the client
  155. if (event.packet->data[0] == IdJoinSuccessAsMod) {
  156. SetState(State::Moderator);
  157. } else {
  158. SetState(State::Joined);
  159. }
  160. break;
  161. case IdModBanListResponse:
  162. HandleModBanListResponsePacket(&event);
  163. break;
  164. case IdRoomIsFull:
  165. SetState(State::Idle);
  166. SetError(Error::RoomIsFull);
  167. break;
  168. case IdNameCollision:
  169. SetState(State::Idle);
  170. SetError(Error::NameCollision);
  171. break;
  172. case IdMacCollision:
  173. SetState(State::Idle);
  174. SetError(Error::MacCollision);
  175. break;
  176. case IdConsoleIdCollision:
  177. SetState(State::Idle);
  178. SetError(Error::ConsoleIdCollision);
  179. break;
  180. case IdVersionMismatch:
  181. SetState(State::Idle);
  182. SetError(Error::WrongVersion);
  183. break;
  184. case IdWrongPassword:
  185. SetState(State::Idle);
  186. SetError(Error::WrongPassword);
  187. break;
  188. case IdCloseRoom:
  189. SetState(State::Idle);
  190. SetError(Error::LostConnection);
  191. break;
  192. case IdHostKicked:
  193. SetState(State::Idle);
  194. SetError(Error::HostKicked);
  195. break;
  196. case IdHostBanned:
  197. SetState(State::Idle);
  198. SetError(Error::HostBanned);
  199. break;
  200. case IdModPermissionDenied:
  201. SetError(Error::PermissionDenied);
  202. break;
  203. case IdModNoSuchUser:
  204. SetError(Error::NoSuchUser);
  205. break;
  206. }
  207. enet_packet_destroy(event.packet);
  208. break;
  209. case ENET_EVENT_TYPE_DISCONNECT:
  210. if (state == State::Joined || state == State::Moderator) {
  211. SetState(State::Idle);
  212. SetError(Error::LostConnection);
  213. }
  214. break;
  215. case ENET_EVENT_TYPE_NONE:
  216. break;
  217. case ENET_EVENT_TYPE_CONNECT:
  218. // The ENET_EVENT_TYPE_CONNECT event can not possibly happen here because we're
  219. // already connected
  220. ASSERT_MSG(false, "Received unexpected connect event while already connected");
  221. break;
  222. }
  223. }
  224. std::list<Packet> packets;
  225. {
  226. std::lock_guard send_lock(send_list_mutex);
  227. packets.swap(send_list);
  228. }
  229. for (const auto& packet : packets) {
  230. ENetPacket* enetPacket = enet_packet_create(packet.GetData(), packet.GetDataSize(),
  231. ENET_PACKET_FLAG_RELIABLE);
  232. enet_peer_send(server, 0, enetPacket);
  233. }
  234. enet_host_flush(client);
  235. }
  236. Disconnect();
  237. };
  238. void RoomMember::RoomMemberImpl::StartLoop() {
  239. loop_thread = std::make_unique<std::thread>(&RoomMember::RoomMemberImpl::MemberLoop, this);
  240. }
  241. void RoomMember::RoomMemberImpl::Send(Packet&& packet) {
  242. std::lock_guard lock(send_list_mutex);
  243. send_list.push_back(std::move(packet));
  244. }
  245. void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname_,
  246. const std::string& console_id_hash,
  247. const MacAddress& preferred_mac,
  248. const std::string& password,
  249. const std::string& token) {
  250. Packet packet;
  251. packet << static_cast<u8>(IdJoinRequest);
  252. packet << nickname_;
  253. packet << console_id_hash;
  254. packet << preferred_mac;
  255. packet << network_version;
  256. packet << password;
  257. packet << token;
  258. Send(std::move(packet));
  259. }
  260. void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* event) {
  261. Packet packet;
  262. packet.Append(event->packet->data, event->packet->dataLength);
  263. // Ignore the first byte, which is the message id.
  264. packet.IgnoreBytes(sizeof(u8)); // Ignore the message type
  265. RoomInformation info{};
  266. packet >> info.name;
  267. packet >> info.description;
  268. packet >> info.member_slots;
  269. packet >> info.port;
  270. packet >> info.preferred_game.name;
  271. packet >> info.host_username;
  272. room_information.name = info.name;
  273. room_information.description = info.description;
  274. room_information.member_slots = info.member_slots;
  275. room_information.port = info.port;
  276. room_information.preferred_game = info.preferred_game;
  277. room_information.host_username = info.host_username;
  278. u32 num_members;
  279. packet >> num_members;
  280. member_information.resize(num_members);
  281. for (auto& member : member_information) {
  282. packet >> member.nickname;
  283. packet >> member.mac_address;
  284. packet >> member.game_info.name;
  285. packet >> member.game_info.id;
  286. packet >> member.username;
  287. packet >> member.display_name;
  288. packet >> member.avatar_url;
  289. {
  290. std::lock_guard lock(username_mutex);
  291. if (member.nickname == nickname) {
  292. username = member.username;
  293. }
  294. }
  295. }
  296. Invoke(room_information);
  297. }
  298. void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
  299. Packet packet;
  300. packet.Append(event->packet->data, event->packet->dataLength);
  301. // Ignore the first byte, which is the message id.
  302. packet.IgnoreBytes(sizeof(u8)); // Ignore the message type
  303. // Parse the MAC Address from the packet
  304. packet >> mac_address;
  305. }
  306. void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) {
  307. WifiPacket wifi_packet{};
  308. Packet packet;
  309. packet.Append(event->packet->data, event->packet->dataLength);
  310. // Ignore the first byte, which is the message id.
  311. packet.IgnoreBytes(sizeof(u8)); // Ignore the message type
  312. // Parse the WifiPacket from the packet
  313. u8 frame_type;
  314. packet >> frame_type;
  315. WifiPacket::PacketType type = static_cast<WifiPacket::PacketType>(frame_type);
  316. wifi_packet.type = type;
  317. packet >> wifi_packet.channel;
  318. packet >> wifi_packet.transmitter_address;
  319. packet >> wifi_packet.destination_address;
  320. packet >> wifi_packet.data;
  321. Invoke<WifiPacket>(wifi_packet);
  322. }
  323. void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
  324. Packet packet;
  325. packet.Append(event->packet->data, event->packet->dataLength);
  326. // Ignore the first byte, which is the message id.
  327. packet.IgnoreBytes(sizeof(u8));
  328. ChatEntry chat_entry{};
  329. packet >> chat_entry.nickname;
  330. packet >> chat_entry.username;
  331. packet >> chat_entry.message;
  332. Invoke<ChatEntry>(chat_entry);
  333. }
  334. void RoomMember::RoomMemberImpl::HandleStatusMessagePacket(const ENetEvent* event) {
  335. Packet packet;
  336. packet.Append(event->packet->data, event->packet->dataLength);
  337. // Ignore the first byte, which is the message id.
  338. packet.IgnoreBytes(sizeof(u8));
  339. StatusMessageEntry status_message_entry{};
  340. u8 type{};
  341. packet >> type;
  342. status_message_entry.type = static_cast<StatusMessageTypes>(type);
  343. packet >> status_message_entry.nickname;
  344. packet >> status_message_entry.username;
  345. Invoke<StatusMessageEntry>(status_message_entry);
  346. }
  347. void RoomMember::RoomMemberImpl::HandleModBanListResponsePacket(const ENetEvent* event) {
  348. Packet packet;
  349. packet.Append(event->packet->data, event->packet->dataLength);
  350. // Ignore the first byte, which is the message id.
  351. packet.IgnoreBytes(sizeof(u8));
  352. Room::BanList ban_list = {};
  353. packet >> ban_list.first;
  354. packet >> ban_list.second;
  355. Invoke<Room::BanList>(ban_list);
  356. }
  357. void RoomMember::RoomMemberImpl::Disconnect() {
  358. member_information.clear();
  359. room_information.member_slots = 0;
  360. room_information.name.clear();
  361. if (!server) {
  362. return;
  363. }
  364. enet_peer_disconnect(server, 0);
  365. ENetEvent event;
  366. while (enet_host_service(client, &event, ConnectionTimeoutMs) > 0) {
  367. switch (event.type) {
  368. case ENET_EVENT_TYPE_RECEIVE:
  369. enet_packet_destroy(event.packet); // Ignore all incoming data
  370. break;
  371. case ENET_EVENT_TYPE_DISCONNECT:
  372. server = nullptr;
  373. return;
  374. case ENET_EVENT_TYPE_NONE:
  375. case ENET_EVENT_TYPE_CONNECT:
  376. break;
  377. }
  378. }
  379. // didn't disconnect gracefully force disconnect
  380. enet_peer_reset(server);
  381. server = nullptr;
  382. }
  383. template <>
  384. RoomMember::RoomMemberImpl::CallbackSet<WifiPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() {
  385. return callback_set_wifi_packet;
  386. }
  387. template <>
  388. RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>&
  389. RoomMember::RoomMemberImpl::Callbacks::Get() {
  390. return callback_set_state;
  391. }
  392. template <>
  393. RoomMember::RoomMemberImpl::CallbackSet<RoomMember::Error>&
  394. RoomMember::RoomMemberImpl::Callbacks::Get() {
  395. return callback_set_error;
  396. }
  397. template <>
  398. RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>&
  399. RoomMember::RoomMemberImpl::Callbacks::Get() {
  400. return callback_set_room_information;
  401. }
  402. template <>
  403. RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl::Callbacks::Get() {
  404. return callback_set_chat_messages;
  405. }
  406. template <>
  407. RoomMember::RoomMemberImpl::CallbackSet<StatusMessageEntry>&
  408. RoomMember::RoomMemberImpl::Callbacks::Get() {
  409. return callback_set_status_messages;
  410. }
  411. template <>
  412. RoomMember::RoomMemberImpl::CallbackSet<Room::BanList>&
  413. RoomMember::RoomMemberImpl::Callbacks::Get() {
  414. return callback_set_ban_list;
  415. }
  416. template <typename T>
  417. void RoomMember::RoomMemberImpl::Invoke(const T& data) {
  418. std::lock_guard lock(callback_mutex);
  419. CallbackSet<T> callback_set = callbacks.Get<T>();
  420. for (auto const& callback : callback_set) {
  421. (*callback)(data);
  422. }
  423. }
  424. template <typename T>
  425. RoomMember::CallbackHandle<T> RoomMember::RoomMemberImpl::Bind(
  426. std::function<void(const T&)> callback) {
  427. std::lock_guard lock(callback_mutex);
  428. CallbackHandle<T> handle;
  429. handle = std::make_shared<std::function<void(const T&)>>(callback);
  430. callbacks.Get<T>().insert(handle);
  431. return handle;
  432. }
  433. // RoomMember
  434. RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} {}
  435. RoomMember::~RoomMember() {
  436. ASSERT_MSG(!IsConnected(), "RoomMember is being destroyed while connected");
  437. if (room_member_impl->loop_thread) {
  438. Leave();
  439. }
  440. }
  441. RoomMember::State RoomMember::GetState() const {
  442. return room_member_impl->state;
  443. }
  444. const RoomMember::MemberList& RoomMember::GetMemberInformation() const {
  445. return room_member_impl->member_information;
  446. }
  447. const std::string& RoomMember::GetNickname() const {
  448. return room_member_impl->nickname;
  449. }
  450. const std::string& RoomMember::GetUsername() const {
  451. std::lock_guard lock(room_member_impl->username_mutex);
  452. return room_member_impl->username;
  453. }
  454. const MacAddress& RoomMember::GetMacAddress() const {
  455. ASSERT_MSG(IsConnected(), "Tried to get MAC address while not connected");
  456. return room_member_impl->mac_address;
  457. }
  458. RoomInformation RoomMember::GetRoomInformation() const {
  459. return room_member_impl->room_information;
  460. }
  461. void RoomMember::Join(const std::string& nick, const std::string& console_id_hash,
  462. const char* server_addr, u16 server_port, u16 client_port,
  463. const MacAddress& preferred_mac, const std::string& password,
  464. const std::string& token) {
  465. // If the member is connected, kill the connection first
  466. if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) {
  467. Leave();
  468. }
  469. // If the thread isn't running but the ptr still exists, reset it
  470. else if (room_member_impl->loop_thread) {
  471. room_member_impl->loop_thread.reset();
  472. }
  473. if (!room_member_impl->client) {
  474. room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0);
  475. ASSERT_MSG(room_member_impl->client != nullptr, "Could not create client");
  476. }
  477. room_member_impl->SetState(State::Joining);
  478. ENetAddress address{};
  479. enet_address_set_host(&address, server_addr);
  480. address.port = server_port;
  481. room_member_impl->server =
  482. enet_host_connect(room_member_impl->client, &address, NumChannels, 0);
  483. if (!room_member_impl->server) {
  484. room_member_impl->SetState(State::Idle);
  485. room_member_impl->SetError(Error::UnknownError);
  486. return;
  487. }
  488. ENetEvent event{};
  489. int net = enet_host_service(room_member_impl->client, &event, ConnectionTimeoutMs);
  490. if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
  491. room_member_impl->nickname = nick;
  492. room_member_impl->StartLoop();
  493. room_member_impl->SendJoinRequest(nick, console_id_hash, preferred_mac, password, token);
  494. SendGameInfo(room_member_impl->current_game_info);
  495. } else {
  496. enet_peer_disconnect(room_member_impl->server, 0);
  497. room_member_impl->SetState(State::Idle);
  498. room_member_impl->SetError(Error::CouldNotConnect);
  499. }
  500. }
  501. bool RoomMember::IsConnected() const {
  502. return room_member_impl->IsConnected();
  503. }
  504. void RoomMember::SendWifiPacket(const WifiPacket& wifi_packet) {
  505. Packet packet;
  506. packet << static_cast<u8>(IdWifiPacket);
  507. packet << static_cast<u8>(wifi_packet.type);
  508. packet << wifi_packet.channel;
  509. packet << wifi_packet.transmitter_address;
  510. packet << wifi_packet.destination_address;
  511. packet << wifi_packet.data;
  512. room_member_impl->Send(std::move(packet));
  513. }
  514. void RoomMember::SendChatMessage(const std::string& message) {
  515. Packet packet;
  516. packet << static_cast<u8>(IdChatMessage);
  517. packet << message;
  518. room_member_impl->Send(std::move(packet));
  519. }
  520. void RoomMember::SendGameInfo(const GameInfo& game_info) {
  521. room_member_impl->current_game_info = game_info;
  522. if (!IsConnected())
  523. return;
  524. Packet packet;
  525. packet << static_cast<u8>(IdSetGameInfo);
  526. packet << game_info.name;
  527. packet << game_info.id;
  528. room_member_impl->Send(std::move(packet));
  529. }
  530. void RoomMember::SendModerationRequest(RoomMessageTypes type, const std::string& nickname) {
  531. ASSERT_MSG(type == IdModKick || type == IdModBan || type == IdModUnban,
  532. "type is not a moderation request");
  533. if (!IsConnected())
  534. return;
  535. Packet packet;
  536. packet << static_cast<u8>(type);
  537. packet << nickname;
  538. room_member_impl->Send(std::move(packet));
  539. }
  540. void RoomMember::RequestBanList() {
  541. if (!IsConnected())
  542. return;
  543. Packet packet;
  544. packet << static_cast<u8>(IdModGetBanList);
  545. room_member_impl->Send(std::move(packet));
  546. }
  547. RoomMember::CallbackHandle<RoomMember::State> RoomMember::BindOnStateChanged(
  548. std::function<void(const RoomMember::State&)> callback) {
  549. return room_member_impl->Bind(callback);
  550. }
  551. RoomMember::CallbackHandle<RoomMember::Error> RoomMember::BindOnError(
  552. std::function<void(const RoomMember::Error&)> callback) {
  553. return room_member_impl->Bind(callback);
  554. }
  555. RoomMember::CallbackHandle<WifiPacket> RoomMember::BindOnWifiPacketReceived(
  556. std::function<void(const WifiPacket&)> callback) {
  557. return room_member_impl->Bind(callback);
  558. }
  559. RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged(
  560. std::function<void(const RoomInformation&)> callback) {
  561. return room_member_impl->Bind(callback);
  562. }
  563. RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved(
  564. std::function<void(const ChatEntry&)> callback) {
  565. return room_member_impl->Bind(callback);
  566. }
  567. RoomMember::CallbackHandle<StatusMessageEntry> RoomMember::BindOnStatusMessageReceived(
  568. std::function<void(const StatusMessageEntry&)> callback) {
  569. return room_member_impl->Bind(callback);
  570. }
  571. RoomMember::CallbackHandle<Room::BanList> RoomMember::BindOnBanListReceived(
  572. std::function<void(const Room::BanList&)> callback) {
  573. return room_member_impl->Bind(callback);
  574. }
  575. template <typename T>
  576. void RoomMember::Unbind(CallbackHandle<T> handle) {
  577. std::lock_guard lock(room_member_impl->callback_mutex);
  578. room_member_impl->callbacks.Get<T>().erase(handle);
  579. }
  580. void RoomMember::Leave() {
  581. room_member_impl->SetState(State::Idle);
  582. room_member_impl->loop_thread->join();
  583. room_member_impl->loop_thread.reset();
  584. enet_host_destroy(room_member_impl->client);
  585. room_member_impl->client = nullptr;
  586. }
  587. template void RoomMember::Unbind(CallbackHandle<WifiPacket>);
  588. template void RoomMember::Unbind(CallbackHandle<RoomMember::State>);
  589. template void RoomMember::Unbind(CallbackHandle<RoomMember::Error>);
  590. template void RoomMember::Unbind(CallbackHandle<RoomInformation>);
  591. template void RoomMember::Unbind(CallbackHandle<ChatEntry>);
  592. template void RoomMember::Unbind(CallbackHandle<StatusMessageEntry>);
  593. template void RoomMember::Unbind(CallbackHandle<Room::BanList>);
  594. } // namespace Network