transmission/libtransmission/session-alt-speeds.h

195 lines
5.3 KiB
C++

// This file Copyright © Mnemosyne LLC.
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.
#ifndef __TRANSMISSION__
#error only libtransmission should #include this header.
#endif
#pragma once
#include <bitset>
#include <cstddef> // size_t
#include <ctime> // for time_t
#include <optional>
#include "libtransmission/transmission.h" // for TR_SCHED_ALL
#include "libtransmission/quark.h"
#include "libtransmission/settings.h"
#include "libtransmission/values.h"
struct tr_variant;
/** Manages alternate speed limits and a scheduler to auto-toggle them. */
class tr_session_alt_speeds
{
using Speed = libtransmission::Values::Speed;
public:
class Settings final : public libtransmission::Settings
{
public:
Settings() = default;
explicit Settings(tr_variant const& src)
{
load(src);
}
// NB: When adding a field here, you must also add it to
// fields() if you want it to be in session-settings.json
bool is_active = false;
bool scheduler_enabled = false; // whether alt speeds toggle on and off on schedule
size_t minute_begin = 540U; // minutes past midnight; 9AM
size_t minute_end = 1020U; // minutes past midnight; 5PM
size_t speed_down_kbyps = 50U;
size_t speed_up_kbyps = 50U;
size_t use_on_these_weekdays = TR_SCHED_ALL;
private:
[[nodiscard]] Fields fields() override
{
return {
{ TR_KEY_alt_speed_enabled, &is_active },
{ TR_KEY_alt_speed_up, &speed_up_kbyps },
{ TR_KEY_alt_speed_down, &speed_down_kbyps },
{ TR_KEY_alt_speed_time_enabled, &scheduler_enabled },
{ TR_KEY_alt_speed_time_day, &use_on_these_weekdays },
{ TR_KEY_alt_speed_time_begin, &minute_begin },
{ TR_KEY_alt_speed_time_end, &minute_end },
};
}
};
enum class ChangeReason : uint8_t
{
User,
Scheduler,
LoadSettings
};
class Mediator
{
public:
virtual ~Mediator() noexcept = default;
using ChangeReason = tr_session_alt_speeds::ChangeReason;
virtual void is_active_changed(bool is_active, ChangeReason reason) = 0;
[[nodiscard]] virtual time_t time() = 0;
};
explicit tr_session_alt_speeds(Mediator& mediator) noexcept
: mediator_{ mediator }
{
}
void load(Settings&& settings);
[[nodiscard]] constexpr auto const& settings() const noexcept
{
return settings_;
}
[[nodiscard]] constexpr bool is_active() const noexcept
{
return settings().is_active;
}
void check_scheduler();
void set_scheduler_enabled(bool enabled)
{
settings_.scheduler_enabled = enabled;
update_scheduler();
}
// return true iff the scheduler will turn alt speeds on/off
[[nodiscard]] constexpr auto is_scheduler_enabled() const noexcept
{
return settings().scheduler_enabled;
}
void set_start_minute(size_t minute)
{
settings_.minute_begin = minute;
update_scheduler();
}
[[nodiscard]] constexpr auto start_minute() const noexcept
{
return settings().minute_begin;
}
void set_end_minute(size_t minute)
{
settings_.minute_end = minute;
update_scheduler();
}
[[nodiscard]] constexpr auto end_minute() const noexcept
{
return settings().minute_end;
}
void set_weekdays(tr_sched_day days)
{
settings_.use_on_these_weekdays = days;
update_scheduler();
}
[[nodiscard]] constexpr tr_sched_day weekdays() const noexcept
{
return static_cast<tr_sched_day>(settings().use_on_these_weekdays);
}
[[nodiscard]] auto speed_limit(tr_direction const dir) const noexcept
{
auto const kbyps = dir == TR_DOWN ? settings().speed_down_kbyps : settings().speed_up_kbyps;
return Speed{ kbyps, Speed::Units::KByps };
}
constexpr void set_speed_limit(tr_direction dir, Speed const limit) noexcept
{
if (dir == TR_DOWN)
{
settings_.speed_down_kbyps = limit.count(Speed::Units::KByps);
}
else
{
settings_.speed_up_kbyps = limit.count(Speed::Units::KByps);
}
}
void set_active(bool active, ChangeReason reason)
{
set_active(active, reason, false);
}
private:
Mediator& mediator_;
Settings settings_;
void update_scheduler();
void update_minutes();
void set_active(bool active, ChangeReason reason, bool force);
// whether `time` hits in one of the `minutes_` that is true
[[nodiscard]] bool is_active_minute(time_t time) const noexcept;
static auto constexpr MinutesPerHour = int{ 60 };
static auto constexpr MinutesPerDay = int{ MinutesPerHour * 24 };
static auto constexpr MinutesPerWeek = int{ MinutesPerDay * 7 };
// bitfield of all the minutes in a week.
// Each bit's value indicates whether the scheduler wants
// alt speeds on or off at that given minute.
std::bitset<10080> minutes_{};
// recent change that was made by the scheduler
std::optional<bool> scheduler_set_is_active_to_;
};