about summary refs log tree commit diff
path: root/MiniUtils.Core/PolicyStore.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MiniUtils.Core/PolicyStore.cs')
-rw-r--r--MiniUtils.Core/PolicyStore.cs104
1 files changed, 104 insertions, 0 deletions
diff --git a/MiniUtils.Core/PolicyStore.cs b/MiniUtils.Core/PolicyStore.cs
new file mode 100644

index 0000000..f2aa0fc --- /dev/null +++ b/MiniUtils.Core/PolicyStore.cs
@@ -0,0 +1,104 @@ +using System.Diagnostics; +using LibMatrix; +using LibMatrix.EventTypes.Spec.State.Policy; +using Microsoft.Extensions.Logging; + +namespace MiniUtils.Core; + +public class PolicyStore(ILogger<PolicyStore> logger) { + public Dictionary<string, StateEventResponse> AllPolicies { get; } = []; + +#region Single policy events + + /// <summary> + /// Fired when any policy event is received + /// </summary> + public List<Func<StateEventResponse, Task>> OnPolicyReceived { get; } = []; + + /// <summary> + /// Fired when a new policy is added + /// </summary> + public List<Func<StateEventResponse, Task>> OnPolicyAdded { get; } = []; + + /// <summary> + /// Fired when a policy is updated, without being removed. + /// </summary> + public List<Func<StateEventResponse, StateEventResponse, Task>> OnPolicyUpdated { get; } = []; + + /// <summary> + /// Fired when a policy is removed. + /// </summary> + public List<Func<StateEventResponse, StateEventResponse, Task>> OnPolicyRemoved { get; } = []; + +#endregion + +#region Bulk policy events + + /// <summary> + /// Fired when any policy event is received + /// </summary> + public List<Func<(List<StateEventResponse> NewPolicies, + List<(StateEventResponse Old, StateEventResponse New)> UpdatedPolicies, + List<(StateEventResponse Old, StateEventResponse New)> RemovedPolicies), Task>> OnPoliciesChanged { get; } = []; + +#endregion + + public async Task AddPoliciesAsync(IEnumerable<StateEventResponse> events) { + var policyEvents = events + .Where(evt => evt.TypedContent is PolicyRuleEventContent) + .ToList(); + List<StateEventResponse> 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) { } +} \ No newline at end of file