Przeglądaj źródła

Added missing parts in libnetwork (#2838)

* Network: Set and send the game information over enet

Added Callbacks for RoomMember and GetMemberList to Room in preparation for web_services.
B3n30 9 lat temu
rodzic
commit
5d0a1e7efd

+ 1 - 1
src/core/CMakeLists.txt

@@ -388,7 +388,7 @@ set(HEADERS
 
 create_directory_groups(${SRCS} ${HEADERS})
 add_library(core STATIC ${SRCS} ${HEADERS})
-target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
+target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
 target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt)
 if (ENABLE_WEB_SERVICE)
     target_link_libraries(core PUBLIC json-headers web_service)

+ 5 - 0
src/core/core.cpp

@@ -19,6 +19,7 @@
 #include "core/loader/loader.h"
 #include "core/memory_setup.h"
 #include "core/settings.h"
+#include "network/network.h"
 #include "video_core/video_core.h"
 
 namespace Core {
@@ -188,6 +189,10 @@ void System::Shutdown() {
     cpu_core = nullptr;
     app_loader = nullptr;
     telemetry_session = nullptr;
+    if (auto room_member = Network::GetRoomMember().lock()) {
+        Network::GameInfo game_info{};
+        room_member->SendGameInfo(game_info);
+    }
 
     LOG_DEBUG(Core, "Shutdown OK");
 }

+ 8 - 0
src/core/loader/ncch.cpp

@@ -20,6 +20,7 @@
 #include "core/loader/ncch.h"
 #include "core/loader/smdh.h"
 #include "core/memory.h"
+#include "network/network.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Loader namespace
@@ -350,6 +351,13 @@ ResultStatus AppLoader_NCCH::Load() {
 
     Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", program_id);
 
+    if (auto room_member = Network::GetRoomMember().lock()) {
+        Network::GameInfo game_info;
+        ReadTitle(game_info.name);
+        game_info.id = ncch_header.program_id;
+        room_member->SendGameInfo(game_info);
+    }
+
     is_loaded = true; // Set state to loaded
 
     result = LoadExec(); // Load the executable into memory for booting

+ 38 - 0
src/network/packet.cpp

@@ -13,6 +13,18 @@
 
 namespace Network {
 
+#ifndef htonll
+u64 htonll(u64 x) {
+    return ((1 == htonl(1)) ? (x) : ((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32));
+}
+#endif
+
+#ifndef ntohll
+u64 ntohll(u64 x) {
+    return ((1 == ntohl(1)) ? (x) : ((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32));
+}
+#endif
+
 void Packet::Append(const void* in_data, std::size_t size_in_bytes) {
     if (in_data && (size_in_bytes > 0)) {
         std::size_t start = data.size();
@@ -100,6 +112,20 @@ Packet& Packet::operator>>(u32& out_data) {
     return *this;
 }
 
+Packet& Packet::operator>>(s64& out_data) {
+    s64 value;
+    Read(&value, sizeof(value));
+    out_data = ntohll(value);
+    return *this;
+}
+
+Packet& Packet::operator>>(u64& out_data) {
+    u64 value;
+    Read(&value, sizeof(value));
+    out_data = ntohll(value);
+    return *this;
+}
+
 Packet& Packet::operator>>(float& out_data) {
     Read(&out_data, sizeof(out_data));
     return *this;
@@ -183,6 +209,18 @@ Packet& Packet::operator<<(u32 in_data) {
     return *this;
 }
 
+Packet& Packet::operator<<(s64 in_data) {
+    s64 toWrite = htonll(in_data);
+    Append(&toWrite, sizeof(toWrite));
+    return *this;
+}
+
+Packet& Packet::operator<<(u64 in_data) {
+    u64 toWrite = htonll(in_data);
+    Append(&toWrite, sizeof(toWrite));
+    return *this;
+}
+
 Packet& Packet::operator<<(float in_data) {
     Append(&in_data, sizeof(in_data));
     return *this;

+ 4 - 0
src/network/packet.h

@@ -72,6 +72,8 @@ public:
     Packet& operator>>(u16& out_data);
     Packet& operator>>(s32& out_data);
     Packet& operator>>(u32& out_data);
+    Packet& operator>>(s64& out_data);
+    Packet& operator>>(u64& out_data);
     Packet& operator>>(float& out_data);
     Packet& operator>>(double& out_data);
     Packet& operator>>(char* out_data);
@@ -89,6 +91,8 @@ public:
     Packet& operator<<(u16 in_data);
     Packet& operator<<(s32 in_data);
     Packet& operator<<(u32 in_data);
+    Packet& operator<<(s64 in_data);
+    Packet& operator<<(u64 in_data);
     Packet& operator<<(float in_data);
     Packet& operator<<(double in_data);
     Packet& operator<<(const char* in_data);

+ 63 - 21
src/network/room.cpp

@@ -4,9 +4,9 @@
 
 #include <algorithm>
 #include <atomic>
+#include <mutex>
 #include <random>
 #include <thread>
-#include <vector>
 #include "enet/enet.h"
 #include "network/packet.h"
 #include "network/room.h"
@@ -29,12 +29,14 @@ public:
 
     struct Member {
         std::string nickname;   ///< The nickname of the member.
-        std::string game_name;  ///< The current game of the member
+        GameInfo game_info;     ///< The current game of the member
         MacAddress mac_address; ///< The assigned mac address of the member.
         ENetPeer* peer;         ///< The remote peer.
     };
     using MemberList = std::vector<Member>;
-    MemberList members; ///< Information about the members of this room.
+    MemberList members;              ///< Information about the members of this room
+    mutable std::mutex member_mutex; ///< Mutex for locking the members list
+    /// This should be a std::shared_mutex as soon as C++17 is supported
 
     RoomImpl()
         : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {}
@@ -147,7 +149,7 @@ void Room::RoomImpl::ServerLoop() {
                 case IdJoinRequest:
                     HandleJoinRequest(&event);
                     break;
-                case IdSetGameName:
+                case IdSetGameInfo:
                     HandleGameNamePacket(&event);
                     break;
                 case IdWifiPacket:
@@ -213,7 +215,10 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
     member.nickname = nickname;
     member.peer = event->peer;
 
-    members.push_back(std::move(member));
+    {
+        std::lock_guard<std::mutex> lock(member_mutex);
+        members.push_back(std::move(member));
+    }
 
     // Notify everyone that the room information has changed.
     BroadcastRoomInformation();
@@ -223,12 +228,14 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
 bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const {
     // A nickname is valid if it is not already taken by anybody else in the room.
     // TODO(B3N30): Check for empty names, spaces, etc.
+    std::lock_guard<std::mutex> lock(member_mutex);
     return std::all_of(members.begin(), members.end(),
                        [&nickname](const auto& member) { return member.nickname != nickname; });
 }
 
 bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const {
     // A MAC address is valid if it is not already taken by anybody else in the room.
+    std::lock_guard<std::mutex> lock(member_mutex);
     return std::all_of(members.begin(), members.end(),
                        [&address](const auto& member) { return member.mac_address != address; });
 }
@@ -279,6 +286,7 @@ void Room::RoomImpl::SendCloseMessage() {
     packet << static_cast<u8>(IdCloseRoom);
     ENetPacket* enet_packet =
         enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
+    std::lock_guard<std::mutex> lock(member_mutex);
     for (auto& member : members) {
         enet_peer_send(member.peer, 0, enet_packet);
     }
@@ -295,10 +303,14 @@ void Room::RoomImpl::BroadcastRoomInformation() {
     packet << room_information.member_slots;
 
     packet << static_cast<u32>(members.size());
-    for (const auto& member : members) {
-        packet << member.nickname;
-        packet << member.mac_address;
-        packet << member.game_name;
+    {
+        std::lock_guard<std::mutex> lock(member_mutex);
+        for (const auto& member : members) {
+            packet << member.nickname;
+            packet << member.mac_address;
+            packet << member.game_info.name;
+            packet << member.game_info.id;
+        }
     }
 
     ENetPacket* enet_packet =
@@ -335,11 +347,13 @@ void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) {
                                                  ENET_PACKET_FLAG_RELIABLE);
 
     if (destination_address == BroadcastMac) { // Send the data to everyone except the sender
+        std::lock_guard<std::mutex> lock(member_mutex);
         for (const auto& member : members) {
             if (member.peer != event->peer)
                 enet_peer_send(member.peer, 0, enet_packet);
         }
     } else { // Send the data only to the destination client
+        std::lock_guard<std::mutex> lock(member_mutex);
         auto member = std::find_if(members.begin(), members.end(),
                                    [destination_address](const Member& member) -> bool {
                                        return member.mac_address == destination_address;
@@ -361,6 +375,8 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) {
     auto CompareNetworkAddress = [event](const Member member) -> bool {
         return member.peer == event->peer;
     };
+
+    std::lock_guard<std::mutex> lock(member_mutex);
     const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress);
     if (sending_member == members.end()) {
         return; // Received a chat message from a unknown sender
@@ -385,22 +401,32 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {
     in_packet.Append(event->packet->data, event->packet->dataLength);
 
     in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
-    std::string game_name;
-    in_packet >> game_name;
-    auto member =
-        std::find_if(members.begin(), members.end(),
-                     [event](const Member& member) -> bool { return member.peer == event->peer; });
-    if (member != members.end()) {
-        member->game_name = game_name;
-        BroadcastRoomInformation();
+    GameInfo game_info;
+    in_packet >> game_info.name;
+    in_packet >> game_info.id;
+
+    {
+        std::lock_guard<std::mutex> lock(member_mutex);
+        auto member =
+            std::find_if(members.begin(), members.end(), [event](const Member& member) -> bool {
+                return member.peer == event->peer;
+            });
+        if (member != members.end()) {
+            member->game_info = game_info;
+        }
     }
+    BroadcastRoomInformation();
 }
 
 void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) {
     // Remove the client from the members list.
-    members.erase(std::remove_if(members.begin(), members.end(),
-                                 [client](const Member& member) { return member.peer == client; }),
-                  members.end());
+    {
+        std::lock_guard<std::mutex> lock(member_mutex);
+        members.erase(
+            std::remove_if(members.begin(), members.end(),
+                           [client](const Member& member) { return member.peer == client; }),
+            members.end());
+    }
 
     // Announce the change to all clients.
     enet_peer_disconnect(client, 0);
@@ -437,6 +463,19 @@ const RoomInformation& Room::GetRoomInformation() const {
     return room_impl->room_information;
 }
 
+std::vector<Room::Member> Room::GetRoomMemberList() const {
+    std::vector<Room::Member> member_list;
+    std::lock_guard<std::mutex> lock(room_impl->member_mutex);
+    for (const auto& member_impl : room_impl->members) {
+        Member member;
+        member.nickname = member_impl.nickname;
+        member.mac_address = member_impl.mac_address;
+        member.game_info = member_impl.game_info;
+        member_list.push_back(member);
+    }
+    return member_list;
+};
+
 void Room::Destroy() {
     room_impl->state = State::Closed;
     room_impl->room_thread->join();
@@ -447,7 +486,10 @@ void Room::Destroy() {
     }
     room_impl->room_information = {};
     room_impl->server = nullptr;
-    room_impl->members.clear();
+    {
+        std::lock_guard<std::mutex> lock(room_impl->member_mutex);
+        room_impl->members.clear();
+    }
     room_impl->room_information.member_slots = 0;
     room_impl->room_information.name.clear();
 }

+ 18 - 1
src/network/room.h

@@ -7,6 +7,7 @@
 #include <array>
 #include <memory>
 #include <string>
+#include <vector>
 #include "common/common_types.h"
 
 namespace Network {
@@ -21,6 +22,11 @@ struct RoomInformation {
     u32 member_slots; ///< Maximum number of members in this room
 };
 
+struct GameInfo {
+    std::string name{""};
+    u64 id{0};
+};
+
 using MacAddress = std::array<u8, 6>;
 /// A special MAC address that tells the room we're joining to assign us a MAC address
 /// automatically.
@@ -34,7 +40,7 @@ enum RoomMessageTypes : u8 {
     IdJoinRequest = 1,
     IdJoinSuccess,
     IdRoomInformation,
-    IdSetGameName,
+    IdSetGameInfo,
     IdWifiPacket,
     IdChatMessage,
     IdNameCollision,
@@ -51,6 +57,12 @@ public:
         Closed, ///< The room is not opened and can not accept connections.
     };
 
+    struct Member {
+        std::string nickname;   ///< The nickname of the member.
+        GameInfo game_info;     ///< The current game of the member
+        MacAddress mac_address; ///< The assigned mac address of the member.
+    };
+
     Room();
     ~Room();
 
@@ -64,6 +76,11 @@ public:
      */
     const RoomInformation& GetRoomInformation() const;
 
+    /**
+     * Gets a list of the mbmers connected to the room.
+     */
+    std::vector<Member> GetRoomMemberList() const;
+
     /**
      * Creates the socket for this room. Will bind to default address if
      * server is empty string.

+ 118 - 10
src/network/room_member.cpp

@@ -5,6 +5,7 @@
 #include <atomic>
 #include <list>
 #include <mutex>
+#include <set>
 #include <thread>
 #include "common/assert.h"
 #include "enet/enet.h"
@@ -25,6 +26,9 @@ public:
     /// Information about the room we're connected to.
     RoomInformation room_information;
 
+    /// The current game name, id and version
+    GameInfo current_game_info;
+
     std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
     void SetState(const State new_state);
     bool IsConnected() const;
@@ -37,6 +41,24 @@ public:
     std::unique_ptr<std::thread> loop_thread;
     std::mutex send_list_mutex;  ///< Mutex that controls access to the `send_list` variable.
     std::list<Packet> send_list; ///< A list that stores all packets to send the async
+
+    template <typename T>
+    using CallbackSet = std::set<CallbackHandle<T>>;
+    std::mutex callback_mutex; ///< The mutex used for handling callbacks
+
+    class Callbacks {
+    public:
+        template <typename T>
+        CallbackSet<T>& Get();
+
+    private:
+        CallbackSet<WifiPacket> callback_set_wifi_packet;
+        CallbackSet<ChatEntry> callback_set_chat_messages;
+        CallbackSet<RoomInformation> callback_set_room_information;
+        CallbackSet<State> callback_set_state;
+    };
+    Callbacks callbacks; ///< All CallbackSets to all events
+
     void MemberLoop();
 
     void StartLoop();
@@ -84,12 +106,20 @@ public:
      * Disconnects the RoomMember from the Room
      */
     void Disconnect();
+
+    template <typename T>
+    void Invoke(const T& data);
+
+    template <typename T>
+    CallbackHandle<T> Bind(std::function<void(const T&)> callback);
 };
 
 // RoomMemberImpl
 void RoomMember::RoomMemberImpl::SetState(const State new_state) {
-    state = new_state;
-    // TODO(B3N30): Invoke the callback functions
+    if (state != new_state) {
+        state = new_state;
+        Invoke<State>(state);
+    }
 }
 
 bool RoomMember::RoomMemberImpl::IsConnected() const {
@@ -195,9 +225,10 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev
     for (auto& member : member_information) {
         packet >> member.nickname;
         packet >> member.mac_address;
-        packet >> member.game_name;
+        packet >> member.game_info.name;
+        packet >> member.game_info.id;
     }
-    // TODO(B3N30): Invoke callbacks
+    Invoke(room_information);
 }
 
 void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
@@ -209,7 +240,7 @@ void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
 
     // Parse the MAC Address from the packet
     packet >> mac_address;
-    // TODO(B3N30): Invoke callbacks
+    SetState(State::Joined);
 }
 
 void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) {
@@ -235,7 +266,7 @@ void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) {
 
     packet >> wifi_packet.data;
 
-    // TODO(B3N30): Invoke callbacks
+    Invoke<WifiPacket>(wifi_packet);
 }
 
 void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
@@ -248,7 +279,7 @@ void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
     ChatEntry chat_entry{};
     packet >> chat_entry.nickname;
     packet >> chat_entry.message;
-    // TODO(B3N30): Invoke callbacks
+    Invoke<ChatEntry>(chat_entry);
 }
 
 void RoomMember::RoomMemberImpl::Disconnect() {
@@ -276,6 +307,46 @@ void RoomMember::RoomMemberImpl::Disconnect() {
     server = nullptr;
 }
 
+template <>
+RoomMember::RoomMemberImpl::CallbackSet<WifiPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() {
+    return callback_set_wifi_packet;
+}
+
+template <>
+RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>&
+RoomMember::RoomMemberImpl::Callbacks::Get() {
+    return callback_set_state;
+}
+
+template <>
+RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>&
+RoomMember::RoomMemberImpl::Callbacks::Get() {
+    return callback_set_room_information;
+}
+
+template <>
+RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl::Callbacks::Get() {
+    return callback_set_chat_messages;
+}
+
+template <typename T>
+void RoomMember::RoomMemberImpl::Invoke(const T& data) {
+    std::lock_guard<std::mutex> lock(callback_mutex);
+    CallbackSet<T> callback_set = callbacks.Get<T>();
+    for (auto const& callback : callback_set)
+        (*callback)(data);
+}
+
+template <typename T>
+RoomMember::CallbackHandle<T> RoomMember::RoomMemberImpl::Bind(
+    std::function<void(const T&)> callback) {
+    std::lock_guard<std::mutex> lock(callback_mutex);
+    CallbackHandle<T> handle;
+    handle = std::make_shared<std::function<void(const T&)>>(callback);
+    callbacks.Get<T>().insert(handle);
+    return handle;
+}
+
 // RoomMember
 RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} {
     room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0);
@@ -339,6 +410,7 @@ void RoomMember::Join(const std::string& nick, const char* server_addr, u16 serv
         room_member_impl->SetState(State::Joining);
         room_member_impl->StartLoop();
         room_member_impl->SendJoinRequest(nick, preferred_mac);
+        SendGameInfo(room_member_impl->current_game_info);
     } else {
         room_member_impl->SetState(State::CouldNotConnect);
     }
@@ -366,17 +438,53 @@ void RoomMember::SendChatMessage(const std::string& message) {
     room_member_impl->Send(std::move(packet));
 }
 
-void RoomMember::SendGameName(const std::string& game_name) {
+void RoomMember::SendGameInfo(const GameInfo& game_info) {
+    room_member_impl->current_game_info = game_info;
+    if (!IsConnected())
+        return;
+
     Packet packet;
-    packet << static_cast<u8>(IdSetGameName);
-    packet << game_name;
+    packet << static_cast<u8>(IdSetGameInfo);
+    packet << game_info.name;
+    packet << game_info.id;
     room_member_impl->Send(std::move(packet));
 }
 
+RoomMember::CallbackHandle<RoomMember::State> RoomMember::BindOnStateChanged(
+    std::function<void(const RoomMember::State&)> callback) {
+    return room_member_impl->Bind(callback);
+}
+
+RoomMember::CallbackHandle<WifiPacket> RoomMember::BindOnWifiPacketReceived(
+    std::function<void(const WifiPacket&)> callback) {
+    return room_member_impl->Bind(callback);
+}
+
+RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged(
+    std::function<void(const RoomInformation&)> callback) {
+    return room_member_impl->Bind(callback);
+}
+
+RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved(
+    std::function<void(const ChatEntry&)> callback) {
+    return room_member_impl->Bind(callback);
+}
+
+template <typename T>
+void RoomMember::Unbind(CallbackHandle<T> handle) {
+    std::lock_guard<std::mutex> lock(room_member_impl->callback_mutex);
+    room_member_impl->callbacks.Get<T>().erase(handle);
+}
+
 void RoomMember::Leave() {
     room_member_impl->SetState(State::Idle);
     room_member_impl->loop_thread->join();
     room_member_impl->loop_thread.reset();
 }
 
+template void RoomMember::Unbind(CallbackHandle<WifiPacket>);
+template void RoomMember::Unbind(CallbackHandle<RoomMember::State>);
+template void RoomMember::Unbind(CallbackHandle<RoomInformation>);
+template void RoomMember::Unbind(CallbackHandle<ChatEntry>);
+
 } // namespace Network

+ 55 - 4
src/network/room_member.h

@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <functional>
 #include <memory>
 #include <string>
 #include <vector>
@@ -53,12 +54,23 @@ public:
 
     struct MemberInformation {
         std::string nickname;   ///< Nickname of the member.
-        std::string game_name;  ///< Name of the game they're currently playing, or empty if they're
+        GameInfo game_info;     ///< Name of the game they're currently playing, or empty if they're
                                 /// not playing anything.
         MacAddress mac_address; ///< MAC address associated with this member.
     };
     using MemberList = std::vector<MemberInformation>;
 
+    // The handle for the callback functions
+    template <typename T>
+    using CallbackHandle = std::shared_ptr<std::function<void(const T&)>>;
+
+    /**
+     * Unbinds a callback function from the events.
+     * @param handle The connection handle to disconnect
+     */
+    template <typename T>
+    void Unbind(CallbackHandle<T> handle);
+
     RoomMember();
     ~RoomMember();
 
@@ -113,10 +125,49 @@ public:
     void SendChatMessage(const std::string& message);
 
     /**
-     * Sends the current game name  to the room.
-     * @param game_name The game name.
+     * Sends the current game info to the room.
+     * @param game_info The game information.
+     */
+    void SendGameInfo(const GameInfo& game_info);
+
+    /**
+     * Binds a function to an event that will be triggered every time the State of the member
+     * changed. The function wil be called every time the event is triggered. The callback function
+     * must not bind or unbind a function. Doing so will cause a deadlock
+     * @param callback The function to call
+     * @return A handle used for removing the function from the registered list
+     */
+    CallbackHandle<State> BindOnStateChanged(std::function<void(const State&)> callback);
+
+    /**
+     * Binds a function to an event that will be triggered every time a WifiPacket is received.
+     * The function wil be called everytime the event is triggered.
+     * The callback function must not bind or unbind a function. Doing so will cause a deadlock
+     * @param callback The function to call
+     * @return A handle used for removing the function from the registered list
+     */
+    CallbackHandle<WifiPacket> BindOnWifiPacketReceived(
+        std::function<void(const WifiPacket&)> callback);
+
+    /**
+     * Binds a function to an event that will be triggered every time the RoomInformation changes.
+     * The function wil be called every time the event is triggered.
+     * The callback function must not bind or unbind a function. Doing so will cause a deadlock
+     * @param callback The function to call
+     * @return A handle used for removing the function from the registered list
+     */
+    CallbackHandle<RoomInformation> BindOnRoomInformationChanged(
+        std::function<void(const RoomInformation&)> callback);
+
+    /**
+     * Binds a function to an event that will be triggered every time a ChatMessage is received.
+     * The function wil be called every time the event is triggered.
+     * The callback function must not bind or unbind a function. Doing so will cause a deadlock
+     * @param callback The function to call
+     * @return A handle used for removing the function from the registered list
      */
-    void SendGameName(const std::string& game_name);
+    CallbackHandle<ChatEntry> BindOnChatMessageRecieved(
+        std::function<void(const ChatEntry&)> callback);
 
     /**
      * Leaves the current room.