From adb478ee37ae44fa494bace4b9bbc876cb9481e4 Mon Sep 17 00:00:00 2001 From: ZmnSCPxj jxPCSnmZ Date: Tue, 9 Feb 2021 14:04:26 +0800 Subject: [PATCH] Boss/Mod/SelfUptimeMonitor.cpp: Module to track our own uptime. --- Boss/Mod/SelfUptimeMonitor.cpp | 191 ++++++++++++++++++++++++++++++++ Boss/Mod/SelfUptimeMonitor.hpp | 32 ++++++ Boss/Mod/all.cpp | 2 + Boss/Msg/RequestSelfUptime.hpp | 18 +++ Boss/Msg/ResponseSelfUptime.hpp | 24 ++++ Makefile.am | 4 + 6 files changed, 271 insertions(+) create mode 100644 Boss/Mod/SelfUptimeMonitor.cpp create mode 100644 Boss/Mod/SelfUptimeMonitor.hpp create mode 100644 Boss/Msg/RequestSelfUptime.hpp create mode 100644 Boss/Msg/ResponseSelfUptime.hpp diff --git a/Boss/Mod/SelfUptimeMonitor.cpp b/Boss/Mod/SelfUptimeMonitor.cpp new file mode 100644 index 0000000..c05088d --- /dev/null +++ b/Boss/Mod/SelfUptimeMonitor.cpp @@ -0,0 +1,191 @@ +#include"Boss/Mod/SelfUptimeMonitor.hpp" +#include"Boss/Msg/DbResource.hpp" +#include"Boss/Msg/InternetOnline.hpp" +#include"Boss/Msg/ProvideStatus.hpp" +#include"Boss/Msg/RequestSelfUptime.hpp" +#include"Boss/Msg/ResponseSelfUptime.hpp" +#include"Boss/Msg/SolicitStatus.hpp" +#include"Boss/Msg/Timer10Minutes.hpp" +#include"Boss/concurrent.hpp" +#include"Ev/Io.hpp" +#include"Ev/now.hpp" +#include"S/Bus.hpp" +#include"Sqlite3.hpp" +#include"Util/make_unique.hpp" + +namespace { + +/* Number of 10-minute timers expected per day, */ +auto constexpr timers_per_day = std::size_t(144); +/* Number of seconds per day. */ +auto constexpr seconds_per_day = double(24 * 60 * 60); + +/* Number of days. */ +auto constexpr days_per_day3 = std::size_t(3); +auto constexpr days_per_weeks2 = std::size_t(14); +auto constexpr days_per_month1 = std::size_t(30); + +/* Number of seconds. */ +auto constexpr seconds_per_day3 = days_per_day3 * seconds_per_day; +auto constexpr seconds_per_weeks2 = days_per_weeks2 * seconds_per_day; +auto constexpr seconds_per_month1 = days_per_month1 * seconds_per_day; + +/* Number of 10-minute timers. */ +auto constexpr timers_per_day3 = days_per_day3 * timers_per_day; +auto constexpr timers_per_weeks2 = days_per_weeks2 * timers_per_day; +auto constexpr timers_per_month1 = days_per_month1 * timers_per_day; + +} + +namespace Boss { namespace Mod { + +class SelfUptimeMonitor::Impl { +private: + S::Bus& bus; + + Sqlite3::Db db; + + bool online; + + void start() { + online = false; + bus.subscribe([this](Msg::DbResource const& m) { + db = m.db; + return db.transact().then([](Sqlite3::Tx tx) { + tx.query_execute(R"QRY( + CREATE TABLE IF NOT EXISTS "SelfUptimeMonitor" + ( time REAL PRIMARY KEY + ); + )QRY"); + + tx.commit(); + return Ev::lift(); + }); + }); + bus.subscribe([this](Msg::InternetOnline const& m) { + online = m.online; + return Ev::lift(); + }); + bus.subscribe([this](Msg::Timer10Minutes const& _) { + return Boss::concurrent(timer10minutes()); + }); + bus.subscribe([this](Msg::RequestSelfUptime const& req) { + auto requester = req.requester; + return Ev::lift().then([this, requester]() { + return get_uptime(requester); + }).then([this](Msg::ResponseSelfUptime rsp) { + return bus.raise(std::move(rsp)); + }); + }); + bus.subscribe([this](Msg::SolicitStatus const& m) { + return Ev::lift().then([this]() { + return get_uptime(nullptr); + }).then([this](Msg::ResponseSelfUptime rsp) { + auto out = Json::Out() + .start_object() + .field("past_3_days", rsp.day3) + .field("past_2_weeks", rsp.weeks2) + .field("past_1_month", rsp.month1) + .end_object() + ; + return bus.raise(Msg::ProvideStatus{ + "my_uptime", + std::move(out) + }); + }); + }); + } + + Ev::Io timer10minutes() { + return Ev::lift().then([this]() { + return db.transact(); + }).then([this](Sqlite3::Tx tx) { + auto now = Ev::now(); + if (online) { + tx.query(R"QRY( + INSERT OR IGNORE INTO "SelfUptimeMonitor" + VALUES(:time); + )QRY") + .bind(":time", now) + .execute() + ; + } + + /* Clean up very old entries. */ + auto limit = now - 2 * seconds_per_month1; + tx.query(R"QRY( + DELETE FROM "SelfUptimeMonitor" + WHERE time < :mintime; + )QRY") + .bind(":mintime", limit) + .execute() + ; + + tx.commit(); + return Ev::lift(); + }); + } + + /* Calculates the uptime of a particular timeframe. */ + static + double calc_uptime( Sqlite3::Tx& tx + , double seconds_per_timeframe + , std::size_t timers_per_timeframe + ) { + auto count = std::size_t(0); + + auto fetch = tx.query(R"QRY( + SELECT COUNT(*) FROM "SelfUptimeMonitor" + WHERE time >= :mintime; + )QRY") + .bind(":mintime", Ev::now() - seconds_per_timeframe) + .execute() + ; + for (auto& r : fetch) { + count = r.get(0); + break; + } + + if (count > timers_per_timeframe) + count = timers_per_timeframe; + + return double(count) / double(timers_per_timeframe); + } + /* Gathers the uptime data. */ + Ev::Io + get_uptime(void* requester) { + return db.transact().then([requester](Sqlite3::Tx tx) { + auto msg = Msg::ResponseSelfUptime(); + msg.requester = requester; + msg.day3 = calc_uptime(tx, seconds_per_day3, timers_per_day3); + msg.weeks2 = calc_uptime(tx, seconds_per_weeks2, timers_per_weeks2); + msg.month1 = calc_uptime(tx, seconds_per_month1, timers_per_month1); + + tx.commit(); + + return Ev::lift(std::move(msg)); + }); + } + +public: + Impl() =delete; + Impl(Impl&&) =delete; + Impl(Impl const&) =delete; + + Impl( S::Bus& bus_ + ) : bus(bus_) + { start(); } +}; + +SelfUptimeMonitor::SelfUptimeMonitor(SelfUptimeMonitor&&) =default; +SelfUptimeMonitor::~SelfUptimeMonitor() =default; + +SelfUptimeMonitor::SelfUptimeMonitor(S::Bus& bus) + : pimpl(Util::make_unique(bus)) { } + +}} diff --git a/Boss/Mod/SelfUptimeMonitor.hpp b/Boss/Mod/SelfUptimeMonitor.hpp new file mode 100644 index 0000000..d143167 --- /dev/null +++ b/Boss/Mod/SelfUptimeMonitor.hpp @@ -0,0 +1,32 @@ +#ifndef BOSS_MOD_SELFUPTIMEMONITOR_HPP +#define BOSS_MOD_SELFUPTIMEMONITOR_HPP + +#include + +namespace S { class Bus; } + +namespace Boss { namespace Mod { + +/** class Boss::Mod::SelfUptimeMonitor + * + * @brief Monitors our own uptime. + * Uptime is about being internet connected and CLBOSS is running. + */ +class SelfUptimeMonitor { +private: + class Impl; + std::unique_ptr pimpl; + +public: + SelfUptimeMonitor() =delete; + + SelfUptimeMonitor(SelfUptimeMonitor&&); + ~SelfUptimeMonitor(); + + explicit + SelfUptimeMonitor(S::Bus& bus); +}; + +}} + +#endif /* !defined(BOSS_MOD_SELFUPTIMEMONITOR_HPP) */ diff --git a/Boss/Mod/all.cpp b/Boss/Mod/all.cpp index 1f67b5d..1da347a 100644 --- a/Boss/Mod/all.cpp +++ b/Boss/Mod/all.cpp @@ -52,6 +52,7 @@ #include"Boss/Mod/PeerStatistician.hpp" #include"Boss/Mod/Reconnector.hpp" #include"Boss/Mod/RegularActiveProbe.hpp" +#include"Boss/Mod/SelfUptimeMonitor.hpp" #include"Boss/Mod/SendpayResultMonitor.hpp" #include"Boss/Mod/StatusCommand.hpp" #include"Boss/Mod/SwapManager.hpp" @@ -126,6 +127,7 @@ std::shared_ptr all( std::ostream& cout all->install(bus); all->install(bus); all->install(bus); + all->install(bus); /* Channel creation wrangling. */ all->install(bus, *waiter); diff --git a/Boss/Msg/RequestSelfUptime.hpp b/Boss/Msg/RequestSelfUptime.hpp new file mode 100644 index 0000000..0032867 --- /dev/null +++ b/Boss/Msg/RequestSelfUptime.hpp @@ -0,0 +1,18 @@ +#ifndef BOSS_MSG_REQUESTSELFUPTIME_HPP +#define BOSS_MSG_REQUESTSELFUPTIME_HPP + +namespace Boss { namespace Msg { + +/** struct Boss::Msg::RequestSelfUptime + * + * @brief queries our own uptime. + * The `Boss::Mod::SelfUptimeMonitor` will respond with a + * `Boss::Msg::ResponseSelfUptime` message. + */ +struct RequestSelfUptime { + void* requester; +}; + +}} + +#endif /* !defined(BOSS_MSG_REQUESTSELFUPTIME_HPP) */ diff --git a/Boss/Msg/ResponseSelfUptime.hpp b/Boss/Msg/ResponseSelfUptime.hpp new file mode 100644 index 0000000..7f00942 --- /dev/null +++ b/Boss/Msg/ResponseSelfUptime.hpp @@ -0,0 +1,24 @@ +#ifndef BOSS_MSG_RESPONSESELFUPTIME_HPP +#define BOSS_MSG_RESPONSESELFUPTIME_HPP + +namespace Boss { namespace Msg { + +/** struct Boss::Msg::ResponseSelfUptime + * + * @brief Broadcast in response to `Boss::Msg::RequestSelfUptime` to + * provide uptime information. + */ +struct ResponseSelfUptime { + void* requester; + + /* Uptime in the last 3 days. */ + double day3; + /* Uptime in the last 14 days. */ + double weeks2; + /* Uptime in the last 30 days. */ + double month1; +}; + +}} + +#endif /* !defined(BOSS_MSG_RESPONSESELFUPTIME_HPP) */ diff --git a/Makefile.am b/Makefile.am index 16cad4d..176e16b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -199,6 +199,8 @@ libclboss_la_SOURCES = \ Boss/Mod/RegularActiveProbe.hpp \ Boss/Mod/Rpc.cpp \ Boss/Mod/Rpc.hpp \ + Boss/Mod/SelfUptimeMonitor.cpp \ + Boss/Mod/SelfUptimeMonitor.hpp \ Boss/Mod/SendpayResultMonitor.cpp \ Boss/Mod/SendpayResultMonitor.hpp \ Boss/Mod/StatusCommand.cpp \ @@ -275,6 +277,7 @@ libclboss_la_SOURCES = \ Boss/Msg/RequestNewaddr.hpp \ Boss/Msg/RequestPeerMetrics.hpp \ Boss/Msg/RequestPeerStatistics.hpp \ + Boss/Msg/RequestSelfUptime.hpp \ Boss/Msg/ResponseConnect.hpp \ Boss/Msg/ResponseDowser.hpp \ Boss/Msg/ResponseEarningsInfo.hpp \ @@ -284,6 +287,7 @@ libclboss_la_SOURCES = \ Boss/Msg/ResponseNewaddr.hpp \ Boss/Msg/ResponsePeerMetrics.hpp \ Boss/Msg/ResponsePeerStatistics.hpp \ + Boss/Msg/ResponseSelfUptime.hpp \ Boss/Msg/RpcCommandHook.hpp \ Boss/Msg/SendpayResult.hpp \ Boss/Msg/SetChannelFee.hpp \