Skip to content

Commit

Permalink
feat: send notifications to sending controller on prenote timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
AndyTWF committed Oct 7, 2022
1 parent 981e8af commit b73eded
Show file tree
Hide file tree
Showing 21 changed files with 315 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/plugin/CMakeLists.txt
Expand Up @@ -699,7 +699,7 @@ set(src__prenote
prenote/PlayNewPrenoteMessageSound.cpp prenote/PlayNewPrenoteMessageSound.h
prenote/SendNewPrenoteChatAreaMessage.cpp prenote/SendNewPrenoteChatAreaMessage.h
prenote/PrenoteIsTargetedToUser.cpp prenote/PrenoteIsTargetedToUser.h
prenote/PrenoteUserRelevanceChecker.h prenote/SendPrenoteCancelledChatAreaMessage.cpp prenote/SendPrenoteCancelledChatAreaMessage.h prenote/PrenoteIsSentFromUsersPosition.cpp prenote/PrenoteIsSentFromUsersPosition.h prenote/SendPrenoteAcknowledgedChatAreaMessage.cpp prenote/SendPrenoteAcknowledgedChatAreaMessage.h)
prenote/PrenoteUserRelevanceChecker.h prenote/SendPrenoteCancelledChatAreaMessage.cpp prenote/SendPrenoteCancelledChatAreaMessage.h prenote/PrenoteIsSentFromUsersPosition.cpp prenote/PrenoteIsSentFromUsersPosition.h prenote/SendPrenoteAcknowledgedChatAreaMessage.cpp prenote/SendPrenoteAcknowledgedChatAreaMessage.h prenote/SendPrenoteTimeoutChatAreaMessage.cpp prenote/SendPrenoteTimeoutChatAreaMessage.h)
source_group("src\\prenote" FILES ${src__prenote})

set(src__push
Expand Down
9 changes: 7 additions & 2 deletions src/plugin/prenote/PrenoteMessageCollection.cpp
Expand Up @@ -52,11 +52,16 @@ namespace UKControllerPlugin::Prenote {
}
}

void
PrenoteMessageCollection::RemoveWhere(const std::function<bool(const std::shared_ptr<PrenoteMessage>&)>& predicate)
void PrenoteMessageCollection::RemoveWhere(
const std::function<bool(const std::shared_ptr<PrenoteMessage>&)>& predicate,
const std::function<void(const PrenoteMessage&)>& onRemove)
{
for (auto prenote = this->prenotes.cbegin(); prenote != this->prenotes.cend();) {
if (predicate(*prenote)) {
if (onRemove) {
onRemove(**prenote);
}

prenote = this->prenotes.erase(prenote);
} else {
++prenote;
Expand Down
4 changes: 3 additions & 1 deletion src/plugin/prenote/PrenoteMessageCollection.h
Expand Up @@ -17,7 +17,9 @@ namespace UKControllerPlugin::Prenote {
[[nodiscard]] auto GetById(int id) -> const std::shared_ptr<PrenoteMessage>&;
void Iterate(const std::function<void(const std::shared_ptr<PrenoteMessage>&)>& function);
void Remove(int id);
void RemoveWhere(const std::function<bool(const std::shared_ptr<PrenoteMessage>&)>& predicate);
void RemoveWhere(
const std::function<bool(const std::shared_ptr<PrenoteMessage>&)>& predicate,
const std::function<void(const PrenoteMessage&)>& onRemove = {});

private:
[[nodiscard]] auto GetByIdUnsafe(int id) -> const std::shared_ptr<PrenoteMessage>&;
Expand Down
8 changes: 8 additions & 0 deletions src/plugin/prenote/PrenoteMessageEventHandlerCollection.cpp
Expand Up @@ -28,6 +28,14 @@ namespace UKControllerPlugin::Prenote {
handler->MessageAcknowledged(message);
}
}

void PrenoteMessageEventHandlerCollection::MessageTimeout(const PrenoteMessage& message) const
{
for (const auto& handler : handlers) {
handler->MessageTimeout(message);
}
}

auto PrenoteMessageEventHandlerCollection::CountHandlers() const -> size_t
{
return handlers.size();
Expand Down
1 change: 1 addition & 0 deletions src/plugin/prenote/PrenoteMessageEventHandlerCollection.h
Expand Up @@ -15,6 +15,7 @@ namespace UKControllerPlugin::Prenote {
void MessageAcknowledged(const PrenoteMessage& message) const;
void MessageCancelled(const PrenoteMessage& message) const;
void NewMessage(const PrenoteMessage& message) const;
void MessageTimeout(const PrenoteMessage& message) const;

private:
// All the handlers
Expand Down
4 changes: 4 additions & 0 deletions src/plugin/prenote/PrenoteMessageEventHandlerInterface.h
Expand Up @@ -21,5 +21,9 @@ namespace UKControllerPlugin::Prenote {
virtual void MessageAcknowledged(const PrenoteMessage& message)
{
}

virtual void MessageTimeout(const PrenoteMessage& message)
{
}
};
} // namespace UKControllerPlugin::Prenote
20 changes: 13 additions & 7 deletions src/plugin/prenote/PrenoteMessageTimeout.cpp
@@ -1,23 +1,29 @@
#include "PrenoteMessage.h"
#include "PrenoteMessageCollection.h"
#include "PrenoteMessageEventHandlerCollection.h"
#include "PrenoteMessageTimeout.h"
#include "time/SystemClock.h"

using UKControllerPlugin::Time::TimeNow;

namespace UKControllerPlugin::Prenote {

PrenoteMessageTimeout::PrenoteMessageTimeout(std::shared_ptr<PrenoteMessageCollection> messages)
: messages(std::move(messages))
PrenoteMessageTimeout::PrenoteMessageTimeout(
std::shared_ptr<PrenoteMessageCollection> messages, const PrenoteMessageEventHandlerCollection& eventHandlers)
: messages(std::move(messages)), eventHandlers(eventHandlers)
{
}

void PrenoteMessageTimeout::TimedEventTrigger()
{
this->messages->RemoveWhere([](const std::shared_ptr<PrenoteMessage>& message) -> bool {
return message->IsAcknowledged()
? message->GetAcknowledgedAt() < TimeNow() - std::chrono::minutes(ACKNOWLEDGED_PRENOTE_TIMEOUT)
: message->GetExpiresAt() < TimeNow();
});
this->messages->RemoveWhere(
[](const std::shared_ptr<PrenoteMessage>& message) -> bool {
return message->IsAcknowledged() ? message->GetAcknowledgedAt() <
TimeNow() - std::chrono::minutes(ACKNOWLEDGED_PRENOTE_TIMEOUT)
: message->GetExpiresAt() < TimeNow();
},
[this](const PrenoteMessage& message) {
eventHandlers.MessageTimeout(message);
});
}
} // namespace UKControllerPlugin::Prenote
8 changes: 7 additions & 1 deletion src/plugin/prenote/PrenoteMessageTimeout.h
Expand Up @@ -3,17 +3,23 @@

namespace UKControllerPlugin::Prenote {
class PrenoteMessageCollection;
class PrenoteMessageEventHandlerCollection;

class PrenoteMessageTimeout : public UKControllerPlugin::TimedEvent::AbstractTimedEvent
{
public:
explicit PrenoteMessageTimeout(std::shared_ptr<PrenoteMessageCollection> messages);
explicit PrenoteMessageTimeout(
std::shared_ptr<PrenoteMessageCollection> messages,
const PrenoteMessageEventHandlerCollection& eventHandlers);
void TimedEventTrigger() override;

private:
// Collection of prenote messages
const std::shared_ptr<PrenoteMessageCollection> messages;

// Handlers of prenote events
const PrenoteMessageEventHandlerCollection& eventHandlers;

static const int ACKNOWLEDGED_PRENOTE_TIMEOUT = 10;
};
} // namespace UKControllerPlugin::Prenote
6 changes: 5 additions & 1 deletion src/plugin/prenote/PrenoteModule.cpp
Expand Up @@ -21,6 +21,7 @@
#include "SendPrenoteAcknowledgedChatAreaMessage.h"
#include "SendPrenoteCancelledChatAreaMessage.h"
#include "SendPrenoteMenu.h"
#include "SendPrenoteTimeoutChatAreaMessage.h"
#include "TriggerPrenoteMessageStatusView.h"
#include "bootstrap/BootstrapWarningMessage.h"
#include "bootstrap/PersistenceContainer.h"
Expand Down Expand Up @@ -96,6 +97,8 @@ namespace UKControllerPlugin::Prenote {
userTargetPrenoteRelevance, *persistence.plugin, *persistence.pluginUserSettingHandler));
persistence.prenoteMessageHandlers->AddHandler(std::make_shared<SendPrenoteAcknowledgedChatAreaMessage>(
userSendingPrenoteRelevance, *persistence.plugin, *persistence.pluginUserSettingHandler));
persistence.prenoteMessageHandlers->AddHandler(std::make_shared<SendPrenoteTimeoutChatAreaMessage>(
userSendingPrenoteRelevance, *persistence.plugin, *persistence.pluginUserSettingHandler));

// Push event processors
persistence.pushEventProcessors->AddProcessor(std::make_shared<NewPrenotePushEventHandler>(
Expand All @@ -105,7 +108,8 @@ namespace UKControllerPlugin::Prenote {
persistence.pushEventProcessors->AddProcessor(std::make_shared<PrenoteDeletedPushEventHandler>(
persistence.prenotes, *persistence.prenoteMessageHandlers));
persistence.timedHandler->RegisterEvent(
std::make_shared<PrenoteMessageTimeout>(persistence.prenotes), MESSAGE_TIMEOUT_CHECK_INTERVAL);
std::make_shared<PrenoteMessageTimeout>(persistence.prenotes, *persistence.prenoteMessageHandlers),
MESSAGE_TIMEOUT_CHECK_INTERVAL);

// Status indicator tag item
persistence.tagHandler->RegisterTagItem(
Expand Down
42 changes: 42 additions & 0 deletions src/plugin/prenote/SendPrenoteTimeoutChatAreaMessage.cpp
@@ -0,0 +1,42 @@
#include "PrenoteMessage.h"
#include "PrenoteUserRelevanceChecker.h"
#include "SendPrenoteTimeoutChatAreaMessage.h"
#include "controller/ControllerPosition.h"
#include "euroscope/EuroscopePluginLoopbackInterface.h"
#include "euroscope/GeneralSettingsEntries.h"
#include "euroscope/UserSetting.h"

namespace UKControllerPlugin::Prenote {

SendPrenoteTimeoutChatAreaMessage::SendPrenoteTimeoutChatAreaMessage(
std::shared_ptr<PrenoteUserRelevanceChecker> prenoteRelevance,
Euroscope::EuroscopePluginLoopbackInterface& plugin,
Euroscope::UserSetting& userSettings)
: prenoteRelevance(prenoteRelevance), plugin(plugin), userSettings(userSettings)
{
assert(prenoteRelevance && "Prenote relevance is nullptr");
}

void SendPrenoteTimeoutChatAreaMessage::MessageTimeout(const PrenoteMessage& message)
{
if (message.IsAcknowledged() || !UserWantsChatAreaMessages() || !prenoteRelevance->IsRelevant(message)) {
return;
}

plugin.ChatAreaMessage(
"UKCP_COORDINATION",
"UKCP",
"Prenote message to " + message.GetTargetController()->GetCallsign() + " for " + message.GetCallsign() +
" has timed out without acknowledgement.",
true,
true,
true,
true,
true);
}

auto SendPrenoteTimeoutChatAreaMessage::UserWantsChatAreaMessages() const -> bool
{
return userSettings.GetBooleanEntry(Euroscope::GeneralSettingsEntries::prenoteChatAreaMessagesSettingsKey);
}
} // namespace UKControllerPlugin::Prenote
32 changes: 32 additions & 0 deletions src/plugin/prenote/SendPrenoteTimeoutChatAreaMessage.h
@@ -0,0 +1,32 @@
#pragma once
#include "PrenoteMessageEventHandlerInterface.h"

namespace UKControllerPlugin::Euroscope {
class EuroscopePluginLoopbackInterface;
class UserSetting;
} // namespace UKControllerPlugin::Euroscope

namespace UKControllerPlugin::Prenote {
class PrenoteUserRelevanceChecker;

class SendPrenoteTimeoutChatAreaMessage : public PrenoteMessageEventHandlerInterface
{
public:
SendPrenoteTimeoutChatAreaMessage(
std::shared_ptr<PrenoteUserRelevanceChecker> prenoteRelevance,
Euroscope::EuroscopePluginLoopbackInterface& plugin,
Euroscope::UserSetting& userSettings);
void MessageTimeout(const PrenoteMessage& message) override;

private:
[[nodiscard]] auto UserWantsChatAreaMessages() const -> bool;
// Checks relevance of prenotes
const std::shared_ptr<PrenoteUserRelevanceChecker> prenoteRelevance;

// For sending messages
Euroscope::EuroscopePluginLoopbackInterface& plugin;

// User settings
Euroscope::UserSetting& userSettings;
};
} // namespace UKControllerPlugin::Prenote
2 changes: 1 addition & 1 deletion test/plugin/CMakeLists.txt
Expand Up @@ -451,7 +451,7 @@ set(test__prenote
prenote/PrenoteIsTargetedToUserTest.cpp
prenote/SendNewPrenoteChatAreaMessageTest.cpp
prenote/SendPrenoteCancelledChatAreaMessageTest.cpp
prenote/PrenoteIsSentFromUserPositionTest.cpp prenote/SendPrenoteAcknowledgedChatAreaMessageTest.cpp)
prenote/PrenoteIsSentFromUserPositionTest.cpp prenote/SendPrenoteAcknowledgedChatAreaMessageTest.cpp prenote/SendPrenoteTimeoutChatAreaMessageTest.cpp)
source_group("test\\prenote" FILES ${test__prenote})

set(test__push
Expand Down
1 change: 1 addition & 0 deletions test/plugin/mock/MockPrenoteMessageEventHandlerInterface.h
Expand Up @@ -12,5 +12,6 @@ namespace UKControllerPluginTest::Prenote {
MOCK_METHOD(void, NewMessage, (const PrenoteMessage&), (override));
MOCK_METHOD(void, MessageCancelled, (const PrenoteMessage&), (override));
MOCK_METHOD(void, MessageAcknowledged, (const PrenoteMessage&), (override));
MOCK_METHOD(void, MessageTimeout, (const PrenoteMessage&), (override));
};
} // namespace UKControllerPluginTest::Prenote
2 changes: 1 addition & 1 deletion test/plugin/prenote/AcknowledgePrenoteMessageTest.cpp
Expand Up @@ -39,7 +39,7 @@ namespace UKControllerPluginTest::Prenote {
userPosition = std::make_shared<ControllerPosition>(
2, "LON_S_CTR", 129.420, std::vector<std::string>{"EGKK"}, true, false, true);
callsigns.AddUserCallsign(ActiveCallsign("LON_S_CTR", "Test", *userPosition, true));

// Add the prenotes
collection->Add(std::make_shared<PrenoteMessage>(
1, "BAW123", "EGGD", "BADIM1X", "EGLL", sendingPosition, userPosition, TimeNow()));
Expand Down
6 changes: 3 additions & 3 deletions test/plugin/prenote/NewPrenotePushEventHandlerTest.cpp
Expand Up @@ -96,7 +96,7 @@ namespace UKControllerPluginTest::Prenote {
TEST_F(NewPrenotePushEventHandlerTest, ItAddsPrenoteFromMessageWithOptionalData)
{
EXPECT_CALL(*mockHandler, NewMessage(testing::_)).Times(1);

this->handler.ProcessPushEvent(MakePushEvent(nlohmann::json{
{"departure_sid", nlohmann::json::value_t::null},
{"destination_airfield", nlohmann::json::value_t::null},
Expand All @@ -123,11 +123,11 @@ namespace UKControllerPluginTest::Prenote {
EXPECT_EQ(1, this->messages->Count());
EXPECT_TRUE(this->messages->GetById(1)->IsAcknowledged());
}

TEST_F(NewPrenotePushEventHandlerTest, ItTriggersNewMessageEventIfPrenoteExists)
{
EXPECT_CALL(*mockHandler, NewMessage(testing::_)).Times(2);

this->handler.ProcessPushEvent(MakePushEvent());
this->messages->GetById(1)->Acknowledge();
this->handler.ProcessPushEvent(MakePushEvent());
Expand Down
4 changes: 2 additions & 2 deletions test/plugin/prenote/PrenoteDeletedPushEventHandlerTest.cpp
Expand Up @@ -24,8 +24,8 @@ namespace UKControllerPluginTest::Prenote {
receivingPosition = std::make_shared<ControllerPosition>(
2, "EGKK_F_APP", 124.225, std::vector<std::string>{"EGKK"}, true, false);
this->messages->Add(std::make_shared<PrenoteMessage>(
1,+
"BAW123",
1,
+"BAW123",
"EGGD",
"BADIM1X",
"EGLL",
Expand Down
19 changes: 18 additions & 1 deletion test/plugin/prenote/PrenoteMessageCollectionTest.cpp
Expand Up @@ -21,14 +21,17 @@ namespace UKControllerPluginTest::Prenote {
message1 = std::make_shared<PrenoteMessage>(
1, "BAW123", "EGGD", "BADIM1X", "EGLL", sendingPosition, receivingPosition, TimeNow());
message2 = std::make_shared<PrenoteMessage>(
5, "BAW456", "EGGD", "BADIM1X", "EGLL", sendingPosition, receivingPosition, TimeNow());
5, "BAW456", "EGGD", "BADIM1X", "EGKK", sendingPosition, receivingPosition, TimeNow());
message3 = std::make_shared<PrenoteMessage>(
3, "BAW456", "EGGD", "BADIM1X", "EGLL", sendingPosition, receivingPosition, TimeNow());
}

std::shared_ptr<ControllerPosition> sendingPosition;
std::shared_ptr<ControllerPosition> receivingPosition;
PrenoteMessageCollection collection;
std::shared_ptr<PrenoteMessage> message1;
std::shared_ptr<PrenoteMessage> message2;
std::shared_ptr<PrenoteMessage> message3;
};

TEST_F(PrenoteMessageCollectionTest, ItStartsEmpty)
Expand Down Expand Up @@ -128,4 +131,18 @@ namespace UKControllerPluginTest::Prenote {
EXPECT_EQ(0, collection.Count());
EXPECT_EQ(nullptr, collection.GetById(5));
}

TEST_F(PrenoteMessageCollectionTest, ItemsRemovedByPredicateArePassedToCallback)
{
std::vector<int> prenoteIds;
collection.Add(message1);
collection.Add(message2);
collection.Add(message3);
collection.RemoveWhere(
[](const std::shared_ptr<PrenoteMessage>& message) { return message->GetDestinationAirfield() == "EGLL"; },
[&prenoteIds](const PrenoteMessage& message) { prenoteIds.push_back(message.GetId()); });

EXPECT_EQ(1, collection.Count());
EXPECT_EQ(std::vector<int>({1, 3}), prenoteIds);
}
} // namespace UKControllerPluginTest::Prenote
17 changes: 17 additions & 0 deletions test/plugin/prenote/PrenoteMessageEventHandlerCollectionTest.cpp
Expand Up @@ -75,4 +75,21 @@ namespace UKControllerPluginTest::Prenote {

collection.MessageAcknowledged(message);
}

TEST_F(PrenoteMessageEventHandlerCollectionTest, ItProcessesTimeoutMessageEvent)
{
auto handler1 = std::make_shared<testing::NiceMock<MockPrenoteMessageEventHandlerInterface>>();
auto handler2 = std::make_shared<testing::NiceMock<MockPrenoteMessageEventHandlerInterface>>();
collection.AddHandler(handler1);
collection.AddHandler(handler2);

const PrenoteMessage message(
1, "BAW123", "EGKK", "TEST1A", "EGLL", nullptr, nullptr, std::chrono::system_clock::now());

EXPECT_CALL(*handler1, MessageTimeout(testing::Ref(message))).Times(1);

EXPECT_CALL(*handler2, MessageTimeout(testing::Ref(message))).Times(1);

collection.MessageTimeout(message);
}
} // namespace UKControllerPluginTest::Prenote

0 comments on commit b73eded

Please sign in to comment.