using System; using System.Collections.Generic; using System.Linq; using MediaBrowser.Common.Configuration; namespace Jellyfin.Server.Implementations.Tests.Configuration; /// /// An in-process stand-in for the Redis pub/sub bus: every endpoint connected to one fabric receives /// what the others publish, and never its own notices. /// internal sealed class FakeInvalidationBusFabric { private readonly List _endpoints = new(); /// /// Connects a new instance to the fabric. /// /// The identity of the connecting instance. /// The bus of that instance. public IConfigurationInvalidationBus Connect(string originId) { var endpoint = new Endpoint(this, originId); lock (_endpoints) { _endpoints.Add(endpoint); } return endpoint; } private void Broadcast(ConfigurationInvalidation invalidation) { Endpoint[] endpoints; lock (_endpoints) { endpoints = _endpoints.ToArray(); } foreach (var endpoint in endpoints.Where(e => !string.Equals(e.OriginId, invalidation.OriginId, StringComparison.Ordinal))) { endpoint.Deliver(invalidation); } } private sealed class Endpoint : IConfigurationInvalidationBus { private readonly FakeInvalidationBusFabric _fabric; private readonly List> _handlers = new(); public Endpoint(FakeInvalidationBusFabric fabric, string originId) { _fabric = fabric; OriginId = originId; } public string OriginId { get; } public void Publish(ConfigurationInvalidationScope scope, string? target) => _fabric.Broadcast(new ConfigurationInvalidation { Scope = scope, Target = target, OriginId = OriginId }); public void Subscribe(Action handler) => _handlers.Add(handler); public void Deliver(ConfigurationInvalidation invalidation) { foreach (var handler in _handlers) { handler(invalidation); } } } }