#include #include #include #include #include #include #include #include #include "raptor_eagle_ccd.h" typedef adc::impl::AdcDeviceNetServerASIO server_t; int main(int argc, char* argv[]) { int exit_code = 0; asio::io_context ctx; std::vector threads; std::size_t Nthreads = 3; /* COMMANDLINE OPTS */ cxxopts::Options options(argv[0], "ADC-library test device network server (ASIO implementation)\n"); options.allow_unrecognised_options(); options.add_options()("h,help", "Print usage"); options.add_options()("D", "Daemonize server", cxxopts::value()->default_value("false")); options.add_options()("l,log", "Log filename (use stdout and stderr for standard output and error stream)", cxxopts::value()->default_value("")); options.add_options()("level", "Log level (see SPDLOG package description for valid values)", cxxopts::value()->default_value("info")); options.add_options()("t,threads", "Number of threads used by the server", cxxopts::value()->default_value(std::to_string(Nthreads))); options.add_options()( "endpoints", "endpoints server will be listening for. For 'local' endpoint the '@' symbol at the beginning of the path " "means " "abstract namespace socket.", cxxopts::value>()->default_value("local://stream/@RAPTOR_EAGLEV_SERVER")); options.positional_help("[endpoint0] [enpoint1] ... [endpointN]"); options.parse_positional({"endpoints"}); try { auto opt_result = options.parse(argc, argv); if (opt_result["help"].count()) { std::cout << options.help(); std::cout << "\n"; std::cout << "[endpoint0] [enpoint1] ... [endpointN] - endpoints server will be listening for. For 'local' " "endpoint the '@' symbol at the beginning of the path " "means abstract namespace socket." << "\n"; return 0; } auto logname = opt_result["log"].as(); auto logger = [&logname]() { if (logname == "stdout") { return spdlog::stdout_color_mt("console"); } else if (logname == "stderr") { return spdlog::stderr_color_mt("stderr"); } else if (logname == "") { return spdlog::null_logger_mt("RAPTOR_EAGLEV_SERVER_NULL_LOGGER"); } else { return spdlog::basic_logger_mt(logname, logname); } }(); std::string level_str = opt_result["level"].as(); std::ranges::transform(level_str, level_str.begin(), [](const char& c) { return std::tolower(c); }); auto log_level = spdlog::level::from_str(level_str); logger->set_level(log_level); logger->flush_on(spdlog::level::trace); logger->set_pattern("%v"); int w = 90; const std::string fmt = std::format("{{:*^{}}}", w); logger->info("\n\n\n"); logger->info(fmt, ""); logger->info(fmt, " RAPTOR EAGLE V CCD CAMERA SERVER "); auto zt = std::chrono::zoned_time(std::chrono::current_zone(), std::chrono::floor(std::chrono::system_clock::now())); logger->info(fmt, std::format(" {} ", zt)); logger->info(fmt, ""); logger->info("\n"); asio::io_context io_ctx; asio::signal_set signals(io_ctx, SIGINT, SIGTERM); signals.async_wait([&](std::error_code, int) { io_ctx.stop(); }); RaptorEagleCCD ccd_device(logger); server_t server("RAPTOR EAGLE V CCD SERVER", io_ctx, logger); server.setupSignals(); server.addDevice(&ccd_device); auto epnt = opt_result["endpoints"].as>(); for (auto& ep : epnt) { adc::AdcEndpoint epn(ep); if (epn.isValid()) { if (epn.isLocalSeqpacket() || epn.isLocalStream()) { if (epn.path()[0] == '@') { // replace '@' to '\0' (use of UNIX abstract namespace) auto it = std::ranges::find(ep, '@'); *it = '\0'; epn = adc::AdcEndpoint(ep); } } server.start>(epn); } else { std::cerr << "Unrecognized endpoint: '" << ep << "'! Ignore!\n"; } } if (opt_result["D"].as()) { server.daemonize(); } io_ctx.run(); } catch (const cxxopts::exceptions::exception& ex) { std::cerr << "\nAn error occured while parsing input options: " << ex.what() << "\n"; exit_code = 127; } catch (const std::system_error& ex) { std::cerr << "\nAn error occured: " << ex.what() << " (err category: " << ex.code().category().name() << ")\n"; // std::cerr << "Category: " << ex.code().category().name() << "; message: " << ex.code().message() << "\n"; exit_code = 128; } return exit_code; }