| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- #include "database_service.hpp"
- #include <spdlog/spdlog.h>
- #include <spdlog/sinks/stdout_color_sinks.h>
- #include <csignal>
- #include <cstdlib>
- #include <filesystem>
- #include <iostream>
- #ifdef HAVE_SYSTEMD
- #include <systemd/sd-daemon.h>
- #endif
- namespace {
- smartbotic::database::DatabaseService* g_service = nullptr;
- void signalHandler(int signal) {
- spdlog::info("Received signal {}", signal);
- if (g_service) {
- g_service->signalStop();
- }
- }
- void printUsage(const char* programName) {
- std::cout << "Usage: " << programName << " [OPTIONS]\n"
- << "\n"
- << "Options:\n"
- << " --config, -c PATH Configuration file path\n"
- << " --help, -h Show this help message\n"
- << " --version, -v Show version information\n"
- << "\n"
- << "Environment variables:\n"
- << " DATABASE_NODE_ID Override node ID from config\n"
- << " DATABASE_MASTER_KEY Encryption master key (hex-encoded)\n"
- << std::endl;
- }
- void printVersion() {
- std::cout << "smartbotic-database version 1.0.0\n"
- << "Smartbotic Database Service\n"
- << std::endl;
- }
- void initLogging(const std::string& serviceName) {
- try {
- // Create console sink
- auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
- console_sink->set_level(spdlog::level::debug);
- // Create default logger with console sink
- auto logger = std::make_shared<spdlog::logger>(serviceName, console_sink);
- logger->set_level(spdlog::level::info);
- // Check environment for log level
- if (const char* logLevel = std::getenv("LOG_LEVEL")) {
- std::string level(logLevel);
- if (level == "trace") logger->set_level(spdlog::level::trace);
- else if (level == "debug") logger->set_level(spdlog::level::debug);
- else if (level == "info") logger->set_level(spdlog::level::info);
- else if (level == "warn") logger->set_level(spdlog::level::warn);
- else if (level == "error") logger->set_level(spdlog::level::err);
- }
- spdlog::set_default_logger(logger);
- spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%n] %v");
- } catch (const spdlog::spdlog_ex& ex) {
- std::cerr << "Log initialization failed: " << ex.what() << std::endl;
- }
- }
- std::filesystem::path findConfigFile(int argc, char* argv[]) {
- // Check command line arguments
- for (int i = 1; i < argc; ++i) {
- std::string arg = argv[i];
- if ((arg == "--config" || arg == "-c") && i + 1 < argc) {
- return argv[i + 1];
- }
- }
- // Check environment variable
- if (const char* configPath = std::getenv("DATABASE_CONFIG")) {
- return configPath;
- }
- // Default paths
- std::vector<std::filesystem::path> defaultPaths = {
- "./config/database.json",
- "./config/storage.json", // Backward compatibility
- "/etc/smartbotic/database.json",
- "/etc/callerai/storage.json", // Backward compatibility
- std::filesystem::path(std::getenv("HOME") ? std::getenv("HOME") : "") / ".config/smartbotic/database.json"
- };
- for (const auto& path : defaultPaths) {
- if (std::filesystem::exists(path)) {
- return path;
- }
- }
- return "./config/database.json";
- }
- } // anonymous namespace
- int main(int argc, char* argv[]) {
- // Parse command line arguments
- for (int i = 1; i < argc; ++i) {
- std::string arg = argv[i];
- if (arg == "--help" || arg == "-h") {
- printUsage(argv[0]);
- return 0;
- }
- if (arg == "--version" || arg == "-v") {
- printVersion();
- return 0;
- }
- }
- try {
- // Initialize logging
- initLogging("database");
- // Find configuration file
- auto configPath = findConfigFile(argc, argv);
- spdlog::info("Loading configuration from {}", configPath.string());
- // Load configuration
- smartbotic::database::DatabaseService::Config config;
- if (std::filesystem::exists(configPath)) {
- config = smartbotic::database::DatabaseService::loadConfig(configPath);
- } else {
- spdlog::warn("Configuration file not found, using defaults");
- // Set default data directory
- const char* home = std::getenv("HOME");
- if (home) {
- config.dataDirectory = std::filesystem::path(home) / ".local/share/smartbotic/database";
- config.keyFilePath = std::filesystem::path(home) / ".config/smartbotic/database.key";
- } else {
- config.dataDirectory = "/var/lib/smartbotic/database";
- config.keyFilePath = "/etc/smartbotic/database.key";
- }
- }
- // Override node ID from environment if set
- if (const char* nodeId = std::getenv("DATABASE_NODE_ID")) {
- config.nodeId = nodeId;
- }
- // Create service
- smartbotic::database::DatabaseService service(config);
- g_service = &service;
- // Set up signal handlers
- std::signal(SIGINT, signalHandler);
- std::signal(SIGTERM, signalHandler);
- // Initialize service
- if (!service.initialize()) {
- spdlog::error("Failed to initialize database service");
- return 1;
- }
- // Start service
- service.start();
- #ifdef HAVE_SYSTEMD
- // Notify systemd we're ready
- sd_notify(0, "READY=1");
- spdlog::info("Notified systemd: READY");
- #endif
- // Wait for shutdown
- int watchdogCounter = 0;
- while (service.isRunning()) {
- std::this_thread::sleep_for(std::chrono::seconds(1));
- #ifdef HAVE_SYSTEMD
- // Send watchdog notification every 30 seconds (half of WatchdogSec=60)
- if (++watchdogCounter >= 30) {
- sd_notify(0, "WATCHDOG=1");
- watchdogCounter = 0;
- }
- #endif
- }
- #ifdef HAVE_SYSTEMD
- sd_notify(0, "STOPPING=1");
- #endif
- // Stop service
- service.stop();
- g_service = nullptr;
- spdlog::info("Database service exited cleanly");
- return 0;
- } catch (const std::exception& e) {
- spdlog::error("Fatal error: {}", e.what());
- return 1;
- }
- }
|