← Documentation
ADS-IDAC Engine 5.0.0
Notification.cpp
Go to the documentation of this file.
1
3
4#include "Notification.h"
5#include <cstdlib>
6#include <sstream>
7#include <iostream>
8#include <iomanip>
9#include <functional>
10#include <unistd.h>
11using namespace std;
12
15
17static std::string format_time(double seconds) {
18 std::ostringstream ss;
19 if (seconds < 60.0) {
20 ss << std::fixed << std::setprecision(1) << seconds << "s";
21 } else if (seconds < 3600.0) {
22 int m = static_cast<int>(seconds) / 60;
23 double s = seconds - m * 60;
24 ss << m << "m " << std::fixed << std::setprecision(0) << s << "s";
25 } else {
26 int h = static_cast<int>(seconds) / 3600;
27 int m = (static_cast<int>(seconds) % 3600) / 60;
28 ss << h << "h " << m << "m";
29 }
30 return ss.str();
31}
32
34static std::string project_name(const std::string& path) {
35 auto pos = path.find_last_of('/');
36 if (pos != std::string::npos && pos + 1 < path.size())
37 return path.substr(pos + 1);
38 return path;
39}
40
41static void send_ntfy(const std::string& topic, const RunSummary& summary) {
42 std::string name = project_name(summary.project);
43 std::string time_str = format_time(summary.wall_seconds);
44
45 std::ostringstream body;
46 body << name << ": " << summary.sequences << " sequences, "
47 << time_str << " wall time";
48 if (summary.ranks > 1)
49 body << " (" << summary.ranks << " ranks)";
50
51 // curl -s --max-time 10 -H "Title: ADS-IDAC Complete" -H "Tags: white_check_mark"
52 // -d "<body>" ntfy.sh/<topic>
53 std::ostringstream cmd;
54 cmd << "curl -s --max-time 10"
55 << " -H \"Title: ADS-IDAC Complete\""
56 << " -H \"Tags: white_check_mark\""
57 << " -d \"" << body.str() << "\""
58 << " ntfy.sh/" << topic
59 << " > /dev/null 2>&1";
60
61 int rc = std::system(cmd.str().c_str());
62 if (rc != 0)
63 std::cerr << "[notify] ntfy.sh notification failed (curl exit " << rc << ")" << std::endl;
64 else
65 std::cout << "[notify] Sent ntfy.sh notification to topic '" << topic << "'" << std::endl;
66}
67
68static void send_discord(const std::string& webhook_url, const RunSummary& summary) {
69 std::string name = project_name(summary.project);
70 std::string time_str = format_time(summary.wall_seconds);
71
72 // Build Discord embed JSON — all field values are controlled strings, no escaping needed
73 std::ostringstream json;
74 json << "{\"embeds\":[{\"title\":\"ADS-IDAC Simulation Complete\","
75 << "\"color\":5763719," // green (#57F287)
76 << "\"fields\":["
77 << "{\"name\":\"Project\",\"value\":\"" << name << "\",\"inline\":true},"
78 << "{\"name\":\"Sequences\",\"value\":\"" << summary.sequences << "\",\"inline\":true},"
79 << "{\"name\":\"Wall Time\",\"value\":\"" << time_str << "\",\"inline\":true},"
80 << "{\"name\":\"Ranks\",\"value\":\"" << summary.ranks << "\",\"inline\":true},"
81 << "{\"name\":\"Solver\",\"value\":\"" << summary.solver << "\",\"inline\":true},"
82 << "{\"name\":\"Truncation\",\"value\":\"T=" << std::fixed << std::setprecision(1)
83 << summary.truncation_time << "\",\"inline\":true}"
84 << "]}]}";
85
86 // curl -s --max-time 10 -H "Content-Type: application/json" -d '<json>' <url>
87 std::ostringstream cmd;
88 cmd << "curl -s --max-time 10"
89 << " -H \"Content-Type: application/json\""
90 << " -d '" << json.str() << "'"
91 << " " << webhook_url
92 << " > /dev/null 2>&1";
93
94 int rc = std::system(cmd.str().c_str());
95 if (rc != 0)
96 std::cerr << "[notify] Discord notification failed (curl exit " << rc << ")" << std::endl;
97 else
98 std::cout << "[notify] Sent Discord notification" << std::endl;
99}
100
101std::string auto_ntfy_topic() {
102 char buf[256];
103 if (gethostname(buf, sizeof(buf)) != 0)
104 std::snprintf(buf, sizeof(buf), "unknown");
105 size_t h = std::hash<std::string>{}(buf);
106 char topic[16];
107 std::snprintf(topic, sizeof(topic), "ads%04x", static_cast<unsigned>(h & 0xFFFF));
108 return topic;
109}
110
112 if (!notify_ntfy_topic.empty())
114 if (!notify_discord_webhook.empty())
116}
void send_completion_notification(const RunSummary &summary)
Send completion notifications to all configured targets. Non-fatal: prints a warning if curl fails,...
static std::string project_name(const std::string &path)
Extract the last path component as the project name.
std::string notify_discord_webhook
static std::string format_time(double seconds)
Format wall time as human-readable string.
static void send_ntfy(const std::string &topic, const RunSummary &summary)
static void send_discord(const std::string &webhook_url, const RunSummary &summary)
std::string auto_ntfy_topic()
Generate a default ntfy topic name: "ads" + 4 hex chars from hostname hash. Example: "ads7f3a".
std::string notify_ntfy_topic
Global notification targets (set by Scheduler::parseOptions).
Send completion notifications via ntfy.sh or Discord webhooks.
nlohmann::json json
Summary of a completed simulation run.
Definition: Notification.h:8
std::string solver
Definition: Notification.h:13
std::string project
Definition: Notification.h:9
double truncation_time
Definition: Notification.h:14
double wall_seconds
Definition: Notification.h:11