Files
DarkflameServer/dDashboardServer/routes/BackupFiles.h
Aaron Kimbrell 8993360f66 fix(dashboard): MySQL backups with a tcp://, unix:// or pipe:// mysql_host
mysqldump was given --host=tcp --port=//host:port for the tcp:// form the servers accept, so
backups failed. Read mysql_host the way the servers connect with it: tcp://host:port (a trailing
/database is dropped), unix:// as --socket and pipe:// as a named pipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:47 -05:00

81 lines
3.1 KiB
C++

#pragma once
#include <cstdint>
#include <ctime>
#include <filesystem>
#include <functional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "json.hpp"
/**
* The parts of database backups that do not need the dashboard: file names, which old backups to delete, the
* mysqldump command line, and checking that a backup file can be restored. Kept separate so they can be unit tested.
*/
namespace BackupFiles {
// dlu-YYYYMMDD-HHMMSS.sqlite (SQLite, VACUUM INTO) or .sql (MySQL, mysqldump), UTC
std::string Name(std::time_t when, bool mysql);
// Only files named like Name() are listed, downloaded, deleted or verified
bool IsName(std::string_view name);
// Backups are written under this name and renamed when complete, so a half-written file is never listed or kept
std::string PartialName(const std::string& name);
bool IsPartialName(std::string_view name);
/**
* Which backups to delete so only the newest `keep` remain (0 keeps all). Names that are not backups are ignored.
* @return the names to delete, oldest last
*/
std::vector<std::string> Expired(std::vector<std::string> names, int64_t keep);
// A SQL string literal: 'it''s'
std::string SqlString(std::string_view value);
// A [client] option file with the login, so the password is never on the command line
std::string MysqlOptionFile(std::string_view user, std::string_view password);
struct DumpCommand {
std::string program;
std::string optionsFile;
std::string host; // mysql_host: host, host:port, tcp://host:port, unix://socket or pipe://name
std::string database;
std::string target;
std::string errorFile; // mysqldump's messages; never mixed into the dump, where they would break a restore
};
// mysqldump as an argument vector for Process::Run (no shell); its messages go to errorFile through --log-error
std::vector<std::string> MysqldumpArguments(const DumpCommand& command);
struct Verification {
bool ok{};
std::string summary;
std::string format; // "sqlite" or "mysqldump"
std::string integrity; // SQLite: PRAGMA integrity_check's first lines ("ok")
std::vector<std::pair<std::string, int64_t>> tables; // name, rows (SQLite) or INSERT statements (dump)
int64_t rows{};
int64_t migrations{};
std::string lastMigration;
// Accounts with two-factor login on, and how many of their secrets the current key could not decrypt
int64_t twoFactorAccounts{};
int64_t twoFactorUnreadable{};
bool twoFactorChecked{};
nlohmann::json ToJson() const;
};
using CanDecrypt = std::function<bool(const std::string& storedSecret)>;
/**
* Open a SQLite backup read-only and check it: PRAGMA integrity_check, every table's row count, migration_history,
* and (with canDecrypt) whether each two-factor secret in it can be decrypted with the current key.
*/
Verification VerifySqlite(const std::filesystem::path& file, const CanDecrypt& canDecrypt = {});
/**
* Check a mysqldump file is complete: starts with a dump header, ends with "-- Dump completed", and has
* the tables the servers need (accounts, charinfo, migration_history).
*/
Verification VerifyDump(const std::filesystem::path& file);
}