refactor: structured config with validation (ServerConfig class)
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <picout.h>
|
||||
#include <pifile.h>
|
||||
#include <pijson.h>
|
||||
|
||||
static const int DefaultPort = 8000;
|
||||
static const PIString DefaultPipelinesDir = "./storage/pipelines/";
|
||||
static const PIString DefaultLogsDir = "./storage/logs/";
|
||||
|
||||
ServerConfig::ServerConfig()
|
||||
: port_(DefaultPort)
|
||||
, pipelines_dir_(DefaultPipelinesDir)
|
||||
, logs_dir_(DefaultLogsDir)
|
||||
, web_root_()
|
||||
, valid_(true) {}
|
||||
|
||||
bool ServerConfig::loadFromFile(const PIString & path) {
|
||||
if (!PIFile::isExists(path)) {
|
||||
piCout << "Config file not found: " << path << ", using defaults";
|
||||
valid_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
PIByteArray data = PIFile::readAll(path);
|
||||
PIJSON config = PIJSON::fromJSON(PIString::fromUTF8(data));
|
||||
|
||||
if (!config.isObject()) {
|
||||
piCout << "Invalid config file: not a JSON object";
|
||||
valid_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
piCout << "Loaded config from: " << path;
|
||||
|
||||
if (config.contains("port")) {
|
||||
port_ = config["port"].toInt();
|
||||
}
|
||||
if (config.contains("pipelines_dir")) {
|
||||
pipelines_dir_ = config["pipelines_dir"].toString();
|
||||
}
|
||||
if (config.contains("logs_dir")) {
|
||||
logs_dir_ = config["logs_dir"].toString();
|
||||
}
|
||||
if (config.contains("web_root")) {
|
||||
web_root_ = config["web_root"].toString();
|
||||
}
|
||||
|
||||
// Normalize directory paths
|
||||
pipelines_dir_ = normalizeDir(pipelines_dir_);
|
||||
logs_dir_ = normalizeDir(logs_dir_);
|
||||
web_root_ = normalizeDir(web_root_);
|
||||
|
||||
// Validate
|
||||
valid_ = true;
|
||||
|
||||
if (port_ < 1024 || port_ > 65535) {
|
||||
piCout << "Invalid port: " << port_ << " (must be 1024-65535)";
|
||||
valid_ = false;
|
||||
}
|
||||
|
||||
if (pipelines_dir_.isEmpty()) {
|
||||
piCout << "Invalid config: pipelines_dir must not be empty";
|
||||
valid_ = false;
|
||||
}
|
||||
|
||||
if (logs_dir_.isEmpty()) {
|
||||
piCout << "Invalid config: logs_dir must not be empty";
|
||||
valid_ = false;
|
||||
}
|
||||
|
||||
return valid_;
|
||||
}
|
||||
|
||||
int ServerConfig::port() const {
|
||||
return port_;
|
||||
}
|
||||
|
||||
PIString ServerConfig::pipelinesDir() const {
|
||||
return pipelines_dir_;
|
||||
}
|
||||
|
||||
PIString ServerConfig::logsDir() const {
|
||||
return logs_dir_;
|
||||
}
|
||||
|
||||
PIString ServerConfig::webRoot() const {
|
||||
return web_root_;
|
||||
}
|
||||
|
||||
bool ServerConfig::isValid() const {
|
||||
return valid_;
|
||||
}
|
||||
|
||||
PIString ServerConfig::normalizeDir(const PIString & dir) {
|
||||
if (dir.isEmpty()) {
|
||||
return dir;
|
||||
}
|
||||
if (!dir.endsWith('/')) {
|
||||
return dir + '/';
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <pistring.h>
|
||||
|
||||
class ServerConfig {
|
||||
public:
|
||||
ServerConfig();
|
||||
|
||||
bool loadFromFile(const PIString & path);
|
||||
|
||||
int port() const;
|
||||
PIString pipelinesDir() const;
|
||||
PIString logsDir() const;
|
||||
PIString webRoot() const;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
static PIString normalizeDir(const PIString & dir);
|
||||
|
||||
int port_;
|
||||
PIString pipelines_dir_;
|
||||
PIString logs_dir_;
|
||||
PIString web_root_;
|
||||
bool valid_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,52 +1,32 @@
|
||||
#include "config.h"
|
||||
#include "server.h"
|
||||
|
||||
#include <picout.h>
|
||||
#include <pifile.h>
|
||||
#include <pijson.h>
|
||||
#include <pikbdlistener.h>
|
||||
#include <pisignals.h>
|
||||
|
||||
static PIString getConfigValue(const PIJSON & config, const PIString & key, const PIString & def = PIString()) {
|
||||
if (config.contains(key)) {
|
||||
return config[key].toString();
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
static int getConfigInt(const PIJSON & config, const PIString & key, int def) {
|
||||
if (config.contains(key)) {
|
||||
return config[key].toInt();
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
// Load config file
|
||||
PIString configPath = "./pipeline-runner.conf";
|
||||
PIJSON config;
|
||||
|
||||
if (argc > 1) {
|
||||
configPath = PIString(argv[1]);
|
||||
}
|
||||
|
||||
if (PIFile::isExists(configPath)) {
|
||||
PIByteArray data = PIFile::readAll(configPath);
|
||||
config = PIJSON::fromJSON(PIString::fromUTF8(data));
|
||||
piCout << "Loaded config from: " << configPath;
|
||||
} else {
|
||||
piCout << "Config file not found: " << configPath << ", using defaults";
|
||||
ServerConfig config;
|
||||
if (!config.loadFromFile(configPath)) {
|
||||
piCout << "Failed to load config, exiting";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Parse config
|
||||
int port = getConfigInt(config, "port", 8000);
|
||||
PIString pipelinesDir = getConfigValue(config, "pipelines_dir", "./storage/pipelines/");
|
||||
PIString logsDir = getConfigValue(config, "logs_dir", "./storage/logs/");
|
||||
PIString webRoot = getConfigValue(config, "web_root", "");
|
||||
if (!config.isValid()) {
|
||||
piCout << "Config validation failed, exiting";
|
||||
return 1;
|
||||
}
|
||||
|
||||
piCout << "Port: " << port;
|
||||
piCout << "Pipelines dir: " << pipelinesDir;
|
||||
piCout << "Logs dir: " << logsDir;
|
||||
piCout << "Web root: " << (webRoot.isEmpty() ? "(not set)" : webRoot);
|
||||
piCout << "Port: " << config.port();
|
||||
piCout << "Pipelines dir: " << config.pipelinesDir();
|
||||
piCout << "Logs dir: " << config.logsDir();
|
||||
piCout << "Web root: " << (config.webRoot().isEmpty() ? "(not set)" : config.webRoot());
|
||||
|
||||
// Handle signals
|
||||
PISignals::setSlot([](PISignals::Signal s) {
|
||||
@@ -57,7 +37,7 @@ int main(int argc, char * argv[]) {
|
||||
PISignals::grabSignals(PISignals::Interrupt);
|
||||
|
||||
// Start server
|
||||
Server server(static_cast<ushort>(port), pipelinesDir, logsDir, webRoot);
|
||||
Server server(static_cast<ushort>(config.port()), config.pipelinesDir(), config.logsDir(), config.webRoot());
|
||||
server.start();
|
||||
|
||||
// Wait for exit
|
||||
|
||||
Reference in New Issue
Block a user