OpenCPN Partial API docs
Loading...
Searching...
No Matches
notification_manager.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2025 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24#include <cmath>
25#include <fstream>
26#include <memory>
27#include <sstream>
28#include <vector>
29
30#include <wx/dir.h>
31#include <wx/filename.h>
32
33#include "model/base_platform.h"
35#include "model/datetime.h"
36#include "model/navutil_base.h"
37#include "model/notification.h"
39
40NotificationManager& NotificationManager::GetInstance() {
41 static NotificationManager instance;
42 return instance;
43}
44
45NotificationManager::NotificationManager() {
46 m_timeout_timer.Bind(wxEVT_TIMER, &NotificationManager::OnTimer, this,
47 m_timeout_timer.GetId());
48 m_timeout_timer.Start(1000, wxTIMER_CONTINUOUS);
49}
50
51void NotificationManager::OnTimer(wxTimerEvent& event) {
52 for (auto note : active_notifications) {
53 if (note->GetTimeoutLeft() > 0) {
54 note->DecrementTimoutCount();
55 }
56 }
57 for (auto note : active_notifications) {
58 if (note->GetTimeoutLeft() == 0) {
59 AcknowledgeNotification(note->GetGuid());
60 note->DecrementTimoutCount();
61 break;
62 }
63 }
64}
65
66void NotificationManager::ScrubNotificationDirectory(int days_to_retain) {
67 if (g_disableNotifications) return;
68 wxString note_directory = g_BasePlatform->GetPrivateDataDir() +
69 wxFileName::GetPathSeparator() + "notifications" +
70 wxFileName::GetPathSeparator();
71 if (!wxDirExists(note_directory)) return;
72
73 wxDateTime now = wxDateTime::Now();
74 wxArrayString file_list;
75 wxDir::GetAllFiles(note_directory, &file_list);
76 for (size_t i = 0; i < file_list.GetCount(); i++) {
77 wxFileName fn(file_list[i]);
78 wxTimeSpan age = now.Subtract(fn.GetModificationTime());
79 if (age.IsLongerThan(wxTimeSpan(days_to_retain * 24))) {
80 wxRemoveFile(file_list[i]);
81 }
82 }
83}
84
85void NotificationManager::PersistNotificationAsFile(
86 const std::shared_ptr<Notification> _notification) {
87 wxString note_directory = g_BasePlatform->GetPrivateDataDir() +
88 wxFileName::GetPathSeparator() + "notifications" +
89 wxFileName::GetPathSeparator();
90 if (!wxDirExists(note_directory)) wxMkdir(note_directory);
91 wxString severity_prefix = "Info_";
92 NotificationSeverity severity = _notification->GetSeverity();
93 if (severity == NotificationSeverity::kWarning)
94 severity_prefix = "Warning_";
95 else if (severity == NotificationSeverity::kCritical)
96 severity_prefix = "Critical_";
97 wxString file_name = wxString(_notification.get()->GetGuid().c_str());
98 file_name.Prepend(severity_prefix);
99 file_name.Prepend(note_directory);
100 file_name += ".txt";
101
102 wxDateTime act_time = wxDateTime(_notification->GetActivateTime());
103 wxString stime = wxString::Format(
104 "%s", ocpn::toUsrDateTimeFormat(
105 act_time, DateTimeFormatOptions().SetFormatString(
106 "$short_date $24_hour_minutes_seconds")));
107
108 std::stringstream ss;
109 ss << stime.ToStdString() << std::endl;
110 ss << _notification->GetMessage() << std::endl;
111
112 std::ofstream outputFile(file_name.ToStdString().c_str(), std::ios::out);
113 if (outputFile.is_open()) {
114 outputFile << ss.str();
115 }
116}
117
119 int rv = 0;
120 for (auto note : active_notifications) {
121 int severity = static_cast<int>(note->GetSeverity());
122 if (severity > rv) rv = severity;
123 }
124 return static_cast<NotificationSeverity>(rv);
125}
126
127std::string NotificationManager::AddNotification(
128 std::shared_ptr<Notification> _notification) {
129 if (g_disableNotifications) return "";
130
131 active_notifications.push_back(_notification);
132 PersistNotificationAsFile(_notification);
134
135 // Send notification to listeners
136 auto msg = std::make_shared<NotificationMsg>("POST", _notification);
137 AppMsgBus::GetInstance().Notify(std::move(msg));
138
139 return _notification->GetGuid();
140}
141
142std::string NotificationManager::AddNotification(NotificationSeverity _severity,
143 const std::string& _message,
144 int _timeout_secs) {
145 auto notification =
146 std::make_shared<Notification>(_severity, _message, _timeout_secs);
147 return AddNotification(notification);
148}
149
150bool NotificationManager::AcknowledgeNotification(const std::string& GUID) {
151 if (!GUID.length()) return false;
152
153 size_t target_message_hash = 0;
154 for (auto it = active_notifications.begin();
155 it != active_notifications.end();) {
156 if ((*it)->GetGuid() == GUID) {
157 target_message_hash = (*it)->GetStringHash();
158 break;
159 } else
160 ++it;
161 }
162 if (!target_message_hash) return false;
163
164 // erase multiple notifications with identical message_hash
165 bool rv = false;
166 bool done = false;
167 while (!done && active_notifications.size()) {
168 for (auto it = active_notifications.begin();
169 it != active_notifications.end();) {
170 if ((*it)->GetStringHash() == target_message_hash) {
171 // Send notification to listeners
172 auto msg = std::make_shared<NotificationMsg>("ACK", *it);
173 AppMsgBus::GetInstance().Notify(std::move(msg));
174
175 // Drop the notification
176 active_notifications.erase(it);
177
178 rv = true;
179 break;
180 } else
181 ++it;
182 if (it == active_notifications.end()) done = true;
183 }
184 }
185
186 if (rv) {
188 }
189
190 return rv;
191}
192
193bool NotificationManager::AcknowledgeAllNotifications() {
194 bool rv = false;
195
196 while (active_notifications.size()) {
197 AcknowledgeNotification(active_notifications[0]->GetGuid());
198 rv = true;
199 }
200
201 return rv;
202}
BasePlatform * g_BasePlatform
points to g_platform, handles brain-dead MS linker.
Basic platform specific support utilities without GUI deps.
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
void Notify(const std::shared_ptr< const AppMsg > &msg)
Send message to everyone listening to given message type.
void Notify() override
Notify all listeners, no data supplied.
The global list of user notifications, a singleton.
bool AcknowledgeNotification(const std::string &guid)
User ack on a notification which eventually will remove it.
EventVar evt_notificationlist_change
Notified without data when a notification is added or removed.
NotificationSeverity GetMaxSeverity()
Return max severity among current active notifications.
Decoded messages send/receive support.
Date and time utilities.
Navigation Utility Functions without GUI dependencies.
User notification container.
User notifications manager.
Configuration options for date and time formatting.