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 wxString note_directory = g_BasePlatform->GetPrivateDataDir() +
68 wxFileName::GetPathSeparator() + "notifications" +
69 wxFileName::GetPathSeparator();
70 if (!wxDirExists(note_directory)) return;
71
72 wxDateTime now = wxDateTime::Now();
73 wxArrayString file_list;
74 wxDir::GetAllFiles(note_directory, &file_list);
75 for (size_t i = 0; i < file_list.GetCount(); i++) {
76 wxFileName fn(file_list[i]);
77 wxTimeSpan age = now.Subtract(fn.GetModificationTime());
78 if (age.IsLongerThan(wxTimeSpan(days_to_retain * 24))) {
79 wxRemoveFile(file_list[i]);
80 }
81 }
82}
83
84void NotificationManager::PersistNotificationAsFile(
85 const std::shared_ptr<Notification> _notification) {
86 wxString note_directory = g_BasePlatform->GetPrivateDataDir() +
87 wxFileName::GetPathSeparator() + "notifications" +
88 wxFileName::GetPathSeparator();
89 if (!wxDirExists(note_directory)) wxMkdir(note_directory);
90 wxString severity_prefix = "Info_";
91 NotificationSeverity severity = _notification->GetSeverity();
92 if (severity == NotificationSeverity::kWarning)
93 severity_prefix = "Warning_";
94 else if (severity == NotificationSeverity::kCritical)
95 severity_prefix = "Critical_";
96 wxString file_name = wxString(_notification.get()->GetGuid().c_str());
97 file_name.Prepend(severity_prefix);
98 file_name.Prepend(note_directory);
99 file_name += ".txt";
100
101 wxDateTime act_time = wxDateTime(_notification->GetActivateTime());
102 wxString stime = wxString::Format(
103 "%s", ocpn::toUsrDateTimeFormat(
104 act_time, DateTimeFormatOptions().SetFormatString(
105 "$short_date $24_hour_minutes_seconds")));
106
107 std::stringstream ss;
108 ss << stime.ToStdString() << std::endl;
109 ss << _notification->GetMessage() << std::endl;
110
111 std::ofstream outputFile(file_name.ToStdString().c_str(), std::ios::out);
112 if (outputFile.is_open()) {
113 outputFile << ss.str();
114 }
115}
116
118 int rv = 0;
119 for (auto note : active_notifications) {
120 int severity = static_cast<int>(note->GetSeverity());
121 if (severity > rv) rv = severity;
122 }
123 return static_cast<NotificationSeverity>(rv);
124}
125
126std::string NotificationManager::AddNotification(
127 std::shared_ptr<Notification> _notification) {
128 active_notifications.push_back(_notification);
129 PersistNotificationAsFile(_notification);
131
132 // Send notification to listeners
133 auto msg = std::make_shared<NotificationMsg>("POST", _notification);
134 AppMsgBus::GetInstance().Notify(std::move(msg));
135
136 return _notification->GetGuid();
137}
138
139std::string NotificationManager::AddNotification(NotificationSeverity _severity,
140 const std::string& _message,
141 int _timeout_secs) {
142 auto notification =
143 std::make_shared<Notification>(_severity, _message, _timeout_secs);
144 return AddNotification(notification);
145}
146
147bool NotificationManager::AcknowledgeNotification(const std::string& GUID) {
148 if (!GUID.length()) return false;
149
150 size_t target_message_hash = 0;
151 for (auto it = active_notifications.begin();
152 it != active_notifications.end();) {
153 if ((*it)->GetGuid() == GUID) {
154 target_message_hash = (*it)->GetStringHash();
155 break;
156 } else
157 ++it;
158 }
159 if (!target_message_hash) return false;
160
161 // erase multiple notifications with identical message_hash
162 bool rv = false;
163 bool done = false;
164 while (!done && active_notifications.size()) {
165 for (auto it = active_notifications.begin();
166 it != active_notifications.end();) {
167 if ((*it)->GetStringHash() == target_message_hash) {
168 // Send notification to listeners
169 auto msg = std::make_shared<NotificationMsg>("ACK", *it);
170 AppMsgBus::GetInstance().Notify(std::move(msg));
171
172 // Drop the notification
173 active_notifications.erase(it);
174
175 rv = true;
176 break;
177 } else
178 ++it;
179 if (it == active_notifications.end()) done = true;
180 }
181 }
182
183 if (rv) {
185 }
186
187 return rv;
188}
189
190bool NotificationManager::AcknowledgeAllNotifications() {
191 bool rv = false;
192
193 while (active_notifications.size()) {
194 AcknowledgeNotification(active_notifications[0]->GetGuid());
195 rv = true;
196 }
197
198 return rv;
199}
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.