summaryrefslogtreecommitdiff
path: root/src/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cc')
-rw-r--r--src/main.cc98
1 files changed, 97 insertions, 1 deletions
diff --git a/src/main.cc b/src/main.cc
index e66f95a..54f3d0a 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1,16 +1,91 @@
#include "args.hh"
+#include "cfg.hh"
#include "config.h"
+#include "http.hh"
+#include "logger.hh"
+#include "looper.hh"
+#include <cerrno>
+#include <cstring>
+#include <format>
#include <iostream>
+#include <memory>
+#include <unistd.h>
+#include <utility>
+#include <vector>
#ifndef VERSION
# define VERSION "unknown"
#endif
+namespace {
+
+class HttpServerDelegate : public http::Server::Delegate {
+ public:
+ HttpServerDelegate() = default;
+
+ std::unique_ptr<http::Response> handle(
+ http::Request const& request) override {
+ if (request.method() != "GET") {
+ return http::Response::status(http::StatusCode::kMethodNotAllowed);
+ }
+
+ if (request.path() == "/api/v1/status") {
+ return http::Response::content(
+ R"({ status: "OK" })",
+ *http::MimeType::create("application", "json"));
+ }
+
+ return http::Response::status(http::StatusCode::kNotFound);
+ }
+};
+
+bool run(logger::Logger& logger, cfg::Config const& cfg,
+ std::unique_ptr<http::OpenPort> port) {
+ auto looper = looper::create();
+ HttpServerDelegate delegate;
+ auto server =
+ http::create_server(logger, cfg, *looper, std::move(port), delegate);
+ return looper->run(logger);
+}
+
+bool start_daemon(logger::Logger& logger, cfg::Config const& cfg,
+ std::unique_ptr<http::OpenPort> port, bool verbose) {
+ auto pid = fork();
+ if (pid == 0) {
+ // Child process
+ // Move out of current workind directory to not keep it alive
+ chdir("/");
+ // Create a new process group
+ setpgid(0, 0);
+ // Close stdin, stdout and stderr
+ close(0);
+ close(1);
+ close(2);
+ // Use syslog logger
+ auto logger2 = logger::syslog("bluetooth-jukebox", verbose);
+ _exit(run(*logger2, cfg, std::move(port)) ? 0 : 1);
+ } else if (pid == -1) {
+ // Error
+ logger.err(std::format("Unable to fork: {}", strerror(errno)));
+ return false;
+ } else {
+ // Parent process
+ logger.info(std::format("Forked into pid {}", pid));
+ return true;
+ }
+}
+
+} // namespace
+
int main(int argc, char** argv) {
auto args = Args::create();
auto opt_help = args->option('h', "help", "display this text and exit.");
auto opt_version = args->option('V', "version", "display version and exit.");
+ auto opt_config = args->option_argument(
+ 'C', "config", "FILE", "load config from FILE instead of default.");
+ auto opt_verbose = args->option('v', "verbose", "be more verbose.");
+ auto opt_daemon = args->option('d', "daemon", "fork into background.");
if (!args->run(argc, argv)) {
args->print_error(std::cerr);
std::cerr << "Try 'bluetooth-jukebox --help' for more information.\n";
@@ -27,5 +102,26 @@ int main(int argc, char** argv) {
<< " written by Joel Klinghed <the_jk@spawned.biz>.\n";
return 0;
}
- return 0;
+ bool verbose = opt_verbose->is_set();
+ bool daemon = opt_daemon->is_set();
+ std::unique_ptr<cfg::Config> cfg;
+ std::vector<std::string> errors;
+ if (opt_config->is_set()) {
+ cfg = cfg::load_one(opt_config->argument(), errors);
+ } else {
+ cfg = cfg::load_all("bluetooth-jukebox", errors);
+ }
+
+ auto logger = logger::stderr(verbose);
+
+ // Open the port here, in case we fork() later, to fail early.
+ auto port = http::open_port(cfg->get("http.bind").value_or("localhost:5555"),
+ *logger);
+ if (!port)
+ return 1;
+
+ if (daemon)
+ return start_daemon(*logger, *cfg, std::move(port), verbose) ? 0 : 1;
+
+ return run(*logger, *cfg, std::move(port)) ? 0 : 1;
}