VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
OpenConnection.cpp
Go to the documentation of this file.
2
4#include <algorithm>
5#include <filesystem>
6#include <format>
7#include <optional>
8#include <string>
9#include <string_view>
10#include <variant>
11
12namespace VoltMod
13{
14
15using PostgresSslMode = sqlpp::postgresql::connection_config::sslmode_t;
16
18{
19 std::string_view Name;
21};
22
23static constexpr SslModeName SslModes[] = {
24 {"disable", PostgresSslMode::disable}, {"allow", PostgresSslMode::allow},
25 {"prefer", PostgresSslMode::prefer}, {"require", PostgresSslMode::require},
26 {"verify-ca", PostgresSslMode::verify_ca}, {"verify-full", PostgresSslMode::verify_full},
27};
28
29/** The modes MariaDB, which takes a bool, reads as "the connection must use TLS". */
30static constexpr PostgresSslMode TlsModes[] = {PostgresSslMode::require, PostgresSslMode::verify_ca,
31 PostgresSslMode::verify_full};
32
33static constexpr std::string_view InMemory = ":memory:";
34
35static std::optional<PostgresSslMode> ParseSslMode(std::string_view name)
36{
37 const auto found = std::ranges::find(SslModes, name, &SslModeName::Name);
38 return found != std::ranges::end(SslModes) ? std::optional(found->Mode) : std::nullopt;
39}
40
41static sqlpp::postgresql::connection_config PostgresSettings(const DatabaseConfig& config)
42{
43 sqlpp::postgresql::connection_config settings;
44 settings.host = config.host;
45 settings.port = config.port > 0 ? static_cast<uint32_t>(config.port) : 5432u;
46 settings.dbname = config.database;
47 settings.user = config.username;
48 settings.password = config.password;
49 settings.connect_timeout = static_cast<uint32_t>(config.connectTimeoutSec);
50 settings.sslmode = ParseSslMode(config.sslMode).value_or(PostgresSslMode::prefer);
51 return settings;
52}
53
54static sqlpp::mysql::connection_config MariaDbSettings(const DatabaseConfig& config)
55{
56 sqlpp::mysql::connection_config settings;
57 settings.host = config.host;
58 settings.port = config.port > 0 ? static_cast<unsigned int>(config.port) : 3306u;
59 settings.database = config.database;
60 settings.user = config.username;
61 settings.password = config.password;
62 settings.connect_timeout_seconds = static_cast<unsigned int>(config.connectTimeoutSec);
63 settings.charset = "utf8mb4";
64 settings.ssl = std::ranges::contains(TlsModes, ParseSslMode(config.sslMode).value_or(PostgresSslMode::prefer));
65 // Affected rows must mean matched rows, which update-then-insert reads to decide on the insert.
66 settings.client_flag |= CLIENT_FOUND_ROWS;
67 return settings;
68}
69
70static sqlpp::sqlite3::connection_config SqliteSettings(const DatabaseConfig& config)
71{
72 sqlpp::sqlite3::connection_config settings;
74 if (config.path == InMemory)
75 {
76 settings.path_to_database = config.path;
77 return settings;
78 }
79
80 // Relative paths must resolve against the game dir, not the server process cwd.
81 const std::filesystem::path file = ResolvePath(config.path);
82 std::error_code ec;
83 std::filesystem::create_directories(file.parent_path(), ec);
84 settings.path_to_database = file.string();
85 return settings;
86}
87
89{
90 const std::optional<Driver> driver = ParseDriver(config.driver);
91 if (!driver)
92 {
93 return std::unexpected(Error::Invalid(
94 std::format("Unknown database driver '{}'; expected postgres, mariadb or sqlite.", config.driver)));
95 }
96 if (*driver == Driver::Sqlite && config.path.empty())
97 {
98 return std::unexpected(Error::Invalid("Database driver 'sqlite' needs a 'path' (a file, or \":memory:\")."));
99 }
100 if (*driver == Driver::Postgres && !ParseSslMode(config.sslMode))
101 {
102 return std::unexpected(Error::Invalid(std::format(
103 "Unknown sslMode '{}'; expected disable, allow, prefer, require, verify-ca or verify-full.", config.sslMode)));
104 }
105 return *driver;
106}
107
109{
110 return std::visit(
111 [](const auto& conn) {
112 if constexpr (std::same_as<std::remove_cvref_t<decltype(conn)>, std::monostate>)
113 {
114 return false;
115 }
116 else
117 {
118 return conn.is_connected();
119 }
120 },
121 connection);
122}
123
125{
126 switch (driver)
127 {
128 case Driver::Postgres:
130 return;
131 case Driver::MariaDb:
132 sqlpp::mysql::global_library_init();
134 return;
135 case Driver::Sqlite:
136 {
138 if (config.path != InMemory)
139 {
140 conn("PRAGMA journal_mode=WAL");
141 }
142 conn("PRAGMA busy_timeout=" + std::to_string(config.connectTimeoutSec * 1000));
143 return;
144 }
145 }
146}
147
148} // namespace VoltMod
static sqlpp::mysql::connection_config MariaDbSettings(const DatabaseConfig &config)
std::optional< Driver > ParseDriver(std::string_view name)
Definition Driver.hpp:21
bool IsOpen(const AnyConnection &connection)
static constexpr SslModeName SslModes[]
std::filesystem::path ResolvePath(std::string_view relativePath)
a relative path against the base directory. If the path is already absolute, returns it as-is.
Definition Paths.cpp:14
sqlpp::postgresql::connection_config::sslmode_t PostgresSslMode
static std::optional< PostgresSslMode > ParseSslMode(std::string_view name)
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
static constexpr PostgresSslMode TlsModes[]
static sqlpp::sqlite3::connection_config SqliteSettings(const DatabaseConfig &config)
sqlpp::postgresql::connection PostgresConnection
static constexpr std::string_view InMemory
sqlpp::sqlite3::connection SqliteConnection
Result< Driver > CheckConfig(const DatabaseConfig &config)
std::expected< T, Error > Result
Definition Result.hpp:64
static sqlpp::postgresql::connection_config PostgresSettings(const DatabaseConfig &config)
std::variant< std::monostate, PostgresConnection, MariaDbConnection, SqliteConnection > AnyConnection
void OpenConnection(AnyConnection &connection, Driver driver, const DatabaseConfig &config)
sqlpp::mysql::connection MariaDbConnection
Connection parameters for every supported backend.
static Error Invalid(std::string detail)
Definition Result.hpp:51
std::string_view Name