cs-codex-dist-tests/Tools/TestNetRewarder/TimeSegmenter.cs

101 lines
3.1 KiB
C#
Raw Normal View History

2024-01-22 09:27:07 +00:00
using Logging;
using Utils;
namespace TestNetRewarder
{
2024-06-14 09:05:29 +00:00
public interface ITimeSegmentHandler
{
Task<TimeSegmentResponse> OnNewSegment(TimeRange timeRange);
}
public enum TimeSegmentResponse
{
OK,
Underload,
Overload
2024-06-14 09:05:29 +00:00
}
2024-01-22 09:27:07 +00:00
public class TimeSegmenter
{
private const int maxSegmentMult = 50;
2024-01-22 09:27:07 +00:00
private readonly ILog log;
2024-06-14 09:05:29 +00:00
private readonly ITimeSegmentHandler handler;
2024-01-22 09:27:07 +00:00
private readonly TimeSpan segmentSize;
2024-06-14 09:05:29 +00:00
private DateTime latest;
private int currentSegmentMult = 1;
2024-01-22 09:27:07 +00:00
2024-08-21 13:03:20 +00:00
public TimeSegmenter(ILog log, TimeSpan segmentSize, DateTime historyStartUtc, ITimeSegmentHandler handler)
2024-01-22 09:27:07 +00:00
{
this.log = log;
2024-06-14 09:05:29 +00:00
this.handler = handler;
2024-08-21 13:03:20 +00:00
this.segmentSize = segmentSize;
latest = historyStartUtc;
2024-01-22 09:27:07 +00:00
2024-06-14 09:05:29 +00:00
log.Log("Starting time segments at " + latest);
2024-01-22 09:27:07 +00:00
log.Log("Segment size: " + Time.FormatDuration(segmentSize));
}
2024-08-21 13:03:20 +00:00
public bool IsRealtime { get; private set; } = false;
2024-06-14 09:05:29 +00:00
public async Task ProcessNextSegment()
2024-01-22 09:27:07 +00:00
{
var end = GetNewSegmentEnd();
2024-08-21 13:03:20 +00:00
IsRealtime = await WaitUntilTimeSegmentInPast(end);
2024-01-22 09:27:07 +00:00
if (Program.CancellationToken.IsCancellationRequested) return;
2024-01-22 10:47:28 +00:00
var postfix = "(Catching up...)";
2024-08-21 13:03:20 +00:00
if (IsRealtime) postfix = "(Real-time)";
log.Log($"Time segment [{latest} to {end}] {postfix}({currentSegmentMult}x)");
2024-06-14 09:05:29 +00:00
var range = new TimeRange(latest, end);
latest = end;
2024-01-22 10:47:28 +00:00
var response = await handler.OnNewSegment(range);
HandleResponse(response);
}
private DateTime GetNewSegmentEnd()
{
if (IsRealtime) return latest + segmentSize;
var segment = segmentSize * currentSegmentMult;
var end = latest + segment;
if (end > DateTime.UtcNow) return DateTime.UtcNow + segmentSize;
return end;
}
private void HandleResponse(TimeSegmentResponse response)
{
switch (response)
{
case TimeSegmentResponse.OK:
if (currentSegmentMult > 1) currentSegmentMult--;
break;
case TimeSegmentResponse.Underload:
if (currentSegmentMult < maxSegmentMult) currentSegmentMult++;
break;
case TimeSegmentResponse.Overload:
currentSegmentMult = 1;
break;
default:
throw new Exception("Unknown response type: " + response);
}
2024-06-14 09:05:29 +00:00
}
private async Task<bool> WaitUntilTimeSegmentInPast(DateTime end)
{
await Task.Delay(TimeSpan.FromSeconds(3), Program.CancellationToken);
2024-01-22 09:27:07 +00:00
2024-06-14 09:05:29 +00:00
var now = DateTime.UtcNow;
while (end > now)
{
currentSegmentMult = 1;
2024-06-14 09:05:29 +00:00
var delay = (end - now) + TimeSpan.FromSeconds(3);
await Task.Delay(delay, Program.CancellationToken);
return true;
}
return false;
2024-01-22 09:27:07 +00:00
}
}
}