refactor(net): own session wiring subscriptions
This commit is contained in:
parent
88fe1db37b
commit
7d452aa6a2
8 changed files with 577 additions and 61 deletions
|
|
@ -24,7 +24,27 @@ public sealed class GameEventDispatcher
|
|||
{
|
||||
public delegate void EventHandler(GameEventEnvelope envelope);
|
||||
|
||||
private readonly Dictionary<GameEventType, EventHandler> _handlers = new();
|
||||
private sealed class RegistrationNode(
|
||||
GameEventType type,
|
||||
EventHandler handler,
|
||||
RegistrationNode? previous)
|
||||
{
|
||||
public GameEventType Type { get; } = type;
|
||||
public EventHandler Handler { get; } = handler;
|
||||
public RegistrationNode? Previous { get; } = previous;
|
||||
public bool Retired { get; set; }
|
||||
}
|
||||
|
||||
private sealed class OwnedRegistration(
|
||||
GameEventDispatcher owner,
|
||||
RegistrationNode node) : IDisposable
|
||||
{
|
||||
private Action? _retire = () => owner.Retire(node);
|
||||
|
||||
public void Dispose() => Interlocked.Exchange(ref _retire, null)?.Invoke();
|
||||
}
|
||||
|
||||
private readonly Dictionary<GameEventType, RegistrationNode> _handlers = new();
|
||||
private readonly Dictionary<GameEventType, int> _unhandledCounts = new();
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -34,13 +54,34 @@ public sealed class GameEventDispatcher
|
|||
public void Register(GameEventType type, EventHandler handler)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(handler);
|
||||
_handlers[type] = handler;
|
||||
// Legacy replacement intentionally severs the predecessor chain. An
|
||||
// exact owned token installed earlier must never remove or expose a
|
||||
// later unowned replacement when that token is disposed.
|
||||
_handlers[type] = new RegistrationNode(type, handler, previous: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Installs one exact owned handler. Disposal restores the nearest live
|
||||
/// predecessor only when this registration is still current. Nested A/B
|
||||
/// ownership is safe in either disposal order.
|
||||
/// </summary>
|
||||
public IDisposable RegisterOwned(GameEventType type, EventHandler handler)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(handler);
|
||||
_handlers.TryGetValue(type, out RegistrationNode? previous);
|
||||
var node = new RegistrationNode(type, handler, previous);
|
||||
_handlers[type] = node;
|
||||
return new OwnedRegistration(this, node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the registered handler for a sub-opcode.
|
||||
/// </summary>
|
||||
public void Unregister(GameEventType type) => _handlers.Remove(type);
|
||||
public void Unregister(GameEventType type)
|
||||
{
|
||||
if (_handlers.Remove(type, out RegistrationNode? current))
|
||||
current.Retired = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Route an envelope to its handler, or log as unhandled. Exceptions
|
||||
|
|
@ -49,11 +90,11 @@ public sealed class GameEventDispatcher
|
|||
/// </summary>
|
||||
public void Dispatch(GameEventEnvelope envelope)
|
||||
{
|
||||
if (_handlers.TryGetValue(envelope.EventType, out var handler))
|
||||
if (_handlers.TryGetValue(envelope.EventType, out RegistrationNode? registration))
|
||||
{
|
||||
try
|
||||
{
|
||||
handler(envelope);
|
||||
registration.Handler(envelope);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -87,4 +128,21 @@ public sealed class GameEventDispatcher
|
|||
|
||||
/// <summary>How many distinct sub-opcodes have a handler registered.</summary>
|
||||
public int RegisteredHandlerCount => _handlers.Count;
|
||||
|
||||
private void Retire(RegistrationNode node)
|
||||
{
|
||||
node.Retired = true;
|
||||
if (!_handlers.TryGetValue(node.Type, out RegistrationNode? current)
|
||||
|| !ReferenceEquals(current, node))
|
||||
return;
|
||||
|
||||
RegistrationNode? predecessor = node.Previous;
|
||||
while (predecessor?.Retired == true)
|
||||
predecessor = predecessor.Previous;
|
||||
|
||||
if (predecessor is null)
|
||||
_handlers.Remove(node.Type);
|
||||
else
|
||||
_handlers[node.Type] = predecessor;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue