using PrivaPub.Federation.Actors; using PrivaPub.Infrastructure.Statistics; using PrivaPub.Models.Federation; using PrivaPub.Models.Post; namespace PrivaPub.Federation.Inbox { public sealed record Arrival(string ActivityId, string ActivityType, string ActorURI, string Inbox, string KeyId, string Algorithm, IReadOnlyList SignedHeaders, DateTime ReceivedAt, string Context = default) { static readonly AsyncLocal current = new(); public static Arrival Current { get => current.Value; set => current.Value = value; } public ArrivalVerdict Verdict { get; } = new(); public static void Drop(string reason) => Current?.Verdict.Drop(reason); public static void Reject(string reason) => Current?.Verdict.Reject(reason); public static void Accept(string reason) => Current?.Verdict.Accept(reason); public static void About(string objectType = default, PostVisibility? visibility = default, DateTime? created = default, LocalActor local = default) => Current?.Verdict.About(objectType, visibility, created, local); } public sealed class ArrivalVerdict { public string Outcome { get; private set; } public string Reason { get; private set; } public string ObjectType { get; private set; } public string Audience { get; private set; } public string LocalKind { get; private set; } public long? AgeSeconds { get; private set; } public void Drop(string reason) => Decide(Interactions.Dropped, reason); public void Reject(string reason) => Decide(Interactions.Rejected, reason); public void Accept(string reason) => Decide(Interactions.Accepted, reason); void Decide(string outcome, string reason) { if (Outcome != default) return; Outcome = outcome; Reason = reason; } public void About(string objectType, PostVisibility? visibility, DateTime? created, LocalActor local) { ObjectType = objectType ?? ObjectType; if (visibility is { } known) Audience = AudienceOf(known); if (created is { } at) AgeSeconds = Math.Max(0, (long)(DateTime.UtcNow - at).TotalSeconds); if (local != default) LocalKind = local.Kind switch { LocalActorKind.Person => "person", LocalActorKind.Group when !local.IsCircle => "group", LocalActorKind.Application => "application", _ => default }; } public static string AudienceOf(PostVisibility visibility) => visibility switch { PostVisibility.Public => Interactions.Public, PostVisibility.Unlisted => Interactions.Unlisted, _ => Interactions.Private }; } }