cs-codex-dist-tests/Framework/OverwatchTranscript/EventBucketWriter.cs

114 lines
3.4 KiB
C#
Raw Permalink Normal View History

2024-08-02 06:56:49 +00:00
using Logging;
using Newtonsoft.Json;
2024-08-01 12:50:25 +00:00
namespace OverwatchTranscript
{
public class EventBucketWriter
2024-08-01 12:50:25 +00:00
{
private const int MaxBuffer = 1000;
2024-08-01 12:50:25 +00:00
private readonly object _lock = new object();
private bool closed = false;
2024-08-02 06:56:49 +00:00
private readonly ILog log;
2024-08-01 12:50:25 +00:00
private readonly string bucketFile;
private readonly int maxCount;
2024-08-01 12:50:25 +00:00
private readonly List<EventBucketEntry> buffer = new List<EventBucketEntry>();
public EventBucketWriter(ILog log, string bucketFile, int maxCount)
2024-08-01 12:50:25 +00:00
{
2024-08-02 06:56:49 +00:00
this.log = log;
2024-08-01 12:50:25 +00:00
this.bucketFile = bucketFile;
this.maxCount = maxCount;
2024-08-01 12:50:25 +00:00
if (File.Exists(bucketFile)) throw new Exception("Already exists");
log.Debug("Write Bucket open: " + bucketFile);
2024-08-01 12:50:25 +00:00
}
public int Count { get; private set; }
public bool IsFull { get; private set; }
public void Add(DateTime utc, object payload)
{
2024-08-01 14:25:28 +00:00
lock (_lock)
{
if (closed) throw new Exception("Already closed");
AddToBuffer(utc, payload);
2024-08-02 06:56:49 +00:00
BufferToFile(emptyBuffer: false);
2024-08-01 14:25:28 +00:00
}
2024-08-01 12:50:25 +00:00
}
2024-08-01 14:25:28 +00:00
public IFinalizedBucket FinalizeBucket()
2024-08-01 12:50:25 +00:00
{
lock (_lock)
{
2024-08-01 14:25:28 +00:00
closed = true;
2024-08-02 06:56:49 +00:00
BufferToFile(emptyBuffer: true);
2024-08-01 12:50:25 +00:00
SortFileByTimestamps();
}
2024-08-02 06:56:49 +00:00
log.Debug($"Finalized bucket with {Count} entries");
return new EventBucketReader(log, bucketFile);
2024-08-01 12:50:25 +00:00
}
2024-08-02 06:56:49 +00:00
public override string ToString()
{
return $"EventBucket: " + Count;
}
2024-08-01 12:50:25 +00:00
private void AddToBuffer(DateTime utc, object payload)
{
var typeName = payload.GetType().FullName;
2024-08-01 14:25:28 +00:00
if (string.IsNullOrEmpty(typeName)) throw new Exception("Empty typename for payload");
if (utc == default) throw new Exception("DateTimeUtc not set");
2024-08-01 12:50:25 +00:00
var entry = new EventBucketEntry
{
Utc = utc,
Event = new OverwatchEvent
{
Type = typeName,
Payload = Json.Serialize(payload)
2024-08-01 12:50:25 +00:00
}
};
Count++;
IsFull = Count > maxCount;
2024-08-01 12:50:25 +00:00
buffer.Add(entry);
}
2024-08-02 06:56:49 +00:00
private void BufferToFile(bool emptyBuffer)
2024-08-01 14:25:28 +00:00
{
2024-08-02 06:56:49 +00:00
if (emptyBuffer || buffer.Count > MaxBuffer)
2024-08-01 14:25:28 +00:00
{
using var file = File.Open(bucketFile, FileMode.Append);
using var writer = new StreamWriter(file);
foreach (var entry in buffer)
{
writer.WriteLine(Json.Serialize(entry));
2024-08-01 14:25:28 +00:00
}
2024-08-02 06:56:49 +00:00
log.Debug($"Bucket wrote {buffer.Count} entries to file.");
2024-08-01 14:25:28 +00:00
buffer.Clear();
}
}
2024-08-01 12:50:25 +00:00
private void SortFileByTimestamps()
{
var lines = File.ReadAllLines(bucketFile);
var entries = lines.Select(Json.Deserialize<EventBucketEntry>)
2024-08-01 12:50:25 +00:00
.Cast<EventBucketEntry>()
.OrderBy(e => e.Utc)
.ToArray();
File.Delete(bucketFile);
File.WriteAllLines(bucketFile, entries.Select(e => Json.Serialize(e)));
2024-08-01 12:50:25 +00:00
}
2024-08-01 14:25:28 +00:00
}
2024-08-01 12:50:25 +00:00
[Serializable]
public class EventBucketEntry
{
public DateTime Utc { get; set; }
public OverwatchEvent Event { get; set; } = new();
}
}