RTC Toolkit 5.0.0
Loading...
Searching...
No Matches
supervisory.hpp
Go to the documentation of this file.
1
13#ifndef RTCTK_RTCSUPERVISOR_SUPERVISORY_HPP
14#define RTCTK_RTCSUPERVISOR_SUPERVISORY_HPP
15
20
22
23namespace rtctk::rtcSupervisor {
24
25using namespace rtctk::componentFramework;
26
27namespace detail {
39public:
46 explicit SetModesContext(const rad::cii::Request<std::string, std::string>& request)
47 : m_logger(GetLogger("rtctk")), m_request(request), m_arg() {
48 m_arg = JsonPayload::parse(m_request.GetRequestPayload());
49 }
51
56 return m_arg;
57 }
58
63 try {
64 m_request.SetReplyValue(STD_OK_REPLY);
65 } catch (const std::exception& exception) {
67 m_logger, "SetModesContext::SendReply: Failed to send reply: " << exception.what());
68 } catch (...) {
70 m_logger,
71 "SetModesContext::SendReply: Failed to send reply with unknown exception.");
72 }
73 }
74
80 void SendErrorReply(std::exception_ptr eptr) noexcept {
81 try {
82 m_request.SetException(RequestFailed(NestedExceptionPrinter(std::move(eptr)).Str()));
83 } catch (...) {
85 m_logger,
86 "SetModesContext::SendErrorReply: Failed to send reply with unknown exception.");
87 }
88 }
89
90private:
91 log4cplus::Logger& m_logger;
92
94 rad::cii::Request<std::string, std::string> m_request;
98 JsonPayload m_arg;
99};
111public:
118 explicit WriteBackContext(const rad::cii::Request<std::string, std::string>& request)
119 : m_logger(GetLogger("rtctk")), m_request(request), m_arg() {
120 m_arg = JsonPayload::parse(m_request.GetRequestPayload());
121 }
123
128 return m_arg;
129 }
130
135 try {
136 m_request.SetReplyValue(STD_OK_REPLY);
137 } catch (const std::exception& exception) {
139 m_logger,
140 "WriteBackContext::SendReply: Failed to send reply: " << exception.what());
141 } catch (...) {
143 m_logger,
144 "WriteBackContext::SendReply: Failed to send reply with unknown exception.");
145 }
146 }
147
153 void SendErrorReply(std::exception_ptr eptr) noexcept {
154 try {
155 m_request.SetException(RequestFailed(NestedExceptionPrinter(std::move(eptr)).Str()));
156 } catch (...) {
158 m_logger,
159 "WriteBackContext::SendErrorReply: Failed to send reply with unknown exception.");
160 }
161 }
162
167 try {
168 m_request.SetException(StdIfRequestAborted());
169 } catch (...) {
171 m_logger,
172 "SetModesContext::SendStopReply: Failed to send reply with unknown exception.");
173 }
174 }
175
176private:
177 log4cplus::Logger& m_logger;
178
180 rad::cii::Request<std::string, std::string> m_request;
184 JsonPayload m_arg;
185};
186} // namespace detail
187
212template <typename Super>
214 static_assert(std::is_base_of_v<RtcComponent, Super>, "'Supervisory' requires 'RtcComponent'");
215
221 public:
229 virtual std::string ActionGetStatus() {
230 return {};
231 }
243 }
254 return true;
255 }
266 }
267
276 return {};
277 }
278
287 return {};
288 }
289
298 return {};
299 }
311 }
323 return true;
324 }
335 }
336 };
337
342 public:
344
345 void Start() override {
346 Super::InputStage::Start();
347
348 RecoverCmdsImpl::Register(this->m_replier, this->m_engine);
349 ModeCmdsImpl::Register(this->m_replier, this->m_engine);
350 WriteBackCmdsImpl::Register(this->m_replier, this->m_engine);
351 }
352 };
353
358 public:
360 // Handlers ###################################################################
361
362 engine.RegisterRejectHandler<events::SetModes, RequestRejected>();
363 engine.RegisterRejectHandler<events::SetDeferredModes, RequestRejected>();
364 engine.RegisterRejectHandler<events::GetDeferredModes, RequestRejected>();
365 engine.RegisterRejectHandler<events::GetAvailableModes, RequestRejected>();
366 engine.RegisterRejectHandler<events::GetActiveModes, RequestRejected>();
367 engine.RegisterRejectHandler<events::WriteBack, RequestRejected>();
368 engine.RegisterRejectHandler<events::Recover, RequestRejected>();
369
371 this->m_engine.PostEvent(std::make_unique<events::SetModesDone>());
372 };
373
374 m_setmode_error_handler = [this](std::exception_ptr eptr) {
375 this->m_engine.PostEvent(std::make_unique<events::SetModesError>(std::move(eptr)));
376 };
377
379 this->m_engine.PostEvent(std::make_unique<events::WriteBackDone>());
380 };
381
382 m_writeback_error_handler = [this](std::exception_ptr eptr) {
383 this->m_engine.PostEvent(std::make_unique<events::WriteBackError>(std::move(eptr)));
384 };
385
386 // No Disable in states ###############################################################
387
388 this->m_no_disable_in_states.push_back("On:SetModes:Busy");
389
390 // No Update in states ################################################################
391
392 this->m_no_update_in_states.push_back("On:SetModes:Busy");
393
394 // No SetModes in states ##############################################################
395
396 this->m_no_setmode_in_states.push_back("On:Update:Busy");
397 this->m_no_setmode_in_states.push_back("On:WriteBack:Busy");
398 this->m_no_setmode_in_states.push_back("On::NotOperational::Starting");
399 this->m_no_setmode_in_states.push_back("On::NotOperational::NotReady");
400 this->m_no_setmode_in_states.push_back("On::NotOperational::Initialising");
401 this->m_no_setmode_in_states.push_back("On::NotOperational::Enabling");
402 this->m_no_setmode_in_states.push_back("On::NotOperational::Disabling");
403 this->m_no_setmode_in_states.push_back("On::Operational::Error");
404 this->m_no_setmode_in_states.push_back("On::Operational::Recovering");
405
406 // No WriteBack in states #############################################################
407
408 this->m_no_writeback_in_states.push_back("On::NotOperational::Starting");
409 this->m_no_writeback_in_states.push_back("On::NotOperational::NotReady");
410 this->m_no_writeback_in_states.push_back("On::NotOperational::Initialising");
411 this->m_no_writeback_in_states.push_back("On::NotOperational::Enabling");
412 this->m_no_writeback_in_states.push_back("On::NotOperational::Disabling");
413 this->m_no_writeback_in_states.push_back("On:SetModes:Busy");
414
415 // Guards #####################################################################
416
417 engine.RegisterGuardStatic<events::SetModes>(
418 "GuardSettingModesAllowed", [this](const events::SetModes& ev) -> bool {
427 auto act_state = this->m_engine.GetState();
428 for (auto& s : m_no_setmode_in_states) {
429 if (act_state.find(s) != std::string::npos) {
430 return false;
431 }
432 }
433 detail::SetModesContext ctx(ev.GetPayload());
434 if (static_cast<BizLogicIf&>(this->m_logic)
435 .GuardSettingModesAllowed(ctx.GetArg())) {
436 // SetModes is allowed so context is stored.
437 // If there's an active context (and correspondingly an active
438 // request being processed something have gone terribly wrong)
440 m_setmode_ctx.emplace(std::move(ctx));
441 return true;
442 }
443 return false;
444 });
445
446 engine.RegisterGuardStatic<events::WriteBack>(
447 "GuardWritingBackAllowed", [this](const events::WriteBack& ev) -> bool {
456 auto act_state = this->m_engine.GetState();
457 for (auto& s : m_no_writeback_in_states) {
458 if (act_state.find(s) != std::string::npos) {
459 return false;
460 }
461 }
462 detail::WriteBackContext ctx(ev.GetPayload());
463 if (static_cast<BizLogicIf&>(this->m_logic)
464 .GuardWritingBackAllowed(ctx.GetArg())) {
465 // WriteBack is allowed so context is stored.
466 // If there's an active context (and correspondingly an active
467 // request being processed something have gone terribly wrong)
469 m_writeback_ctx.emplace(std::move(ctx));
470 return true;
471 }
472 return false;
473 });
474
475 // Activities #####################################################################
476
477 engine.RegisterActivity(
478 "ActivitySettingModes",
479 [this](StopToken stop_token) {
481 static_cast<BizLogicIf&>(this->m_logic)
482 .ActivitySettingModes(stop_token, m_setmode_ctx->GetArg());
483 },
486
487 engine.RegisterActivity(
488 "ActivityWritingBack",
489 [this](StopToken stop_token) {
491 static_cast<BizLogicIf&>(this->m_logic)
492 .ActivityWritingBack(stop_token, m_writeback_ctx->GetArg());
493 },
496
497 engine.RegisterActivity(
498 "ActivityRecovering",
499 [this](StopToken stop_token) {
500 static_cast<BizLogicIf&>(this->m_logic).ActivityRecovering(stop_token);
501 },
502 this->m_success_handler,
503 this->m_error_handler);
504
505 // Actions #####################################################################
506
507 // override default implementation for ActionGetStatus in stdComponent.hpp
508 engine.RegisterAction("ActionGetStatus", [this](auto c) {
510 if (req == nullptr) {
511 // no event or request
512 return;
513 }
514 auto status = static_cast<BizLogicIf&>(this->m_logic).ActionGetStatus();
515 req->SetReplyValue(status);
516 });
517
518 engine.RegisterActionStatic<events::SetDeferredModes>(
519 "ActionSetDeferredModes", [this](const events::SetDeferredModes& ev) {
521 if (req == nullptr) {
522 // no event or request
523 return;
524 }
525 try {
526 auto json_arg = JsonPayload::parse(req->GetRequestPayload());
527 static_cast<BizLogicIf&>(this->m_logic).ActionSetDeferredModes(json_arg);
528 req->SetReplyValue(STD_OK_REPLY);
529 } catch (...) {
530 auto nested =
531 WrapWithNested(RtctkException("ActionSetDeferredModes: failed"));
532 auto eptr = std::make_exception_ptr(nested);
533 req->SetException(
534 RequestFailed(NestedExceptionPrinter(std::move(eptr)).Str()));
535 throw; // to be caught in stateMachineEngine.cpp
536 }
537 });
538
539 engine.RegisterActionStatic<events::GetAvailableModes>(
540 "ActionGetAvailableModes", [this](const events::GetAvailableModes& ev) {
542 if (req == nullptr) {
543 // no event or request
544 return;
545 }
546 try {
547 auto result =
548 static_cast<BizLogicIf&>(this->m_logic).ActionGetAvailableModes();
549 req->SetReplyValue(result.dump());
550 } catch (...) {
551 auto nested =
552 WrapWithNested(RtctkException("ActionGetAvailableModes: failed"));
553 auto eptr = std::make_exception_ptr(nested);
554 req->SetException(
555 RequestFailed(NestedExceptionPrinter(std::move(eptr)).Str()));
556 throw; // to be caught in stateMachineEngine.cpp
557 }
558 });
559
560 engine.RegisterActionStatic<events::GetActiveModes>(
561 "ActionGetActiveModes", [this](const events::GetActiveModes& ev) {
563 if (req == nullptr) {
564 // no event or request
565 return;
566 }
567 try {
568 auto result =
569 static_cast<BizLogicIf&>(this->m_logic).ActionGetActiveModes();
570 req->SetReplyValue(result.dump());
571 } catch (...) {
572 auto nested =
573 WrapWithNested(RtctkException("ActionGetActiveModes: failed"));
574 auto eptr = std::make_exception_ptr(nested);
575 req->SetException(
576 RequestFailed(NestedExceptionPrinter(std::move(eptr)).Str()));
577 throw; // to be caught in stateMachineEngine.cpp
578 }
579 });
580
581 engine.RegisterActionStatic<events::GetDeferredModes>(
582 "ActionGetDeferredModes", [this](const events::GetDeferredModes& ev) {
584 if (req == nullptr) {
585 // no event or request
586 return;
587 }
588 try {
589 auto result =
590 static_cast<BizLogicIf&>(this->m_logic).ActionGetDeferredModes();
591 req->SetReplyValue(result.dump());
592 } catch (...) {
593 auto nested =
594 WrapWithNested(RtctkException("ActionGetDeferredModes: failed"));
595 auto eptr = std::make_exception_ptr(nested);
596 req->SetException(
597 RequestFailed(NestedExceptionPrinter(std::move(eptr)).Str()));
598 throw; // to be caught in stateMachineEngine.cpp
599 }
600 });
601
602 engine.RegisterActionStatic<events::SetModesDone>("ActionSettingModesDone",
603 [this](const events::SetModesDone&) {
605 m_setmode_ctx->SendReply();
606 m_setmode_ctx.reset();
607 });
608
609 engine.RegisterActionStatic<events::SetModesError>(
610 "ActionSettingModesFailed", [this](const events::SetModesError& ev) {
611 m_setmode_ctx->SendErrorReply(ev.GetPayload());
612 m_setmode_ctx.reset();
613 });
614
615 engine.RegisterActionStatic<events::WriteBackDone>(
616 "ActionWriteBackDone", [this](const events::WriteBackDone&) {
618 m_writeback_ctx->SendReply();
619 m_writeback_ctx.reset();
620 });
621
622 engine.RegisterActionStatic<events::WriteBackError>(
623 "ActionWriteBackFailed", [this](const events::WriteBackError& ev) {
624 m_writeback_ctx->SendErrorReply(ev.GetPayload());
625 m_writeback_ctx.reset();
626 });
627
628 engine.RegisterActionStatic<events::Stop>(
629 "ActionWriteBackStopped", [this](const events::Stop& ev) {
631 if (req == nullptr) {
632 // no event or request
633 return;
634 }
635 m_writeback_ctx->SendStopReply();
636 m_writeback_ctx.reset();
637 req->SetReplyValue(STD_OK_REPLY);
638 });
639
640 engine.RegisterAction("ActionRecoveringEntry", [this](auto c) {
641 this->m_tmp_request = GetPayloadNothrow<events::Recover>(c);
642 });
643
644 engine.RegisterAction("ActionRecoveringDone", [this](auto c) {
645 if (this->m_tmp_request) {
646 this->m_tmp_request->SetReplyValue(STD_OK_REPLY);
647 this->m_tmp_request = nullptr;
648 }
649 });
650
651 engine.RegisterAction("ActionRecoveringFailed", [this](auto c) {
653 if (this->m_tmp_request) {
654 this->m_tmp_request->SetException(
656 this->m_tmp_request = nullptr;
657 }
658 }
659 });
660 }
661
662 protected:
663 std::optional<detail::SetModesContext> m_setmode_ctx;
664 std::optional<detail::WriteBackContext> m_writeback_ctx;
666 std::function<void(std::exception_ptr)> m_setmode_error_handler;
668 std::function<void(std::exception_ptr)> m_writeback_error_handler;
669 std::list<std::string> m_no_setmode_in_states;
670 std::list<std::string> m_no_writeback_in_states;
671 };
672
677 public:
679 // clang-format off
680 this->mm.AddState(Composite, "On:SetModes", "On");
681 this->mm.AddState(Initial, "On:SetModes:Initial", "On:SetModes");
682 this->mm.AddState(Simple, "On:SetModes:Idle", "On:SetModes");
683 this->mm.AddState(Simple, "On:SetModes:Busy", "On:SetModes", "ActivitySettingModes");
684 this->mm.AddState(Initial, "On::Operational::Initial", "On::Operational");
685 this->mm.AddState(Simple, "On::Operational::Idle", "On::Operational");
686 this->mm.AddState(Simple, "On::Operational::Recovering", "On::Operational", "ActivityRecovering", "ActionRecoveringEntry");
687 this->mm.AddState(Simple, "On::Operational::Error", "On::Operational");
688
689 this->mm.AddTrans("On", "" , events::GetAvailableModes::ID, "", "ActionGetAvailableModes");
690 this->mm.AddTrans("On::NotOperational::NotReady", "" , events::SetDeferredModes::ID, "", "ActionSetDeferredModes");
691 this->mm.AddTrans("On::NotOperational::NotReady", "" , events::GetDeferredModes::ID, "", "ActionGetDeferredModes");
692 this->mm.AddTrans("On::NotOperational::Ready", "" , events::GetActiveModes::ID, "", "ActionGetActiveModes");
693 this->mm.AddTrans("On::NotOperational::Enabling", "" , events::GetActiveModes::ID, "", "ActionGetActiveModes");
694 this->mm.AddTrans("On::Operational", "" , events::GetActiveModes::ID, "", "ActionGetActiveModes");
695
696 this->mm.AddTrans("On::Operational::Initial" , "On::Operational::Idle" );
697 this->mm.AddTrans("On::Operational::Idle" , "On::Operational::Recovering" , "events.Recover");
698 this->mm.AddTrans("On::Operational::Error" , "On::Operational::Recovering" , "events.Recover");
699 this->mm.AddTrans("On::Operational::Recovering" , "On::Operational::Idle" , "events.Done", "" ,"ActionRecoveringDone");
700 this->mm.AddTrans("On::Operational::Recovering" , "On::Operational::Error" , "events.Error", "" ,"ActionRecoveringFailed");
701
702 this->mm.AddTrans("On:SetModes:Initial", "On:SetModes:Idle");
703 this->mm.AddTrans("On:SetModes:Idle", "On:SetModes:Busy", events::SetModes::ID, "GuardSettingModesAllowed");
704 this->mm.AddTrans("On:SetModes:Busy", "On:SetModes:Idle", events::SetModesDone::ID, "", "ActionSettingModesDone");
705 this->mm.AddTrans("On:SetModes:Busy", "On:SetModes:Idle", events::SetModesError::ID, "", "ActionSettingModesFailed");
706
707 this->mm.AddState(Composite, "On:WriteBack", "On");
708 this->mm.AddState(Initial, "On:WriteBack:Initial", "On:WriteBack");
709 this->mm.AddState(Simple, "On:WriteBack:Idle", "On:WriteBack");
710 this->mm.AddState(Simple, "On:WriteBack:Busy", "On:WriteBack", "ActivityWritingBack");
711
712 this->mm.AddTrans("On:WriteBack:Initial", "On:WriteBack:Idle");
713 this->mm.AddTrans("On:WriteBack:Idle", "On:WriteBack:Busy", events::WriteBack::ID, "GuardWritingBackAllowed");
714 this->mm.AddTrans("On:WriteBack:Busy", "On:WriteBack:Idle", events::WriteBackDone::ID, "", "ActionWriteBackDone");
715 this->mm.AddTrans("On:WriteBack:Busy", "On:WriteBack:Idle", events::WriteBackError::ID, "", "ActionWriteBackFailed");
716 this->mm.AddTrans("On:WriteBack:Busy", "On:WriteBack:Idle", events::Stop::ID, "", "ActionWriteBackStopped");
717 // clang-format on
718 }
719 };
720};
721
722} // namespace rtctk::rtcSupervisor
723
724#endif
Adapter object intended to be used in contexts without direct access to the output-stream object.
Definition exceptions.hpp:159
std::string Str() const
Convenience function for constructing a std::string from the exception.
Definition exceptions.hpp:177
static void Register(CommandReplier &replier, StateMachineEngine &engine)
Definition rtcCmdsImpl.hpp:68
Thrown if the command was accepted but the task to run failed.
Definition rtcComponent.hpp:53
Thrown if a command is not allowed in current state or guard.
Definition rtcComponent.hpp:40
The RtctkException class is the base class for all Rtctk exceptions.
Definition exceptions.hpp:211
Definition stateMachineEngine.hpp:35
void RegisterGuardStatic(const std::string &id, std::function< bool(const Event &)> guard)
Register guard for statically known event type.
Definition stateMachineEngine.hpp:126
Thrown if somebody sent a stop or abort command.
Definition stdComponent.hpp:96
static void Register(CommandReplier &replier, StateMachineEngine &engine)
Definition supervisoryCmdsImpl.hpp:40
Business logic interface for Supervisory mixin.
Definition supervisory.hpp:220
virtual JsonPayload ActionGetActiveModes()
Action is used for mode inspection and executed in the state machine thread.
Definition supervisory.hpp:286
virtual bool GuardSettingModesAllowed(const JsonPayload &arg)
Determines if set mode is possible at this time with the provided argument.
Definition supervisory.hpp:253
virtual void ActivitySettingModes(StopToken st, const JsonPayload &arg)
Activity executed in its own thread that performs the mode setting.
Definition supervisory.hpp:242
virtual JsonPayload ActionGetDeferredModes()
Action is used for mode inspection and executed in the state machine thread.
Definition supervisory.hpp:297
virtual std::string ActionGetStatus()
Action is used for system status inspection and is executed in the state machine thread.
Definition supervisory.hpp:229
virtual bool GuardWritingBackAllowed(const JsonPayload &arg)
Determines if writeback is possible at this time with the provided argument.
Definition supervisory.hpp:322
virtual void ActivityRecovering(StopToken st)
Activity executed in its own thread that performs the error recovery.
Definition supervisory.hpp:334
virtual JsonPayload ActionGetAvailableModes()
Action is used for mode inspection and executed in the state machine thread.
Definition supervisory.hpp:275
virtual void ActionSetDeferredModes(const JsonPayload &arg)
Action is executed in the state machine thread and it performs deferred mode setting.
Definition supervisory.hpp:265
virtual void ActivityWritingBack(StopToken st, const JsonPayload &arg)
Activity executed in its own thread that performs the writeback.
Definition supervisory.hpp:310
Definition supervisory.hpp:341
void Start() override
Definition supervisory.hpp:345
ModelBuilder(StateMachineEngine &engine)
Definition supervisory.hpp:678
std::list< std::string > m_no_writeback_in_states
Definition supervisory.hpp:670
std::function< void()> m_writeback_success_handler
Definition supervisory.hpp:667
std::function< void()> m_setmode_success_handler
Definition supervisory.hpp:665
std::function< void(std::exception_ptr)> m_setmode_error_handler
Definition supervisory.hpp:666
std::list< std::string > m_no_setmode_in_states
Definition supervisory.hpp:669
std::function< void(std::exception_ptr)> m_writeback_error_handler
Definition supervisory.hpp:668
OutputStage(StateMachineEngine &engine, BizLogicIf &bl)
Definition supervisory.hpp:359
std::optional< detail::SetModesContext > m_setmode_ctx
Definition supervisory.hpp:663
std::optional< detail::WriteBackContext > m_writeback_ctx
Definition supervisory.hpp:664
static void Register(CommandReplier &replier, StateMachineEngine &engine)
Definition supervisoryCmdsImpl.hpp:87
Holds context necessary for processing a SetModes request to completion.
Definition supervisory.hpp:38
SetModesContext(const rad::cii::Request< std::string, std::string > &request)
Construct context with provided request.
Definition supervisory.hpp:46
void SendErrorReply(std::exception_ptr eptr) noexcept
Send exceptional reply.
Definition supervisory.hpp:80
SetModesContext(SetModesContext &&) noexcept=default
const JsonPayload & GetArg() const noexcept
Definition supervisory.hpp:55
void SendReply() noexcept
Sends hardcoded string reply.
Definition supervisory.hpp:62
Holds context necessary for processing a WriteBack request to completion.
Definition supervisory.hpp:110
void SendReply() noexcept
Sends hardcoded string reply.
Definition supervisory.hpp:134
const JsonPayload & GetArg() const noexcept
Definition supervisory.hpp:127
WriteBackContext(const rad::cii::Request< std::string, std::string > &request)
Construct context with provided request.
Definition supervisory.hpp:118
void SendStopReply() noexcept
Send stop reply.
Definition supervisory.hpp:166
void SendErrorReply(std::exception_ptr eptr) noexcept
Send exceptional reply.
Definition supervisory.hpp:153
WriteBackContext(WriteBackContext &&) noexcept=default
Provides macros and utilities for exception handling.
Defines the JSON payload type JsonPayload.
Definition commandReplier.cpp:22
@ Simple
Definition model.hpp:23
@ Composite
Definition model.hpp:23
@ Initial
Definition model.hpp:23
rad::StopToken StopToken
Definition stopToken.hpp:20
const std::string STD_OK_REPLY
Definition stdComponent.hpp:86
auto WrapWithNested(E &&exception) noexcept(std::is_nothrow_constructible_v< detail::UnspecifiedNested< typename std::decay_t< E > >, E && >)
Constructs an unspecified exception that derives from both the provided object and std::nested_except...
Definition exceptions.hpp:95
nlohmann::json JsonPayload
Type requirements:
Definition jsonPayload.hpp:25
elt::mal::future< std::string > InjectReqRepEvent(StateMachineEngine &engine)
Definition malEventInjector.hpp:23
Definition rtcSupervisor.cpp:24
Lifecycle of a basic 'RtcComponent'.
A simple Stop Token.
Life cycle extension to make RtcComponent Supervisory.
Definition supervisory.hpp:213
Implementation of MAL commands for layer 'Supervisory'.