Add host activity and DB browser, and keep dialogs, drag-drop, and idle maintenance responsive.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
87
src/Explorer.Application/HostActivityLog.cs
Normal file
87
src/Explorer.Application/HostActivityLog.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using Explorer.Contracts;
|
||||
|
||||
namespace Explorer.Application;
|
||||
|
||||
public interface IHostActivitySink
|
||||
{
|
||||
void Record(string category, string message);
|
||||
IReadOnlyList<HostActivityEvent> TakeRecent(int max = 120);
|
||||
}
|
||||
|
||||
public sealed class NullHostActivitySink : IHostActivitySink
|
||||
{
|
||||
public static NullHostActivitySink Instance { get; } = new();
|
||||
|
||||
public void Record(string category, string message)
|
||||
{
|
||||
}
|
||||
|
||||
public IReadOnlyList<HostActivityEvent> TakeRecent(int max = 120) => [];
|
||||
}
|
||||
|
||||
/// <summary>Bounded ring of host activity lines for the live monitor. Cheap to write; snapshot is a copy.</summary>
|
||||
public sealed class HostActivityLog : IHostActivitySink
|
||||
{
|
||||
private readonly object _gate = new();
|
||||
private readonly HostActivityEvent[] _ring;
|
||||
private int _next;
|
||||
private int _count;
|
||||
private string? _lastKey;
|
||||
private DateTimeOffset _lastUtc;
|
||||
|
||||
public HostActivityLog(int capacity = 48)
|
||||
{
|
||||
_ring = new HostActivityEvent[Math.Clamp(capacity, 32, 200)];
|
||||
}
|
||||
|
||||
public void Record(string category, string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var cat = string.IsNullOrWhiteSpace(category) ? "Host" : category.Trim();
|
||||
var msg = message.Trim();
|
||||
var key = cat + "\u001f" + msg;
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
lock (_gate)
|
||||
{
|
||||
if (key == _lastKey && (now - _lastUtc) < TimeSpan.FromMilliseconds(750))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastKey = key;
|
||||
_lastUtc = now;
|
||||
_ring[_next] = new HostActivityEvent { Utc = now, Category = cat, Message = msg };
|
||||
_next = (_next + 1) % _ring.Length;
|
||||
if (_count < _ring.Length)
|
||||
{
|
||||
_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<HostActivityEvent> TakeRecent(int max = 120)
|
||||
{
|
||||
max = Math.Clamp(max, 1, _ring.Length);
|
||||
lock (_gate)
|
||||
{
|
||||
var take = Math.Min(max, _count);
|
||||
if (take == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var result = new HostActivityEvent[take];
|
||||
var start = (_next - take + _ring.Length) % _ring.Length;
|
||||
for (var i = 0; i < take; i++)
|
||||
{
|
||||
result[i] = _ring[(start + i) % _ring.Length];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user