1 #pragma once 2 3 #include <biboumi.h> 4 #ifdef USE_DATABASE 5 6 #include <database/table.hpp> 7 #include <database/column.hpp> 8 #include <database/count_query.hpp> 9 10 #include <database/engine.hpp> 11 12 #include <utils/optional_bool.hpp> 13 14 #include <chrono> 15 #include <string> 16 17 #include <memory> 18 #include <map> 19 20 21 class Database 22 { 23 public: 24 using time_point = std::chrono::system_clock::time_point; 25 struct RecordNotFound: public std::exception {}; 26 enum class Paging { first, last }; 27 28 struct Uuid: Column<std::string> { static constexpr auto name = "uuid_"; }; 29 30 struct Owner: UnclearableColumn<std::string> { static constexpr auto name = "owner_"; }; 31 32 struct IrcChanName: UnclearableColumn<std::string> { static constexpr auto name = "ircchanname_"; }; 33 34 struct Channel: UnclearableColumn<std::string> { static constexpr auto name = "channel_"; }; 35 36 struct IrcServerName: UnclearableColumn<std::string> { static constexpr auto name = "ircservername_"; }; 37 38 struct Server: UnclearableColumn<std::string> { static constexpr auto name = "server_"; }; 39 40 struct Date: Column<time_point::rep> { static constexpr auto name = "date_"; }; 41 42 struct Body: Column<std::string> { static constexpr auto name = "body_"; }; 43 44 struct Nick: Column<std::string> { static constexpr auto name = "nick_"; }; 45 46 struct SaslPassword: Column<std::string> { static constexpr auto name = "saslpassword_"; }; 47 48 struct Pass: Column<std::string> { static constexpr auto name = "pass_"; }; 49 50 struct Ports: Column<std::string> { static constexpr auto name = "ports_"; PortsDatabase::Ports51 Ports(): Column<std::string>("6667") {} }; 52 53 struct TlsPorts: Column<std::string> { static constexpr auto name = "tlsports_"; TlsPortsDatabase::TlsPorts54 TlsPorts(): Column<std::string>("6697;6670") {} }; 55 56 struct Username: Column<std::string> { static constexpr auto name = "username_"; }; 57 58 struct Realname: Column<std::string> { static constexpr auto name = "realname_"; }; 59 60 struct AfterConnectionCommand: Column<std::string> { static constexpr auto name = "afterconnectioncommand_"; }; 61 62 struct TrustedFingerprint: Column<std::string> { static constexpr auto name = "trustedfingerprint_"; }; 63 64 struct EncodingOut: Column<std::string> { static constexpr auto name = "encodingout_"; }; 65 66 struct EncodingIn: Column<std::string> { static constexpr auto name = "encodingin_"; }; 67 68 struct MaxHistoryLength: Column<std::int64_t> { static constexpr auto name = "maxhistorylength_"; MaxHistoryLengthDatabase::MaxHistoryLength69 MaxHistoryLength(): Column<std::int64_t>(20) {} }; 70 71 struct RecordHistory: Column<bool> { static constexpr auto name = "recordhistory_"; RecordHistoryDatabase::RecordHistory72 RecordHistory(): Column<bool>(true) {}}; 73 74 struct RecordHistoryOptional: Column<OptionalBool> { static constexpr auto name = "recordhistory_"; }; 75 76 struct VerifyCert: Column<bool> { static constexpr auto name = "verifycert_"; VerifyCertDatabase::VerifyCert77 VerifyCert(): Column<bool>(true) {} }; 78 79 struct Persistent: Column<bool> { static constexpr auto name = "persistent_"; PersistentDatabase::Persistent80 Persistent(): Column<bool>(false) {} }; 81 82 struct GlobalPersistent: Column<bool> { static constexpr auto name = "persistent_"; 83 GlobalPersistent(); }; 84 85 struct LocalJid: Column<std::string> { static constexpr auto name = "local"; }; 86 87 struct RemoteJid: Column<std::string> { static constexpr auto name = "remote"; }; 88 89 struct Address: Column<std::string> { static constexpr auto name = "address_"; }; 90 91 struct ThrottleLimit: Column<std::int64_t> { static constexpr auto name = "throttlelimit_"; ThrottleLimitDatabase::ThrottleLimit92 ThrottleLimit(): Column<std::int64_t>(10) {} }; 93 94 using MucLogLineTable = Table<Id, Uuid, Owner, IrcChanName, IrcServerName, Date, Body, Nick>; 95 using MucLogLine = MucLogLineTable::RowType; 96 97 using GlobalOptionsTable = Table<Id, Owner, MaxHistoryLength, RecordHistory, GlobalPersistent>; 98 using GlobalOptions = GlobalOptionsTable::RowType; 99 100 using IrcServerOptionsTable = Table<Id, Owner, Server, Pass, TlsPorts, Ports, Username, Realname, VerifyCert, TrustedFingerprint, EncodingOut, EncodingIn, MaxHistoryLength, Address, Nick, SaslPassword, ThrottleLimit>; 101 using IrcServerOptions = IrcServerOptionsTable::RowType; 102 103 using IrcChannelOptionsTable = Table<Id, Owner, Server, Channel, EncodingOut, EncodingIn, MaxHistoryLength, Persistent, RecordHistoryOptional>; 104 using IrcChannelOptions = IrcChannelOptionsTable::RowType; 105 106 using RosterTable = Table<LocalJid, RemoteJid>; 107 using RosterItem = RosterTable::RowType; 108 109 using AfterConnectionCommandsTable = Table<Id, ForeignKey, AfterConnectionCommand>; 110 using AfterConnectionCommands = std::vector<AfterConnectionCommandsTable::RowType>; 111 112 Database() = default; 113 ~Database() = default; 114 115 Database(const Database&) = delete; 116 Database(Database&&) = delete; 117 Database& operator=(const Database&) = delete; 118 Database& operator=(Database&&) = delete; 119 120 static GlobalOptions get_global_options(const std::string& owner); 121 static IrcServerOptions get_irc_server_options(const std::string& owner, 122 const std::string& server); 123 static IrcChannelOptions get_irc_channel_options(const std::string& owner, 124 const std::string& server, 125 const std::string& channel); 126 static IrcChannelOptions get_irc_channel_options_with_server_default(const std::string& owner, 127 const std::string& server, 128 const std::string& channel); 129 static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner, 130 const std::string& server, 131 const std::string& channel); 132 static AfterConnectionCommands get_after_connection_commands(const IrcServerOptions& server_options); 133 static void set_after_connection_commands(const IrcServerOptions& server_options, AfterConnectionCommands& commands); 134 135 /** 136 * Get all the lines between (optional) start and end dates, with a (optional) limit. 137 * If after_id is set, only the records after it will be returned. 138 */ 139 static std::tuple<bool, std::vector<MucLogLine>> get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, 140 std::size_t limit, const std::string& start="", const std::string& end="", 141 const Id::real_type reference_record_id=Id::unset_value, Paging=Paging::first); 142 143 /** 144 * Get just one single record matching the given uuid, between (optional) end and start. 145 * If it does not exist (or is not between end and start), throw a RecordNotFound exception. 146 */ 147 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=""); 148 static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name, 149 time_point date, const std::string& body, const std::string& nick); 150 151 static void add_roster_item(const std::string& local, const std::string& remote); 152 static bool has_roster_item(const std::string& local, const std::string& remote); 153 static void delete_roster_item(const std::string& local, const std::string& remote); 154 static std::vector<Database::RosterItem> get_contact_list(const std::string& local); 155 static std::vector<Database::RosterItem> get_full_roster(); 156 157 static void close(); 158 static void open(const std::string& filename); 159 160 template <typename TableType> count(const TableType & table)161 static int64_t count(const TableType& table) 162 { 163 CountQuery query{table.get_name()}; 164 return query.execute(*Database::db); 165 } 166 167 static MucLogLineTable muc_log_lines; 168 static GlobalOptionsTable global_options; 169 static IrcServerOptionsTable irc_server_options; 170 static IrcChannelOptionsTable irc_channel_options; 171 static RosterTable roster; 172 static AfterConnectionCommandsTable after_connection_commands; 173 174 static std::unique_ptr<DatabaseEngine> db; 175 176 /** 177 * Some caches, to avoid doing very frequent query requests for a few options. 178 */ 179 using CacheKey = std::tuple<std::string, std::string, std::string>; 180 get_encoding_in(const std::string & owner,const std::string & server,const std::string & channel)181 static EncodingIn::real_type get_encoding_in(const std::string& owner, 182 const std::string& server, 183 const std::string& channel) 184 { 185 CacheKey channel_key{owner, server, channel}; 186 auto it = Database::encoding_in_cache.find(channel_key); 187 if (it == Database::encoding_in_cache.end()) 188 { 189 auto options = Database::get_irc_channel_options_with_server_default(owner, server, channel); 190 EncodingIn::real_type result = options.col<Database::EncodingIn>(); 191 if (result.empty()) 192 result = "ISO-8859-1"; 193 it = Database::encoding_in_cache.insert(std::make_pair(channel_key, result)).first; 194 } 195 return it->second; 196 } invalidate_encoding_in_cache(const std::string & owner,const std::string & server,const std::string & channel)197 static void invalidate_encoding_in_cache(const std::string& owner, 198 const std::string& server, 199 const std::string& channel) 200 { 201 CacheKey channel_key{owner, server, channel}; 202 Database::encoding_in_cache.erase(channel_key); 203 } invalidate_encoding_in_cache()204 static void invalidate_encoding_in_cache() 205 { 206 Database::encoding_in_cache.clear(); 207 } 208 raw_exec(const std::string & query)209 static auto raw_exec(const std::string& query) 210 { 211 return Database::db->raw_exec(query); 212 } 213 214 private: 215 static std::string gen_uuid(); 216 static std::map<CacheKey, EncodingIn::real_type> encoding_in_cache; 217 }; 218 219 class Transaction 220 { 221 public: 222 Transaction(); 223 ~Transaction(); 224 bool success{false}; 225 }; 226 227 #endif /* USE_DATABASE */ 228