Files
TorchPlugins/Maintenance/Managers/MaintenanceScheduleManager.cs
zznty 5e4bef5b01 meh
2023-11-20 13:57:12 +07:00

181 lines
6.6 KiB
C#

using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Configuration;
using Torch.API.Managers;
using Torch.Managers;
namespace Maintenance.Managers;
public class MaintenanceScheduleManager(string storagePath) : IManager
{
[Manager.Dependency]
private readonly MaintenanceManager _maintenanceManager = null!;
[Manager.Dependency]
private readonly ConfigManager _configManager = null!;
[Manager.Dependency]
private readonly LanguageManager _languageManager = null!;
[Manager.Dependency]
private readonly IChatManagerServer _chatManager = null!;
private MaintenanceSchedule _currentSchedule = MaintenanceSchedule.Default;
private readonly FileInfo _scheduleFile = new(Path.Combine(storagePath, ".schedule"));
public MaintenanceSchedule CurrentSchedule
{
get => _currentSchedule;
private set
{
if (value != _currentSchedule)
{
using var file = _scheduleFile.Create();
JsonSerializer.Serialize(file, value);
}
_currentSchedule = value;
}
}
private readonly CancellationTokenSource _cancellationTokenSource = new();
public void Attach()
{
Scheduler();
if (!_scheduleFile.Exists) return;
using (var file = _scheduleFile.OpenRead())
_currentSchedule = JsonSerializer.Deserialize<MaintenanceSchedule>(file)!;
_scheduleFile.Delete();
if (_currentSchedule is not { StartTime: null, EndTime: not null }) return;
if (!_configManager.Configuration.GetValue<bool>(ConfigKeys.ContinueEndTimerAfterRestart))
CurrentSchedule = MaintenanceSchedule.Default;
_maintenanceManager.MaintenanceEnabled = true;
}
private async void Scheduler()
{
var token = _cancellationTokenSource.Token;
var timerSecondsSection = _configManager.Configuration.GetSection(ConfigKeys.TimerBroadcastForSeconds);
var timerSeconds = timerSecondsSection.GetChildren().Select(b => b.Get<int>()).ToArray();
using var disposable = timerSecondsSection.GetReloadToken()
.RegisterChangeCallback(_ => timerSeconds = timerSecondsSection.GetChildren().Select(b => b.Get<int>()).ToArray(), null);
while (!token.IsCancellationRequested)
{
await Task.Delay(2000, token);
switch (_maintenanceManager.MaintenanceEnabled)
{
case false when _currentSchedule.StartTime.HasValue:
{
if (timerSeconds.Any(b => Math.Abs(_currentSchedule.Time.TotalSeconds - b) <= 1))
{
_chatManager.SendMessageAsOther("Maintenance",
Format(_currentSchedule.EndTime.HasValue
? LangKeys.ScheduleTimerBroadcast
: LangKeys.StartTimerBroadcast));
}
if (_currentSchedule.Time.TotalSeconds <= 1)
{
_chatManager.SendMessageAsOther("Maintenance", Format(LangKeys.MaintenanceActivated));
_maintenanceManager.MaintenanceEnabled = true;
CurrentSchedule = CurrentSchedule with { StartTime = null };
}
break;
}
case true when _currentSchedule.EndTime.HasValue:
{
if (timerSeconds.Any(b => Math.Abs(_currentSchedule.Duration.TotalSeconds - b) <= 1))
{
_chatManager.SendMessageAsOther("Maintenance", Format(LangKeys.EndTimerBroadcast));
}
if (_currentSchedule.Duration.TotalSeconds <= 1)
{
_chatManager.SendMessageAsOther("Maintenance", Format(LangKeys.MaintenanceDeactivated));
_maintenanceManager.MaintenanceEnabled = false;
CurrentSchedule = CurrentSchedule with { EndTime = null };
}
break;
}
}
}
string Format(string key) => _languageManager.Format(key, _currentSchedule);
}
public void Detach()
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
}
public void ScheduleTimer(TimerType type, TimeSpan duration)
{
if (_maintenanceManager.MaintenanceEnabled && type == TimerType.Start)
throw new InvalidOperationException("Maintenance is already enabled");
if (type == TimerType.Start)
CurrentSchedule = CurrentSchedule with { StartTime = DateTimeOffset.Now + duration };
else
CurrentSchedule = CurrentSchedule with { EndTime = DateTimeOffset.Now + duration };
}
public void ScheduleMaintenance(TimeSpan startTime, TimeSpan endTime)
{
if (_maintenanceManager.MaintenanceEnabled)
throw new InvalidOperationException("Maintenance is already enabled");
var startDateTime = DateTimeOffset.Now + startTime;
CurrentSchedule = new(startDateTime, startDateTime + endTime);
}
public void CancelTimer(TimerType? type)
{
CurrentSchedule = type switch
{
TimerType.Start when !_currentSchedule.StartTime.HasValue => throw new InvalidOperationException(
"No start timer running"),
TimerType.Start => MaintenanceSchedule.Default,
TimerType.End when !_currentSchedule.EndTime.HasValue => throw new InvalidOperationException(
"No end timer running"),
TimerType.End => CurrentSchedule with { EndTime = null },
_ => MaintenanceSchedule.Default
};
}
}
public record MaintenanceSchedule(DateTimeOffset? StartTime, DateTimeOffset? EndTime)
{
public static MaintenanceSchedule Default => new(null, null);
[JsonIgnore]
public TimeSpan Time => Round((StartTime ?? throw new InvalidOperationException("No start timer running"))
- DateTimeOffset.Now);
[JsonIgnore]
public TimeSpan Duration => Round((EndTime ?? throw new InvalidOperationException("No end timer running"))
- (StartTime ?? DateTimeOffset.Now));
private static TimeSpan Round(TimeSpan timeSpan) => TimeSpan.FromSeconds(Math.Round(timeSpan.TotalSeconds, 0));
}
public enum TimerType : byte
{
Start,
End
}