mirror of
https://github.com/ZmnSCPxj/clboss.git
synced 2026-08-14 12:43:19 +02:00
142 lines
3.5 KiB
C++
142 lines
3.5 KiB
C++
#include"Boss/Mod/Timers.hpp"
|
|
#include"Boss/Mod/Waiter.hpp"
|
|
#include"Boss/Msg/Init.hpp"
|
|
#include"Boss/Msg/Timer10Minutes.hpp"
|
|
#include"Boss/Msg/TimerRandomDaily.hpp"
|
|
#include"Boss/Msg/TimerRandomHourly.hpp"
|
|
#include"Boss/concurrent.hpp"
|
|
#include"Boss/log.hpp"
|
|
#include"Boss/random_engine.hpp"
|
|
#include"Ev/Io.hpp"
|
|
#include"S/Bus.hpp"
|
|
#include<chrono>
|
|
#include<memory>
|
|
#include<random>
|
|
|
|
namespace {
|
|
|
|
template<typename T>
|
|
class RandomTimeLoop : public std::enable_shared_from_this<RandomTimeLoop<T>> {
|
|
private:
|
|
std::string name;
|
|
S::Bus& bus;
|
|
Boss::Mod::Waiter& waiter;
|
|
std::uniform_real_distribution<double> dist;
|
|
|
|
RandomTimeLoop( std::string name_
|
|
, S::Bus& bus_
|
|
, Boss::Mod::Waiter& waiter_
|
|
, std::uniform_real_distribution<double> dist_
|
|
) : name(std::move(name_))
|
|
, bus(bus_)
|
|
, waiter(waiter_)
|
|
, dist(std::move(dist_)) {
|
|
}
|
|
|
|
Ev::Io<void> loop() {
|
|
return Ev::lift().then([this]() {
|
|
auto time = dist(Boss::random_engine);
|
|
return waiter.wait(time);
|
|
}).then([this]() {
|
|
return Boss::log( bus, Boss::Debug
|
|
, "Timers: triggering %s"
|
|
, name.c_str()
|
|
);
|
|
}).then([this]() {
|
|
return Boss::concurrent(bus.raise(T()));
|
|
}).then([this]() {
|
|
return loop();
|
|
});
|
|
}
|
|
|
|
public:
|
|
~RandomTimeLoop() { }
|
|
static
|
|
std::shared_ptr<RandomTimeLoop>
|
|
create( std::string name
|
|
, S::Bus& bus
|
|
, Boss::Mod::Waiter& waiter
|
|
, std::uniform_real_distribution<double> dist
|
|
) {
|
|
/* Cannot use std::make_shared, constructor is private. */
|
|
return std::shared_ptr<RandomTimeLoop>(
|
|
new RandomTimeLoop( std::move(name)
|
|
, bus
|
|
, waiter
|
|
, std::move(dist)
|
|
)
|
|
);
|
|
}
|
|
|
|
Ev::Io<void> enter_loop() {
|
|
auto self = RandomTimeLoop<T>::shared_from_this();
|
|
return self->loop().then([self]() {
|
|
/* This function becomes part of the
|
|
* pass continuation that is given to
|
|
* the loop operation.
|
|
* This keeps the self-pointer alive.
|
|
* This function never actually gets
|
|
* invoked, but if an exception is
|
|
* thrown within the Ev::Io system,
|
|
* this function get destructed, and
|
|
* only then will the self-pointer get
|
|
* destructed.
|
|
*/
|
|
return Ev::lift();
|
|
});
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
Ev::Io<void> random_time_loop( std::string name
|
|
, S::Bus& bus
|
|
, Boss::Mod::Waiter& waiter
|
|
, std::uniform_real_distribution<double> dist
|
|
) {
|
|
auto loop_obj = RandomTimeLoop<T>::create(
|
|
std::move(name), bus, waiter, std::move(dist)
|
|
);
|
|
return loop_obj->enter_loop();
|
|
}
|
|
|
|
}
|
|
|
|
namespace Boss { namespace Mod {
|
|
|
|
void Timers::start() {
|
|
bus.subscribe<Boss::Msg::Init>([this](Boss::Msg::Init const& _) {
|
|
/* Start timers at init. */
|
|
return Ev::lift().then([this]() {
|
|
return Boss::concurrent(random_daily());
|
|
}).then([this]() {
|
|
return Boss::concurrent(random_hourly());
|
|
}).then([this]() {
|
|
return Boss::concurrent(every_10_minutes());
|
|
});
|
|
});
|
|
}
|
|
|
|
Ev::Io<void> Timers::random_daily() {
|
|
auto dist = std::uniform_real_distribution<double>(43200, 86400 + 43200);
|
|
return random_time_loop<Boss::Msg::TimerRandomDaily>(
|
|
"random daily",
|
|
bus, waiter, std::move(dist)
|
|
);
|
|
}
|
|
Ev::Io<void> Timers::random_hourly() {
|
|
auto dist = std::uniform_real_distribution<double>(1800, 3600 + 1800);
|
|
return random_time_loop<Boss::Msg::TimerRandomHourly>(
|
|
"random hourly",
|
|
bus, waiter, std::move(dist)
|
|
);
|
|
}
|
|
Ev::Io<void> Timers::every_10_minutes() {
|
|
/* Reuse the time loop to reduce our code burden. */
|
|
auto dist = std::uniform_real_distribution<double>(600, 600);
|
|
return random_time_loop<Boss::Msg::Timer10Minutes>(
|
|
"regular 10 minutes",
|
|
bus, waiter, std::move(dist)
|
|
);
|
|
}
|
|
|
|
}}
|