Files
metabuilder/dbal/cpp/src/daemon/main.cpp
JohnDoe6345789 17931e3167 feat(tests): add comprehensive tests for workflow engine functionality
- Implemented unit tests for the WorkflowEngine, covering various scenarios including simple workflows, condition handling, and error cases.
- Created a test coverage report generator to identify untested functions and provide actionable recommendations.
- Added a symlink for vite 2 configuration to streamline build processes.
2025-12-31 21:42:06 +00:00

217 lines
9.2 KiB
C++

#include <iostream>
#include <string>
#include <csignal>
#include <thread>
#include <chrono>
#include <memory>
// Cross-platform signal handling
#ifdef _WIN32
#include <windows.h>
// Windows doesn't have SIGTERM, use SIGBREAK
#ifndef SIGTERM
#define SIGTERM SIGBREAK
#endif
#endif
// Include server
#include "server.hpp"
#include "dbal/core/client.hpp"
namespace {
std::unique_ptr<dbal::daemon::Server> server_instance;
void signalHandler(int signal) {
if (signal == SIGINT || signal == SIGTERM) {
std::cout << "\nShutting down DBAL daemon..." << std::endl;
if (server_instance) {
server_instance->stop();
}
}
}
}
int main(int argc, char* argv[]) {
std::cout << "DBAL Daemon v1.0.0" << std::endl;
std::cout << "Copyright (c) 2024 MetaBuilder" << std::endl;
std::cout << std::endl;
// Register signal handlers
std::signal(SIGINT, signalHandler);
std::signal(SIGTERM, signalHandler);
// Load defaults from environment variables (can be overridden by CLI args)
std::string config_file = "config.yaml";
std::string bind_address = "127.0.0.1";
int port = 8080;
bool development_mode = false;
bool daemon_mode = false; // Default to interactive mode
// Check environment variables
const char* env_bind = std::getenv("DBAL_BIND_ADDRESS");
if (env_bind) bind_address = env_bind;
const char* env_port = std::getenv("DBAL_PORT");
if (env_port) port = std::stoi(env_port);
const char* env_mode = std::getenv("DBAL_MODE");
if (env_mode) {
std::string mode_str = env_mode;
development_mode = (mode_str == "development" || mode_str == "dev");
}
const char* env_config = std::getenv("DBAL_CONFIG");
if (env_config) config_file = env_config;
const char* env_daemon = std::getenv("DBAL_DAEMON");
if (env_daemon) {
std::string daemon_str = env_daemon;
daemon_mode = (daemon_str == "true" || daemon_str == "1" || daemon_str == "yes");
}
// Parse command line arguments (override environment variables)
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
if (arg == "--config" && i + 1 < argc) {
config_file = argv[++i];
} else if (arg == "--bind" && i + 1 < argc) {
bind_address = argv[++i];
} else if (arg == "--port" && i + 1 < argc) {
port = std::stoi(argv[++i]);
} else if (arg == "--mode" && i + 1 < argc) {
std::string mode = argv[++i];
development_mode = (mode == "development" || mode == "dev");
} else if (arg == "--daemon" || arg == "-d") {
daemon_mode = true;
} else if (arg == "--help" || arg == "-h") {
std::cout << "Usage: " << argv[0] << " [options]" << std::endl;
std::cout << "Options:" << std::endl;
std::cout << " --config <file> Configuration file (default: config.yaml)" << std::endl;
std::cout << " --bind <address> Bind address (default: 127.0.0.1)" << std::endl;
std::cout << " --port <port> Port number (default: 8080)" << std::endl;
std::cout << " --mode <mode> Run mode: production, development (default: production)" << std::endl;
std::cout << " --daemon, -d Run in daemon mode (default: interactive)" << std::endl;
std::cout << " --help, -h Show this help message" << std::endl;
std::cout << std::endl;
std::cout << "Environment variables (overridden by CLI args):" << std::endl;
std::cout << " DBAL_BIND_ADDRESS Bind address" << std::endl;
std::cout << " DBAL_PORT Port number" << std::endl;
std::cout << " DBAL_MODE Run mode (production/development)" << std::endl;
std::cout << " DBAL_CONFIG Configuration file path" << std::endl;
std::cout << " DBAL_DAEMON Run in daemon mode (true/false)" << std::endl;
std::cout << " DBAL_LOG_LEVEL Log level (trace/debug/info/warn/error/critical)" << std::endl;
std::cout << std::endl;
std::cout << "Interactive mode (default):" << std::endl;
std::cout << " Shows a command prompt with available commands:" << std::endl;
std::cout << " status - Show server status" << std::endl;
std::cout << " help - Show available commands" << std::endl;
std::cout << " stop - Stop the server and exit" << std::endl;
std::cout << std::endl;
std::cout << "Nginx reverse proxy example:" << std::endl;
std::cout << " location /api/ {" << std::endl;
std::cout << " proxy_pass http://127.0.0.1:8080/;" << std::endl;
std::cout << " proxy_set_header X-Real-IP $remote_addr;" << std::endl;
std::cout << " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;" << std::endl;
std::cout << " proxy_set_header X-Forwarded-Proto $scheme;" << std::endl;
std::cout << " proxy_set_header Host $host;" << std::endl;
std::cout << " }" << std::endl;
return 0;
}
}
std::cout << "Configuration: " << config_file << std::endl;
std::cout << "Mode: " << (development_mode ? "development" : "production") << std::endl;
std::cout << std::endl;
dbal::ClientConfig client_config;
client_config.mode = development_mode ? "development" : "production";
const char* adapter_env = std::getenv("DBAL_ADAPTER");
client_config.adapter = adapter_env ? adapter_env : "sqlite";
const char* database_env = std::getenv("DBAL_DATABASE_URL");
if (!database_env) {
database_env = std::getenv("DATABASE_URL");
}
client_config.database_url = database_env ? database_env : ":memory:";
client_config.sandbox_enabled = true;
const char* endpoint_env = std::getenv("DBAL_ENDPOINT");
if (endpoint_env) {
client_config.endpoint = endpoint_env;
}
// Create and start HTTP server
server_instance = std::make_unique<dbal::daemon::Server>(bind_address, port, client_config);
if (!server_instance->start()) {
std::cerr << "Failed to start server" << std::endl;
return 1;
}
std::cout << std::endl;
std::cout << "API endpoints:" << std::endl;
std::cout << " GET /health - Health check" << std::endl;
std::cout << " GET /version - Version information" << std::endl;
std::cout << " GET /status - Server status" << std::endl;
std::cout << std::endl;
if (daemon_mode) {
// Daemon mode: run in background until signal
std::cout << "Daemon mode: Running in background. Press Ctrl+C to stop." << std::endl;
while (server_instance->isRunning()) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
} else {
// Interactive mode: show command prompt
std::cout << "Interactive mode: Type 'help' for available commands, 'stop' to exit." << std::endl;
std::cout << std::endl;
std::string command;
while (server_instance->isRunning()) {
std::cout << "dbal> ";
std::cout.flush();
if (!std::getline(std::cin, command)) {
// EOF or error, exit gracefully
break;
}
// Trim whitespace
size_t start = command.find_first_not_of(" \t\r\n");
size_t end = command.find_last_not_of(" \t\r\n");
if (start == std::string::npos) {
continue; // Empty line
}
command = command.substr(start, end - start + 1);
if (command.empty()) {
continue;
}
if (command == "help" || command == "?") {
std::cout << "Available commands:" << std::endl;
std::cout << " status - Show server status and statistics" << std::endl;
std::cout << " help - Show this help message" << std::endl;
std::cout << " stop - Stop the server and exit" << std::endl;
std::cout << " exit - Alias for stop" << std::endl;
std::cout << " quit - Alias for stop" << std::endl;
} else if (command == "status") {
std::cout << "Server status:" << std::endl;
std::cout << " Address: " << bind_address << ":" << port << std::endl;
std::cout << " Mode: " << (development_mode ? "development" : "production") << std::endl;
std::cout << " Status: " << (server_instance->isRunning() ? "running" : "stopped") << std::endl;
} else if (command == "stop" || command == "exit" || command == "quit") {
std::cout << "Stopping server..." << std::endl;
server_instance->stop();
break;
} else {
std::cout << "Unknown command: " << command << std::endl;
std::cout << "Type 'help' for available commands." << std::endl;
}
}
}
std::cout << "Daemon stopped." << std::endl;
return 0;
}