added JSON support to select the services
This commit is contained in:
parent
d9d0643dfc
commit
1e9a377c2a
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
cmake-build-debug
|
||||||
|
cmake-build-release
|
||||||
|
build
|
||||||
|
|
||||||
|
# JetBrains IDEs
|
||||||
|
.idea/
|
||||||
|
!.idea/codeStyles/
|
||||||
|
!.idea/runConfigurations/
|
||||||
|
!.idea/inspectionProfiles/
|
||||||
|
*.iml
|
||||||
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@ -81,6 +81,12 @@
|
|||||||
"typeinfo": "cpp",
|
"typeinfo": "cpp",
|
||||||
"valarray": "cpp",
|
"valarray": "cpp",
|
||||||
"variant": "cpp",
|
"variant": "cpp",
|
||||||
"*.ipp": "cpp"
|
"*.ipp": "cpp",
|
||||||
|
"expected": "cpp",
|
||||||
|
"queue": "cpp",
|
||||||
|
"stack": "cpp",
|
||||||
|
"strstream": "cpp",
|
||||||
|
"complex": "cpp",
|
||||||
|
"typeindex": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(CrowHTMX)
|
project(CrowHTMX)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
# Allow selection of build type if not set
|
# Allow selection of build type if not set
|
||||||
@ -32,7 +32,21 @@ endforeach()
|
|||||||
# Use Crow from system include (installed via yay -S crow + asio)
|
# Use Crow from system include (installed via yay -S crow + asio)
|
||||||
include_directories(/usr/include)
|
include_directories(/usr/include)
|
||||||
|
|
||||||
add_executable(app main.cpp)
|
add_executable(app src/main.cpp
|
||||||
|
src/htmx/HtmxTable.cpp
|
||||||
|
src/htmx/HtmxTable.h
|
||||||
|
src/systemd.cpp
|
||||||
|
src/systemd.h
|
||||||
|
src/json.hpp
|
||||||
|
src/htmx/HtmxTableRow.cpp
|
||||||
|
src/htmx/HtmxTableRow.h
|
||||||
|
src/htmx/HtmxObject.cpp
|
||||||
|
src/htmx/HtmxObject.h
|
||||||
|
src/htmx_helper.cpp
|
||||||
|
src/htmx_helper.h
|
||||||
|
src/json_settings.cpp
|
||||||
|
src/json_settings.h
|
||||||
|
src/json.hpp)
|
||||||
|
|
||||||
target_link_libraries(app pthread)
|
target_link_libraries(app pthread)
|
||||||
|
|
||||||
|
|||||||
136
main.cpp
136
main.cpp
@ -1,136 +0,0 @@
|
|||||||
#include <crow.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <string>
|
|
||||||
#include <array>
|
|
||||||
#include <format>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
string load_file(const string& path) {
|
|
||||||
ifstream f(path);
|
|
||||||
stringstream buffer;
|
|
||||||
buffer << f.rdbuf();
|
|
||||||
return buffer.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_service_active(string_view service_name) {
|
|
||||||
const string cmd = format("systemctl is-active --quiet {}", service_name);
|
|
||||||
return system(cmd.c_str()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_service_enabled(string_view service_name) {
|
|
||||||
const string cmd = format("systemctl is-enabled --quiet {}", service_name);
|
|
||||||
return system(cmd.c_str()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void toggle_service(string_view serviceName){
|
|
||||||
string_view toggle = is_service_active(serviceName) ? "stop" : "start";
|
|
||||||
const string cmd = format("systemctl {} {}", toggle, serviceName);
|
|
||||||
system(cmd.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
string_view get_button_class(bool isActive) {
|
|
||||||
return isActive ? "active-button" : "inactive-button";
|
|
||||||
}
|
|
||||||
|
|
||||||
optional<string> get_body_name(const string& body) {
|
|
||||||
const auto pos = body.find('=');
|
|
||||||
if (pos == std::string::npos) return {};
|
|
||||||
|
|
||||||
const string key = body.substr(0, pos);
|
|
||||||
string value = body.substr(pos + 1);
|
|
||||||
|
|
||||||
if (key != "name") return {};
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
string create_htmx_button(string_view endpoint, string_view serviceName, string_view text) {
|
|
||||||
return format(
|
|
||||||
"<td>\
|
|
||||||
<button\
|
|
||||||
hx-post=\"{}\"\
|
|
||||||
hx-vals='{{\"name\":\"{}\"}}'\
|
|
||||||
hx-target=\"closest tr\"\
|
|
||||||
hx-swap=\"outerHTML\">\
|
|
||||||
{} \
|
|
||||||
</button> \
|
|
||||||
</td>", endpoint, serviceName, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
string create_htmx_table_row(string_view serviceName){
|
|
||||||
const bool isRunning = is_service_active(serviceName);
|
|
||||||
const bool isEnabled = is_service_active(serviceName);
|
|
||||||
|
|
||||||
const auto running = isRunning ? "Running" : "Stopped";
|
|
||||||
const auto enabled = isEnabled ? "Enabled" : "Disabled";
|
|
||||||
|
|
||||||
// create status indicators
|
|
||||||
string html = format(
|
|
||||||
"<tr>\
|
|
||||||
<td>{}</td>\
|
|
||||||
<td class='{}'>{}</td>\
|
|
||||||
<td class='{}'>{}</td>",
|
|
||||||
serviceName, get_button_class(isRunning), running, get_button_class(isEnabled), enabled);
|
|
||||||
|
|
||||||
// create buttons
|
|
||||||
html += create_htmx_button("/toggle-service", serviceName, isRunning ? "Stop" : "Start");
|
|
||||||
html += create_htmx_button("/enable-service", serviceName, isEnabled ? "Disable" : "Enable");
|
|
||||||
html += create_htmx_button("/restart-service", serviceName, "Restart");
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
const array<string, 1>& get_service_names() {
|
|
||||||
static const array<string, 1> arr = {
|
|
||||||
"cups.service"
|
|
||||||
};
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
crow::SimpleApp app;
|
|
||||||
|
|
||||||
CROW_ROUTE(app, "/")([] {
|
|
||||||
return crow::response(load_file("templates/index.html"));
|
|
||||||
});
|
|
||||||
|
|
||||||
CROW_ROUTE(app, "/static/<string>")([](const std::string& file) {
|
|
||||||
return crow::response(load_file("static/" + file));
|
|
||||||
});
|
|
||||||
|
|
||||||
CROW_ROUTE(app, "/status")([] {
|
|
||||||
auto names = get_service_names();
|
|
||||||
|
|
||||||
// define the table header
|
|
||||||
string html = "<table><tr>\
|
|
||||||
<th>Service</th>\
|
|
||||||
<th>Status</th>\
|
|
||||||
<th>State</th>\
|
|
||||||
</tr>";
|
|
||||||
|
|
||||||
// display each service as an entry
|
|
||||||
for (auto& serviceName : names) {
|
|
||||||
html += create_htmx_table_row(serviceName);
|
|
||||||
}
|
|
||||||
html += " </tr></table>";
|
|
||||||
return crow::response{html};
|
|
||||||
});
|
|
||||||
|
|
||||||
CROW_ROUTE(app, "/toggle-service").methods(crow::HTTPMethod::Post)([](const crow::request& req) {
|
|
||||||
auto body = get_body_name(req.body);
|
|
||||||
if (!body.has_value())
|
|
||||||
return crow::response(400);
|
|
||||||
|
|
||||||
const string& serviceName = body.value();
|
|
||||||
|
|
||||||
toggle_service(serviceName);
|
|
||||||
|
|
||||||
const string html = create_htmx_table_row(serviceName);
|
|
||||||
return crow::response{html};
|
|
||||||
});
|
|
||||||
|
|
||||||
app.port(8080).multithreaded().run();
|
|
||||||
}
|
|
||||||
11
src/htmx/HtmxObject.cpp
Normal file
11
src/htmx/HtmxObject.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "HtmxObject.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
const string& HtmxObject::htmx() const {
|
||||||
|
return html;
|
||||||
|
}
|
||||||
28
src/htmx/HtmxObject.h
Normal file
28
src/htmx/HtmxObject.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef HTMXOBJECT_H
|
||||||
|
#define HTMXOBJECT_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
class HtmxObject {
|
||||||
|
public:
|
||||||
|
|
||||||
|
HtmxObject() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HTMX representation of the object as a string
|
||||||
|
* @return htmx string
|
||||||
|
*/
|
||||||
|
const std::string& htmx() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string html;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //HTMXOBJECT_H
|
||||||
17
src/htmx/HtmxTable.cpp
Normal file
17
src/htmx/HtmxTable.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include "HtmxTable.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void HtmxTable::add_row(const HtmxTableRow& row){
|
||||||
|
html += row.htmx();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HtmxTable::complete() {
|
||||||
|
html += "</table>";
|
||||||
|
}
|
||||||
|
|
||||||
40
src/htmx/HtmxTable.h
Normal file
40
src/htmx/HtmxTable.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef HTMXTABLE_H
|
||||||
|
#define HTMXTABLE_H
|
||||||
|
|
||||||
|
#include "HtmxObject.h"
|
||||||
|
#include "HtmxTableRow.h"
|
||||||
|
#include "format"
|
||||||
|
|
||||||
|
class HtmxTable : public HtmxObject {
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<std::ranges::input_range R>
|
||||||
|
requires std::convertible_to<std::ranges::range_value_t<R>, std::string_view>
|
||||||
|
HtmxTable(const R& strings) {
|
||||||
|
// define the table header
|
||||||
|
html = "<table><tr>";
|
||||||
|
for (const auto& s : strings) {
|
||||||
|
html += format("<th>{}</th>", s);
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a htmx row to the table
|
||||||
|
*
|
||||||
|
* @param row
|
||||||
|
* @return htmx representation of the row
|
||||||
|
*/
|
||||||
|
void add_row(const HtmxTableRow& row);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete the table
|
||||||
|
*/
|
||||||
|
void complete();
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif //HTMXTABLE_H
|
||||||
35
src/htmx/HtmxTableRow.cpp
Normal file
35
src/htmx/HtmxTableRow.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
#include <format>
|
||||||
|
#include "HtmxTableRow.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void HtmxTableRow::add_button(string_view endpoint, string_view name, string_view text) {
|
||||||
|
html += format("<td>\
|
||||||
|
<button\
|
||||||
|
hx-post=\"{}\"\
|
||||||
|
hx-vals='{{\"name\":\"{}\"}}'\
|
||||||
|
hx-target=\"closest tr\"\
|
||||||
|
hx-swap=\"outerHTML\">\
|
||||||
|
{} \
|
||||||
|
</button> \
|
||||||
|
</td>", endpoint, name, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static string_view get_button_class(bool is_active) {
|
||||||
|
return is_active ? "active-button" : "inactive-button";
|
||||||
|
}
|
||||||
|
|
||||||
|
void HtmxTableRow::add_status_box(std::string_view name, bool is_active) {
|
||||||
|
html += format("<td class='{}'>{}</td>", get_button_class(is_active), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HtmxTableRow::add(string_view text) {
|
||||||
|
html += format("<td>{}</td>", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HtmxTableRow::complete() {
|
||||||
|
html += "</tr>";
|
||||||
|
}
|
||||||
28
src/htmx/HtmxTableRow.h
Normal file
28
src/htmx/HtmxTableRow.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef HTMXTABLEROW_H
|
||||||
|
#define HTMXTABLEROW_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "HtmxObject.h"
|
||||||
|
|
||||||
|
class HtmxTableRow : public HtmxObject {
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add_status_box(std::string_view name, bool is_active);
|
||||||
|
|
||||||
|
void add_button(std::string_view endpoint, std::string_view name, std::string_view text);
|
||||||
|
|
||||||
|
void add(std::string_view text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete the row
|
||||||
|
*/
|
||||||
|
void complete();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //HTMXTABLEROW_H
|
||||||
59
src/htmx_helper.cpp
Normal file
59
src/htmx_helper.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
#include <array>
|
||||||
|
#include "systemd.h"
|
||||||
|
#include "htmx_helper.h"
|
||||||
|
#include "json_settings.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
HtmxTableRow create_service_table_row(string_view service_name, string_view service_id) {
|
||||||
|
HtmxTableRow row;
|
||||||
|
|
||||||
|
const bool isRunning = systemd::is_service_active(service_id);
|
||||||
|
const bool isEnabled = systemd::is_service_active(service_id);
|
||||||
|
|
||||||
|
const auto running = isRunning ? "Running" : "Stopped";
|
||||||
|
const auto enabled = isEnabled ? "Enabled" : "Disabled";
|
||||||
|
|
||||||
|
row.add(service_name);
|
||||||
|
row.add_status_box(running, isRunning);
|
||||||
|
row.add_status_box(enabled, isEnabled);
|
||||||
|
|
||||||
|
// create buttons
|
||||||
|
row.add_button("/toggle-service", service_name, isRunning ? "Stop" : "Start");
|
||||||
|
row.add_button("/restart-service", service_name, "Restart");
|
||||||
|
row.complete();
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmxTableRow create_error_table_row(string_view error) {
|
||||||
|
HtmxTableRow row;
|
||||||
|
row.add("Error");
|
||||||
|
row.add(error);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmxTable create_service_table() {
|
||||||
|
constexpr array<string_view, 3> cols = {
|
||||||
|
"Service", "Status", "State"
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmxTable table(cols);
|
||||||
|
|
||||||
|
auto settings = AppSettings::loadAppSettings();
|
||||||
|
|
||||||
|
if(settings.has_value()){
|
||||||
|
AppSettings& data = settings.value();
|
||||||
|
for (auto& service : data.services) {
|
||||||
|
table.add_row(create_service_table_row(service.name, service.service));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
table.add_row(create_error_table_row(settings.error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
15
src/htmx_helper.h
Normal file
15
src/htmx_helper.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef HTMX_HELPER_H
|
||||||
|
#define HTMX_HELPER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "htmx/HtmxTable.h"
|
||||||
|
|
||||||
|
HtmxTableRow create_service_table_row(std::string_view service_name, std::string_view service_id);
|
||||||
|
HtmxTableRow create_error_table_row(std::string_view error);
|
||||||
|
HtmxTable create_service_table();
|
||||||
|
|
||||||
|
#endif //HTMX_HELPER_H
|
||||||
25580
src/json.hpp
Normal file
25580
src/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
54
src/json_settings.cpp
Normal file
54
src/json_settings.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include <fstream>
|
||||||
|
#include <format>
|
||||||
|
#include "json.hpp"
|
||||||
|
#include "json_settings.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
expected<AppSettings, string> AppSettings::loadAppSettings() {
|
||||||
|
constexpr char settings_file[] = "static/settings.json";
|
||||||
|
ifstream file(settings_file);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
return unexpected(format("Failed to open {}",settings_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the JSON
|
||||||
|
json j;
|
||||||
|
try {
|
||||||
|
file >> j;
|
||||||
|
} catch (const json::parse_error& e) {
|
||||||
|
return unexpected(format("Failed to parse JSON {}",e.what()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!j.contains("services") || !j["services"].is_array()) {
|
||||||
|
return unexpected("JSON does not contain an array called 'services'");
|
||||||
|
}
|
||||||
|
|
||||||
|
AppSettings settings;
|
||||||
|
|
||||||
|
for (const auto& item : j["services"]) {
|
||||||
|
if (item.is_array() && item.size() == 2) {
|
||||||
|
Service service = {
|
||||||
|
item[0].get<std::string>(),
|
||||||
|
item[1].get<std::string>()
|
||||||
|
};
|
||||||
|
settings.services.push_back(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.services.empty()){
|
||||||
|
return unexpected("'services' array in JSON file is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<const std::string&> AppSettings::getId(string_view name){
|
||||||
|
for (auto& service : services) {
|
||||||
|
if(service.name == name) {
|
||||||
|
return service.service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
22
src/json_settings.h
Normal file
22
src/json_settings.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef JSON_SETTINGS_H
|
||||||
|
#define JSON_SETTINGS_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <expected>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
struct Service {
|
||||||
|
std::string name;
|
||||||
|
std::string service;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AppSettings {
|
||||||
|
static std::expected<AppSettings, std::string> loadAppSettings();
|
||||||
|
|
||||||
|
std::optional<const std::string&> getId(std::string_view name);
|
||||||
|
|
||||||
|
std::vector<Service> services;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JSON_SETTINGS_H
|
||||||
72
src/main.cpp
Normal file
72
src/main.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include <crow.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
#include "json_settings.h"
|
||||||
|
#include "htmx_helper.h"
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
string load_file(const string& path) {
|
||||||
|
ifstream f(path);
|
||||||
|
stringstream buffer;
|
||||||
|
buffer << f.rdbuf();
|
||||||
|
return buffer.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<string> get_body_name(const string& body) {
|
||||||
|
const auto pos = body.find('=');
|
||||||
|
if (pos == std::string::npos) return {};
|
||||||
|
|
||||||
|
const string key = body.substr(0, pos);
|
||||||
|
string value = body.substr(pos + 1);
|
||||||
|
|
||||||
|
if (key != "name") return {};
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
crow::SimpleApp app;
|
||||||
|
|
||||||
|
CROW_ROUTE(app, "/")([] {
|
||||||
|
return crow::response(load_file("templates/index.html"));
|
||||||
|
});
|
||||||
|
|
||||||
|
CROW_ROUTE(app, "/static/<string>")([](const std::string& file) {
|
||||||
|
return crow::response(load_file("static/" + file));
|
||||||
|
});
|
||||||
|
|
||||||
|
CROW_ROUTE(app, "/status")([] {
|
||||||
|
auto table = create_service_table();
|
||||||
|
return crow::response{table.htmx()};
|
||||||
|
});
|
||||||
|
|
||||||
|
CROW_ROUTE(app, "/toggle-service").methods(crow::HTTPMethod::Post)([](const crow::request& req) {
|
||||||
|
auto body = get_body_name(req.body);
|
||||||
|
if (!body.has_value())
|
||||||
|
return crow::response(400);
|
||||||
|
|
||||||
|
const string& serviceName = body.value();
|
||||||
|
|
||||||
|
auto opt_settings = AppSettings::loadAppSettings();
|
||||||
|
|
||||||
|
HtmxTableRow row;
|
||||||
|
if (opt_settings.has_value()) {
|
||||||
|
auto& settings = opt_settings.value();
|
||||||
|
const auto& service_id = settings.getId(serviceName).value_or(serviceName);
|
||||||
|
|
||||||
|
systemd::toggle_service(service_id);
|
||||||
|
row = create_service_table_row(serviceName, service_id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
row = create_error_table_row(opt_settings.error());
|
||||||
|
}
|
||||||
|
return crow::response{row.htmx()};
|
||||||
|
});
|
||||||
|
|
||||||
|
app.port(8080).multithreaded().run();
|
||||||
|
}
|
||||||
26
src/systemd.cpp
Normal file
26
src/systemd.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "format"
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace systemd {
|
||||||
|
bool is_service_active(string_view service_name) {
|
||||||
|
const string cmd = format("systemctl is-active --quiet {}", service_name);
|
||||||
|
return system(cmd.c_str()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_service_enabled(string_view service_name) {
|
||||||
|
const string cmd = format("systemctl is-enabled --quiet {}", service_name);
|
||||||
|
return system(cmd.c_str()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggle_service(string_view serviceName){
|
||||||
|
string_view toggle = is_service_active(serviceName) ? "stop" : "start";
|
||||||
|
const string cmd = format("systemctl {} {}", toggle, serviceName);
|
||||||
|
system(cmd.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/systemd.h
Normal file
34
src/systemd.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 5/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SYSTEMD_H
|
||||||
|
#define SYSTEMD_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace systemd {
|
||||||
|
/**
|
||||||
|
* Check if a service is active
|
||||||
|
* @param service_name name of the systemd service
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool is_service_active(std::string_view service_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a service is enabled
|
||||||
|
* @param service_name name of the systemd service
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool is_service_enabled(std::string_view service_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the service on or off dependent on its current state
|
||||||
|
* @param service_name name of the systemd service
|
||||||
|
*/
|
||||||
|
void toggle_service(std::string_view service_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SYSTEMD_H
|
||||||
6
static/settings.json
Normal file
6
static/settings.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"services": [
|
||||||
|
["Cups", "cups.service"],
|
||||||
|
["Waydriod", "waydroid-container.service"]
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user