using System.Collections.Immutable; using Connected.Caching.Net; using Connected.Net.Server; namespace Connected.Caching; internal sealed class CachingService : MemoryCache, ICachingService, IDisposable, IAsyncDisposable { public CachingService(IEndpointServer server, CacheServer state, CacheServerConnection backplaneClient) { if (server is null) throw new ArgumentException(null, nameof(server)); if (state is null) throw new ArgumentException(null, nameof(state)); BackplaneClient = backplaneClient; Server = server; BackplaneServer = state; server.Changed += OnServerChanged; server.Initialized += OnServerInitialized; BackplaneServer.Received += OnReceived; BackplaneClient.Received += OnReceived; } private CacheServerConnection BackplaneClient { get; set; } private CacheServer BackplaneServer { get; } private IEndpointServer Server { get; } private async void OnServerInitialized(object? sender, EventArgs e) { await Initialize(); } public async Task Initialize() { await BackplaneClient.Disconnect(); try { if (!await Server.IsServer()) { await BackplaneClient.Initialize(Server.ServerUrl); await BackplaneClient.Connect(); } } catch { // Server probably not initalized yet } } private async void OnReceived(object? sender, CacheNotificationArgs e) { if (string.Equals(e.Method, nameof(Clear), StringComparison.Ordinal)) ClearCore(e.Key); else if (string.Equals(e.Method, nameof(Remove), StringComparison.Ordinal)) { if (e.Ids is not null && e.Ids.Any()) { foreach (var id in e.Ids) RemoveCore(e.Key, id); } } else if (string.Equals(e.Method, nameof(Invalidate), StringComparison.Ordinal)) { if (e.Ids is not null && e.Ids.Any()) { foreach (var id in e.Ids) await InvalidateCore(e.Key, id, true); } } } private async void OnServerChanged(object? sender, ServerChangedArgs e) { await Initialize(); } public override async Task Clear(string key) { await base.Clear(key); var args = new CacheNotificationArgs(nameof(Clear)) { Key = key }; if (await Server.IsServer()) await BackplaneServer.Send(args); else await BackplaneClient.Notify(nameof(Clear), args); } protected internal override async Task OnInvalidating(CacheEventArgs e) { var args = new CacheNotificationArgs(nameof(Invalidate)) { Ids = new List { e.Id }, Key = e.Key }; if (await Server.IsServer()) await BackplaneServer.Send(args); else await BackplaneClient.Notify(nameof(Invalidate), args); } protected override async Task OnRemove(string key, ImmutableList ids) { await base.OnRemove(key, ids); var args = new CacheNotificationArgs(nameof(Remove)) { Ids = ids.ToList(), Key = key }; if (await Server.IsServer()) await BackplaneServer.Send(args); else await BackplaneClient.Notify(nameof(Remove), args); } protected override async Task OnRemove(string key, object? id) { await base.OnRemove(key, id); var ids = new List(); if (id is not null) ids.Add(id.ToString()); await OnRemove(key, ids.ToImmutableList()); } public async ValueTask DisposeAsync() { Server.Changed -= OnServerChanged; Server.Initialized -= OnServerInitialized; } protected override void OnDisposing(bool disposing) { Server.Changed -= OnServerChanged; Server.Initialized -= OnServerInitialized; base.OnDisposing(disposing); } }