diff --git a/src/main.cpp b/src/main.cpp index a283b1d..bc667b8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,27 +1,57 @@ - - -#include +#include +#include #include #include +#include #include "EventLoop.hpp" #include "RestartingProcess.hpp" +namespace fs = std::filesystem; + +/// simple tiny log impl thing. +namespace nanosm::log { + + template + constexpr void LogImpl(std::string_view component, std::string_view severity, std::string_view formatString, std::format_args args) { + auto log = std::vformat(formatString, args); + auto formatted = std::format("[{}|{}] {}\n", component, severity, log); + write(file, formatted.data(), formatted.size()); + } + + template + constexpr void Info(std::string_view component, std::string formatString, Args... args) { + return LogImpl(component, "Info", formatString, std::make_format_args(args...)); + } + + template + constexpr void Warn(std::string_view component, std::string formatString, Args... args) { + return LogImpl(component, "Info", formatString, std::make_format_args(args...)); + } + + template + constexpr void Error(std::string_view component, std::string formatString, Args... args) { + return LogImpl(component, "Info", formatString, std::make_format_args(args...)); + } + +} // namespace nanosm::log + struct NanoSm { struct App : std::enable_shared_from_this { - App(nanosm::EventLoop& ev, const std::string& tomlId, const std::string& commandLine) - : process(std::make_shared(ev)), + App(NanoSm& nanoSm, const std::string& tomlId, const std::string& commandLine) + : process(std::make_shared(nanoSm.ev)), id(tomlId), commandLine(commandLine) { + process->SetRestartTime(nanoSm.restartTime); } void Spawn() { process->SetSpawnCallback([self = shared_from_this()](pid_t pid) { - printf("\"%s\": command spawned as pid %d successfully\n", self->id.c_str(), pid); + nanosm::log::Info("NanoSm.App", "\"{}\": Spawned as PID {} successfully.", self->id, pid); // Set exit callback too self->process->SetExitCallback([self](pid_t pid, int exitCode) { - printf("\"%s\": pid %d exited with %d exitcode\n", self->id.c_str(), pid, exitCode); + nanosm::log::Info("NanoSm.App", "\"{}\": PID {} exited with code {}.", self->id, pid, exitCode); }); }); @@ -35,7 +65,11 @@ struct NanoSm { }; void AddApp(const std::string& id, const std::string& cmdLine) { - apps.push_back(std::make_shared(ev, id, cmdLine)); + apps.push_back(std::make_shared(*this, id, cmdLine)); + } + + void SetRestartTime(u32 newTime) { + restartTime = newTime; } void SpawnAllApps() { @@ -54,15 +88,68 @@ struct NanoSm { private: nanosm::EventLoop ev; + u32 restartTime { 1 }; std::vector> apps; }; +fs::path GetHome() { + // TODO: This should NEVER return nullptr, but if it does your computer is beyond + // repair properly anyways + auto sv = std::string_view { getenv("HOME") }; + + return fs::path(sv); +} + +fs::path GetConfigPath() { + return GetHome() / ".config" / "nanosm" / "nanosm.toml"; +} + int main(int argc, char** argv) { NanoSm nanosm; - // Run a few hardcoded apps (as a test) - nanosm.AddApp("Xterm", "xterm"); - nanosm.AddApp("Xterm2", "xterm"); + auto configPath = GetConfigPath(); + + try { + auto tomlTable = toml::parse_file(configPath.string()); + + if(tomlTable["nanosm"].is_table() && tomlTable["nanosm"]["apps"].is_table()) { + auto restartptr = tomlTable["nanosm"]["restart-time"].as_integer(); + + if(!restartptr) { + nanosm::log::Warn("NanoSm", "No restart time provided in nanosm.toml. Defaulting to 1 second."); + nanosm.SetRestartTime(1); + } else { + nanosm.SetRestartTime(static_cast(restartptr->get())); + } + + for(auto [key, value] : *tomlTable["nanosm"]["apps"].as_table()) { + if(!value.is_table()) { + nanosm::log::Warn("NanoSm", "Ignoring invalid app \"{}\" in configuration file", key.str()); + continue; + } + + auto& appTable = *value.as_table(); + + if(!appTable.get("command")->is_string()) { + nanosm::log::Warn("NanoSm", "Ignoring invalid app \"{}\" in configuration file", key.str()); + continue; + } + + auto cmd = appTable.get("command")->as_string()->get(); + + nanosm::log::Info("NanoSm", "Adding app \"{}\" with command \"{}\"", key.str(), cmd); + + nanosm.AddApp(std::string(key.data(), key.length()), std::string(cmd.data(), cmd.length())); + } + } else { + nanosm::log::Error("NanoSm", "Configuration file {} doesn't have required values. Exiting with failure.", configPath.string()); + return 1; + } + + } catch(toml::parse_error& pe) { + std::fprintf(stderr, "Error parsing config file \"%s\": %s\n", configPath.c_str(), pe.description().data()); + return 1; + } return nanosm.Run(); }