using System.Diagnostics; using LibMatrix; using LibMatrix.EventTypes.Spec.State.Policy; using Microsoft.Extensions.Logging; namespace MatrixAntiDmSpam.Core; public class PolicyStore(ILogger logger) { public Dictionary AllPolicies { get; } = []; #region Single policy events /// /// Fired when any policy event is received /// public List> OnPolicyReceived { get; } = []; /// /// Fired when a new policy is added /// public List> OnPolicyAdded { get; } = []; /// /// Fired when a policy is updated, without being removed. /// public List> OnPolicyUpdated { get; } = []; /// /// Fired when a policy is removed. /// public List> OnPolicyRemoved { get; } = []; #endregion #region Bulk policy events /// /// Fired when any policy event is received /// public List NewPolicies, List<(StateEventResponse Old, StateEventResponse New)> UpdatedPolicies, List<(StateEventResponse Old, StateEventResponse New)> RemovedPolicies), Task>> OnPoliciesChanged { get; } = []; #endregion public async Task AddPoliciesAsync(IEnumerable events) { var policyEvents = events .Where(evt => evt.TypedContent is PolicyRuleEventContent) .ToList(); List newPolicies = new(); List<(StateEventResponse Old, StateEventResponse New)> updatedPolicies = new(); List<(StateEventResponse Old, StateEventResponse New)> removedPolicies = new(); var sw = Stopwatch.StartNew(); try { foreach (var evt in policyEvents) { var eventKey = $"{evt.RoomId}:{evt.Type}:{evt.StateKey}"; if (evt.TypedContent is not PolicyRuleEventContent policy) continue; if (policy.GetNormalizedRecommendation() is "m.ban") { if (AllPolicies.TryGetValue(eventKey, out var oldContent)) updatedPolicies.Add((oldContent, evt)); else newPolicies.Add(evt); AllPolicies[eventKey] = evt; } else if (AllPolicies.Remove(eventKey, out var oldContent)) removedPolicies.Add((oldContent, evt)); } } catch (Exception e) { Console.WriteLine(e); } logger.LogInformation("Processed {Count} policies in {Elapsed}", policyEvents.Count, sw.Elapsed); // execute all the callbacks in parallel, as much as possible... await Task.WhenAll( Task.WhenAll( policyEvents.Select(evt => Task.WhenAll(OnPolicyReceived.Select(callback => callback(evt)).ToList()) ) ), Task.WhenAll( newPolicies.Select(evt => Task.WhenAll(OnPolicyAdded.Select(callback => callback(evt)).ToList()) ) ), Task.WhenAll( updatedPolicies.Select(evt => Task.WhenAll(OnPolicyUpdated.Select(callback => callback(evt.Old, evt.New)).ToList()) ) ), Task.WhenAll( removedPolicies.Select(evt => Task.WhenAll(OnPolicyRemoved.Select(callback => callback(evt.Old, evt.New)).ToList()) ) ), Task.WhenAll(OnPoliciesChanged.Select(callback => callback((newPolicies, updatedPolicies, removedPolicies))).ToList()) ); } private async Task AddPolicyAsync(StateEventResponse evt) { } }