#pragma once #include "utils.hpp" #include "types.hpp" #include "StringView.hpp" #include "User.hpp" #include #include #include #include #include #include namespace dchat { struct RoomMessage { odhtdb::Hash id; std::shared_ptr creator; uint32_t timestampSeconds; std::string text; }; class Rooms; class Room { DISABLE_COPY(Room) friend class Rooms; public: Room(Rooms *rooms, std::shared_ptr id); // Throws exception on failure if we are not allowed to add the user to the group void addUser(const odhtdb::Signature::PublicKey &userPublicKey, std::shared_ptr group); // Returns null if user doesn't exist in room std::shared_ptr getUserByPublicKey(const odhtdb::Signature::PublicKey &userPublicKey); // Returns null if group doesn't exist in room std::shared_ptr getGroupById(const odhtdb::DataView groupId); void setAvatarUrl(const std::string &url); void setUserNickname(const std::string &nickname); bool setName(const std::string &name); void publishMessage(const std::string &msg); const odhtdb::Signature::MapPublicKey>& getUsers() const { return userByPublicKey; } const std::vector>& getMessages() const { return messages; } Rooms *rooms; std::shared_ptr id; std::shared_ptr encryptionKey; std::string name; std::shared_ptr localUser; std::string inviteKey; void *userdata; // TODO: Move to private when we have proper support for groups std::vector> groups; private: // Returns null if the user already exists in the room std::shared_ptr addUserLocally(const odhtdb::Signature::PublicKey &userPublicKey, std::shared_ptr group); // Returns null if the group already exists in the room std::shared_ptr addGroupLocally(const odhtdb::DataView groupId); void setLocalUser(std::shared_ptr user, std::shared_ptr keyPair); private: odhtdb::Signature::MapPublicKey> userByPublicKey; // Used for local users odhtdb::Signature::MapPublicKey> publicKeyToKeyPairMap; std::vector> messages; }; struct RoomAddMessageRequest { std::shared_ptr room; bool loadedFromCache; std::shared_ptr message; std::shared_ptr prevMessage; }; struct UserChangeNicknameRequest { std::shared_ptr room; std::shared_ptr user; uint32_t timestampSeconds; bool loadedFromCache; std::string newNickname; }; struct UserChangeAvatarRequest { std::shared_ptr room; std::shared_ptr user; uint32_t timestampSeconds; bool loadedFromCache; std::string url; }; struct RoomChangeNameRequest { std::shared_ptr room; std::shared_ptr user; uint32_t timestampSeconds; bool loadedFromCache; std::string newName; }; struct InviteUserRequest { Room *room; odhtdb::Signature::PublicKey userPublicKey; std::string message; }; struct RoomAddUserRequest { std::shared_ptr room; std::shared_ptr user; std::shared_ptr addedByUser; uint32_t timestampSeconds; bool loadedFromCache; bool isLocalUser; bool waitedToJoin; }; // if connection failed then @rooms is null and errMsg contains the error using ConnectBoostrapNodeCallbackFunc = std::function rooms, const char *errMsg)>; using CreateRoomCallbackFunc = std::function room)>; using RoomAddUserCallbackFunc = std::function; using RoomAddMessageCallbackFunc = std::function; using UserChangeNicknameCallbackFunc = std::function; using UserChangeAvatarCallbackFunc = std::function; using ChangeRoomNameCallbackFunc = std::function; using ReceiveInviteUserCallbackFunc = std::function; struct RoomCallbackFuncs { ConnectBoostrapNodeCallbackFunc connectCallbackFunc; CreateRoomCallbackFunc createRoomCallbackFunc; RoomAddUserCallbackFunc addUserCallbackFunc; RoomAddMessageCallbackFunc addMessageCallbackFunc; UserChangeNicknameCallbackFunc userChangeNicknameCallbackFunc; UserChangeAvatarCallbackFunc userChangeAvatarCallbackFunc; ChangeRoomNameCallbackFunc changeRoomNameCallbackFunc; ReceiveInviteUserCallbackFunc receiveInviteUserCallbackFunc; }; class Rooms { friend Room; DISABLE_COPY(Rooms) public: // @callbackFuncs.connectCallbackFunc can't be null. // @address is used in another thread so it may need to live beyond the scope which Rooms::connect is called from static void connect(const char *address, u16 port, RoomCallbackFuncs callbackFuncs); // Throws on failure void loginUser(const std::string &username, const std::string &password); // Throws on failure void registerUser(const std::string &username, const std::string &password); // Throws on failure std::shared_ptr createRoom(const std::string &name); // Throws on failure, returns true on success, returns false on expected failures (such as already being a member of the room) bool requestJoinRoom(const std::string &inviteKey, const std::string &message); std::shared_ptr database; const odhtdb::MapHash>& getRooms() const { return roomById; } bool isLoggedIn() const { return loggedIn; } private: Rooms(const char *address, u16 port, RoomCallbackFuncs callbackFuncs); void createNodeCallbackFunc(const odhtdb::DatabaseCreateNodeRequest &request); void addNodeCallbackFunc(const odhtdb::DatabaseAddNodeRequest &request); void addUserCallbackFunc(const odhtdb::DatabaseAddUserRequest &request); private: odhtdb::MapHash> roomById; RoomCallbackFuncs callbackFuncs; bool loggedIn; odhtdb::MapHash> roomLocalUser; odhtdb::MapHash> roomEncryptionKey; std::string currentUsername; std::string currentUserPassword; std::recursive_mutex roomModifyMutex; odhtdb::MapHash> waitingToJoinRoom; std::recursive_mutex waitingToJoinRoomMutex; }; }