mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
- resources/*.ini list the 73 settings the catalog knew but the files left out (dashboard AI helper, backups, metrics, public status, strikes, property rent and reputation, chat log, contraband, logins...), with their title, description and default. The test ShippedFilesListEveryCatalogSetting keeps it that way; with DLU_WRITE_INI_TEMPLATES=1 it writes the missing ones. - ConfigSync forgets a setting row when its key has left a file the server read: from the file, no value set on the dashboard, not a permission level. Before, rows of removed keys stayed forever. - Docs: where setting rows come from and when they go, the templates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
4.1 KiB
C++
92 lines
4.1 KiB
C++
#include "ConfigSync.h"
|
|
|
|
#include "Database.h"
|
|
#include "Logger.h"
|
|
#include "dConfig.h"
|
|
#include "Permissions.h"
|
|
|
|
namespace ConfigSync {
|
|
namespace {
|
|
/**
|
|
* The dashboard reports every permission level its own file or environment sets, so the other servers can use
|
|
* them: environment variables for keys that aren't in the file too, and a key taken out of the file (or the
|
|
* environment) is cleared rather than left at its old value.
|
|
*/
|
|
void ReportPermissionLevels(dConfig& config) {
|
|
std::set<std::string> inFile;
|
|
for (const auto& entry : config.GetFileEntries()) {
|
|
if (entry.file == config.GetFileName()) inFile.insert(entry.key);
|
|
}
|
|
std::map<std::string, IServerConfig::Setting> stored;
|
|
for (auto& row : Database::Get()->GetServerConfig({ config.GetFileName() })) {
|
|
if (Permissions::IsPermissionSetting(row.name)) stored[row.name] = std::move(row);
|
|
}
|
|
for (const auto& permission : Permissions::All()) {
|
|
const auto name = Permissions::ConfigName(permission.key);
|
|
if (inFile.contains(name)) continue; // reported with the file's entries
|
|
const auto env = dConfig::GetEnvironmentValue(name);
|
|
const auto it = stored.find(name);
|
|
const bool reported = it != stored.end() && !it->second.fileSource.empty();
|
|
if (!env && !reported) continue;
|
|
if (env && reported && it->second.fileSource == "env" && it->second.fileValue == env) continue;
|
|
IServerConfig::Setting setting;
|
|
setting.file = config.GetFileName();
|
|
setting.name = name;
|
|
setting.fileSource = env ? "env" : "";
|
|
if (env) setting.fileValue = *env;
|
|
Database::Get()->ReportConfigFromFile(setting);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Sync(dConfig& config) {
|
|
try {
|
|
std::set<std::string> setLocally;
|
|
for (const auto& entry : config.GetFileEntries()) {
|
|
if (dConfig::IsFileOnlyKey(entry.key)) continue;
|
|
const auto env = dConfig::GetEnvironmentValue(entry.key);
|
|
const bool secret = dConfig::IsSecretKey(entry.key);
|
|
setLocally.insert(entry.key);
|
|
IServerConfig::Setting setting;
|
|
setting.file = entry.file;
|
|
setting.name = entry.key;
|
|
setting.fileSource = env ? "env" : "file";
|
|
// Secrets stay where they were put; the dashboard only learns that they are set
|
|
if (!secret) setting.fileValue = env ? *env : entry.value;
|
|
setting.secret = secret;
|
|
setting.description = entry.description;
|
|
Database::Get()->ReportConfigFromFile(setting);
|
|
}
|
|
|
|
// A key taken out of a file this server read is forgotten: its row came from that file (not the environment,
|
|
// not only the dashboard) and nobody set it on the dashboard
|
|
std::set<std::string> filesRead;
|
|
for (const auto& entry : config.GetFileEntries()) filesRead.insert(entry.file);
|
|
for (const auto& row : Database::Get()->GetServerConfig({ filesRead.begin(), filesRead.end() })) {
|
|
if (row.fileSource != "file" || row.webValue || setLocally.contains(row.name) || Permissions::IsPermissionSetting(row.name)) continue;
|
|
LOG("Forgetting the setting %s of %s: it is no longer in the file", row.name.c_str(), row.file.c_str());
|
|
Database::Get()->DeleteServerConfig(row.file, row.name);
|
|
}
|
|
|
|
const auto rows = Database::Get()->GetServerConfig({ config.GetFileName(), "sharedconfig.ini" });
|
|
// Keys set only by environment variables count as set locally too
|
|
for (const auto& row : rows) {
|
|
if (!setLocally.contains(row.name) && dConfig::GetEnvironmentValue(row.name)) setLocally.insert(row.name);
|
|
}
|
|
auto resolved = Resolve(rows, config.GetFileName(), setLocally);
|
|
|
|
// Permission levels belong to the dashboard; every other server uses the values it stored
|
|
const std::string permissionFile(Permissions::CONFIG_FILE);
|
|
if (config.GetFileName() == permissionFile) {
|
|
ReportPermissionLevels(config);
|
|
} else {
|
|
AddOwnedValues(resolved, Database::Get()->GetServerConfig({ permissionFile }), permissionFile, Permissions::PREFIX);
|
|
}
|
|
config.SetDatabaseValues(std::move(resolved.overrides), std::move(resolved.fallbacks));
|
|
} catch (const std::exception& ex) {
|
|
// Before the migration has run there is no table yet; the files alone are used
|
|
LOG_DEBUG("Settings from the database are not available: %s", ex.what());
|
|
}
|
|
}
|
|
}
|