#pragma once #include #ifdef USE_DATABASE #include #include #include #include #include #include #include #include #include class Database { public: using time_point = std::chrono::system_clock::time_point; struct RecordNotFound: public std::exception {}; enum class Paging { first, last }; struct Uuid: Column { static constexpr auto name = "uuid_"; }; struct Owner: UnclearableColumn { static constexpr auto name = "owner_"; }; struct IrcChanName: UnclearableColumn { static constexpr auto name = "ircchanname_"; }; struct Channel: UnclearableColumn { static constexpr auto name = "channel_"; }; struct IrcServerName: UnclearableColumn { static constexpr auto name = "ircservername_"; }; struct Server: UnclearableColumn { static constexpr auto name = "server_"; }; struct Date: Column { static constexpr auto name = "date_"; }; struct Body: Column { static constexpr auto name = "body_"; }; struct Nick: Column { static constexpr auto name = "nick_"; }; struct Pass: Column { static constexpr auto name = "pass_"; }; struct Ports: Column { static constexpr auto name = "ports_"; Ports(): Column("6667") {} }; struct TlsPorts: Column { static constexpr auto name = "tlsports_"; TlsPorts(): Column("6697;6670") {} }; struct Username: Column { static constexpr auto name = "username_"; }; struct Realname: Column { static constexpr auto name = "realname_"; }; struct AfterConnectionCommand: Column { static constexpr auto name = "afterconnectioncommand_"; }; struct TrustedFingerprint: Column { static constexpr auto name = "trustedfingerprint_"; }; struct EncodingOut: Column { static constexpr auto name = "encodingout_"; }; struct EncodingIn: Column { static constexpr auto name = "encodingin_"; }; struct MaxHistoryLength: Column { static constexpr auto name = "maxhistorylength_"; MaxHistoryLength(): Column(20) {} }; struct RecordHistory: Column { static constexpr auto name = "recordhistory_"; RecordHistory(): Column(true) {}}; struct RecordHistoryOptional: Column { static constexpr auto name = "recordhistory_"; }; struct VerifyCert: Column { static constexpr auto name = "verifycert_"; VerifyCert(): Column(true) {} }; struct Persistent: Column { static constexpr auto name = "persistent_"; Persistent(): Column(false) {} }; struct GlobalPersistent: Column { static constexpr auto name = "persistent_"; GlobalPersistent(); }; struct LocalJid: Column { static constexpr auto name = "local"; }; struct RemoteJid: Column { static constexpr auto name = "remote"; }; struct Address: Column { static constexpr auto name = "address_"; }; using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; using GlobalOptionsTable = Table; using GlobalOptions = GlobalOptionsTable::RowType; using IrcServerOptionsTable = Table; using IrcServerOptions = IrcServerOptionsTable::RowType; using IrcChannelOptionsTable = Table; using IrcChannelOptions = IrcChannelOptionsTable::RowType; using RosterTable = Table; using RosterItem = RosterTable::RowType; using AfterConnectionCommandsTable = Table; using AfterConnectionCommands = std::vector; Database() = default; ~Database() = default; Database(const Database&) = delete; Database(Database&&) = delete; Database& operator=(const Database&) = delete; Database& operator=(Database&&) = delete; static GlobalOptions get_global_options(const std::string& owner); static IrcServerOptions get_irc_server_options(const std::string& owner, const std::string& server); static IrcChannelOptions get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel); static IrcChannelOptions get_irc_channel_options_with_server_default(const std::string& owner, const std::string& server, const std::string& channel); static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner, const std::string& server, const std::string& channel); static AfterConnectionCommands get_after_connection_commands(const IrcServerOptions& server_options); static void set_after_connection_commands(const IrcServerOptions& server_options, AfterConnectionCommands& commands); /** * Get all the lines between (optional) start and end dates, with a (optional) limit. * If after_id is set, only the records after it will be returned. */ static std::tuple> get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, std::size_t limit, const std::string& start="", const std::string& end="", const Id::real_type reference_record_id=Id::unset_value, Paging=Paging::first); /** * Get just one single record matching the given uuid, between (optional) end and start. * If it does not exist (or is not between end and start), throw a RecordNotFound exception. */ static MucLogLine get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, const std::string& uuid, const std::string& start="", const std::string& end=""); static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name, time_point date, const std::string& body, const std::string& nick); static void add_roster_item(const std::string& local, const std::string& remote); static bool has_roster_item(const std::string& local, const std::string& remote); static void delete_roster_item(const std::string& local, const std::string& remote); static std::vector get_contact_list(const std::string& local); static std::vector get_full_roster(); static void close(); static void open(const std::string& filename); template static int64_t count(const TableType& table) { CountQuery query{table.get_name()}; return query.execute(*Database::db); } static MucLogLineTable muc_log_lines; static GlobalOptionsTable global_options; static IrcServerOptionsTable irc_server_options; static IrcChannelOptionsTable irc_channel_options; static RosterTable roster; static AfterConnectionCommandsTable after_connection_commands; static std::unique_ptr db; /** * Some caches, to avoid doing very frequent query requests for a few options. */ using CacheKey = std::tuple; static EncodingIn::real_type get_encoding_in(const std::string& owner, const std::string& server, const std::string& channel) { CacheKey channel_key{owner, server, channel}; auto it = Database::encoding_in_cache.find(channel_key); if (it == Database::encoding_in_cache.end()) { auto options = Database::get_irc_channel_options_with_server_default(owner, server, channel); EncodingIn::real_type result = options.col(); if (result.empty()) result = "ISO-8859-1"; it = Database::encoding_in_cache.insert(std::make_pair(channel_key, result)).first; } return it->second; } static void invalidate_encoding_in_cache(const std::string& owner, const std::string& server, const std::string& channel) { CacheKey channel_key{owner, server, channel}; Database::encoding_in_cache.erase(channel_key); } static void invalidate_encoding_in_cache() { Database::encoding_in_cache.clear(); } static auto raw_exec(const std::string& query) { return Database::db->raw_exec(query); } private: static std::string gen_uuid(); static std::map encoding_in_cache; }; class Transaction { public: Transaction(); ~Transaction(); bool success{false}; }; #endif /* USE_DATABASE */