Files
SocialPub/PrivaPub/Infrastructure/Http/HttpScope.cs
T
thepraandClaude Opus 5.5 d37999970c M5: outbound requests, previews, the media proxy and served traffic
- HttpScope (AsyncLocal) tags each outbound request with a purpose and a trigger:
  - purpose is set by the caller: actor, key, object, webfinger, context, nodeinfo;
  - trigger is set by the job kind, by "verify" during inbox verification, or defaults
    to "request".
- FederationHttp records every JSON, media and stream fetch: status, time, bytes, hops,
  and an outcome of ok, refused or failed, with a reason: disallowed, remembered,
  bad-redirect, too-many-redirects, content-type, too-large, bad-json, private-address,
  timeout, network, or the status. A fetch a reader caused (trigger "request") is only
  counted per server per day.
- Link previews record a 'preview' event: card, no-card or failed.
- The media proxy counts cache hits.
- TrafficMeter counts the client API per endpoint group, method and status class. It
  counts our served documents (actor, outbox, collection, object, activity, licence,
  webfinger, nodeinfo) by kind, status and whether signed, per day and never per server,
  and never names a circle's collections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ELjqpznMFMNrJoJUj6K5p2
2026-10-03 11:10:42 +02:00

40 lines
1.2 KiB
C#

namespace PrivaPub.Infrastructure.Http
{
public static class HttpScope
{
public const string Request = "request";
sealed record Tags(string Purpose, string Trigger, bool Crawl);
static readonly AsyncLocal<Tags> current = new();
public static string Purpose => current.Value?.Purpose;
public static string Trigger => current.Value?.Trigger ?? Request;
public static bool Crawling => current.Value?.Crawl == true;
public static IDisposable For(string purpose) => Push(tags => tags with { Purpose = purpose });
public static IDisposable Default(string purpose) => Push(tags => tags with { Purpose = tags.Purpose ?? purpose });
public static IDisposable Triggered(string trigger) => Push(tags => tags with { Trigger = trigger });
public static IDisposable Crawl() => Push(tags => tags with { Crawl = true });
static IDisposable Push(Func<Tags, Tags> change)
{
var previous = current.Value;
current.Value = change(previous ?? new Tags(default, default, false));
return new Restore(previous);
}
sealed class Restore : IDisposable
{
readonly Tags _previous;
public Restore(Tags previous) => _previous = previous;
public void Dispose() => current.Value = _previous;
}
}
}