stuff
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
config.toml
|
||||
build/**
|
||||
35
CMakeLists.txt
Normal file
35
CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(notification-pusher LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
message(FATAL_ERROR "Please configure with Clang: cmake -DCMAKE_CXX_COMPILER=clang++ ..")
|
||||
endif()
|
||||
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(spdlog REQUIRED)
|
||||
find_package(PahoMqttCpp REQUIRED)
|
||||
find_package(cpr REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} src/main.cpp
|
||||
src/definitions.cpp
|
||||
src/daemon.cpp
|
||||
)
|
||||
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||
-Wall -Wextra -Wpedantic
|
||||
-Wshadow -Wconversion
|
||||
-O2
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
fmt::fmt
|
||||
spdlog::spdlog
|
||||
PahoMqttCpp::paho-mqttpp3
|
||||
cpr::cpr
|
||||
)
|
||||
|
||||
75
src/daemon.cpp
Normal file
75
src/daemon.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "daemon.hpp"
|
||||
#include "definitions.hpp"
|
||||
#include "json.hpp"
|
||||
#include <cpr/api.h>
|
||||
#include <cpr/body.h>
|
||||
#include <cpr/cprtypes.h>
|
||||
#include <cpr/response.h>
|
||||
#include <fmt/format.h>
|
||||
#include <memory>
|
||||
#include <mqtt/client.h>
|
||||
#include <mqtt/exception.h>
|
||||
#include <mqtt/message.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <thread>
|
||||
#include <cpr/cpr.h>
|
||||
namespace daemon_notify {
|
||||
void start(std::unique_ptr<mqtt::client> client, std::string topic) {
|
||||
spdlog::info("Entered the notification daemon thread");
|
||||
|
||||
// Subscribe and start consuming
|
||||
client->subscribe(topic, 1);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200)); // Wait for SUBACK
|
||||
client->start_consuming();
|
||||
|
||||
|
||||
// Consume messages with manual timeout to avoid indefinite blocking
|
||||
while (true) {
|
||||
try {
|
||||
mqtt::const_message_ptr potential_notification_message;
|
||||
bool has_message = false;
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto timeout = std::chrono::seconds(2);
|
||||
|
||||
while ((std::chrono::steady_clock::now() - start) < timeout) {
|
||||
has_message = client->try_consume_message(&potential_notification_message);
|
||||
if (has_message) break;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
|
||||
if (!has_message) {
|
||||
spdlog::trace("No message received in this interval.");
|
||||
continue;
|
||||
}
|
||||
|
||||
spdlog::debug("Received mqtt message: {} on topic {}",
|
||||
potential_notification_message->to_string(),
|
||||
potential_notification_message->get_topic());
|
||||
|
||||
nlohmann::json parsed_json = nlohmann::json::parse(potential_notification_message->to_string());
|
||||
definitions::Notification notif = parsed_json.get<definitions::Notification>();
|
||||
|
||||
cpr::Response notification_post_request = cpr::Post(
|
||||
cpr::Url{fmt::format("https://ntfy.sh/{}", notif.topic)},
|
||||
cpr::Header{{"Title", notif.title}},
|
||||
cpr::Body{notif.body}
|
||||
);
|
||||
|
||||
spdlog::debug("Status code: {}", notification_post_request.status_code);
|
||||
}
|
||||
catch (const mqtt::exception& e) {
|
||||
spdlog::warn("Encountered mqtt exception: {}", e.what());
|
||||
}
|
||||
catch (const nlohmann::json::parse_error& e) {
|
||||
spdlog::warn("Encountered JSON parsing exception: {}", e.what());
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
spdlog::warn("Encountered std exception: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
client->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
6
src/daemon.hpp
Normal file
6
src/daemon.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <mqtt/client.h>
|
||||
namespace daemon_notify{
|
||||
void start(std::unique_ptr<mqtt::client> client, std::string topic);
|
||||
}
|
||||
5
src/definitions.cpp
Normal file
5
src/definitions.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "definitions.hpp"
|
||||
namespace definitions{
|
||||
|
||||
|
||||
}
|
||||
12
src/definitions.hpp
Normal file
12
src/definitions.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "json.hpp"
|
||||
namespace definitions{
|
||||
struct Notification{
|
||||
std::string title;
|
||||
std::string body;
|
||||
std::string topic;
|
||||
|
||||
};
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Notification, title, body, topic)
|
||||
|
||||
}
|
||||
25526
src/json.hpp
Normal file
25526
src/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
104
src/main.cpp
Normal file
104
src/main.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <algorithm>
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/format.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <mqtt/client.h>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include "daemon.hpp"
|
||||
#include "toml.hpp"
|
||||
int main() {
|
||||
try {
|
||||
spdlog::set_level(spdlog::level::debug);
|
||||
|
||||
// Parse config.toml
|
||||
auto config = toml::parse_file("config.toml");
|
||||
uint client_counter = {0};
|
||||
// Retrieve broker settings
|
||||
std::string server_address = config["broker"]["address"].value_or("");
|
||||
std::string client_id = config["broker"]["client_id"].value_or("");
|
||||
std::string topic = config["broker"]["topic"].value_or("");
|
||||
|
||||
// Retrieve auth settings
|
||||
std::string username = config["auth"]["username"].value_or("");
|
||||
std::string password = config["auth"]["password"].value_or("");
|
||||
|
||||
if (server_address.empty() || client_id.empty() || topic.empty()) {
|
||||
spdlog::error("Missing broker configuration in config.toml");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create MQTT client
|
||||
mqtt::client client(server_address, fmt::format("{}-{}",client_id,client_counter++));
|
||||
|
||||
// Configure connection with login
|
||||
mqtt::connect_options connOpts;
|
||||
connOpts.set_clean_session(true);
|
||||
|
||||
if (!username.empty()) {
|
||||
connOpts.set_user_name(username);
|
||||
connOpts.set_password(password);
|
||||
}
|
||||
|
||||
spdlog::info("Connecting to broker at {} with client ID '{}'", server_address, client_id);
|
||||
client.connect(connOpts);
|
||||
spdlog::info("Connected successfully.");
|
||||
|
||||
// Subscribe
|
||||
client.subscribe(topic, 1);
|
||||
spdlog::info("Subscribed to topic '{}'", topic);
|
||||
|
||||
// Publish a test message
|
||||
auto message = fmt::format("Hello from {}", client_id);
|
||||
client.publish(topic, message.data(), message.size(), 1, false);
|
||||
spdlog::info("Published message: {}", message);
|
||||
|
||||
// Receive one message
|
||||
spdlog::info("Waiting for incoming message...");
|
||||
auto msg = client.consume_message();
|
||||
if (msg) {
|
||||
spdlog::info("Received message on topic '{}': {}",
|
||||
msg->get_topic(), msg->to_string());
|
||||
} else {
|
||||
spdlog::warn("No message received.");
|
||||
}
|
||||
|
||||
// Disconnect
|
||||
client.disconnect();
|
||||
spdlog::info("Disconnected from broker for the test attempt.");
|
||||
// Start Notification Daemon (listen to that one topic, and then write to ntfy.sh)
|
||||
spdlog::info("Starting notification daemon");
|
||||
|
||||
|
||||
|
||||
std::unique_ptr<mqtt::client> daemon_mqtt_client = std::make_unique<mqtt::client>(server_address, fmt::format("{}-{}", client_id, client_counter++));
|
||||
daemon_mqtt_client->connect(connOpts);
|
||||
std::thread daemon_thread(
|
||||
[client = std::move(daemon_mqtt_client), topic]() mutable {
|
||||
daemon_notify::start(std::move(client), topic);
|
||||
}
|
||||
);
|
||||
daemon_thread.join();
|
||||
|
||||
}
|
||||
catch (const toml::parse_error& err) {
|
||||
spdlog::error("TOML parse error: {}", err.description());
|
||||
return 1;
|
||||
}
|
||||
catch (const mqtt::exception& e) {
|
||||
spdlog::error("MQTT Error: {}", e.what());
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
spdlog::error("Error: {}", e.what());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
17880
src/toml.hpp
Normal file
17880
src/toml.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user