Found by the first live run against GoToSocial: - A remote post's id came from its published second plus random bytes, so a reply arriving in the same second as the post it answers could sort under it, and a late arrival landed behind a client's since_id. A post published within the last hour now gets an id for its arrival; backfill keeps its published time. - NoteParser.Time returned default(DateTime) for a missing "updated", so every remote post was stored as edited in year one. Migration _006 clears the stored ones. - published now carries milliseconds, so peers that derive ids from it (GoToSocial, Mastodon) keep our posts in order within a second. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
28 lines
945 B
C#
28 lines
945 B
C#
using System.Buffers.Binary;
|
|
using System.Security.Cryptography;
|
|
|
|
using MongoDB.Bson;
|
|
|
|
namespace PrivaPub.Infrastructure.Ids
|
|
{
|
|
public static class PrivacyIds
|
|
{
|
|
public static string ForDay(DateTime when) => At(DateTime.SpecifyKind(when, DateTimeKind.Utc).Date);
|
|
|
|
public static string Arrived(DateTime published) =>
|
|
DateTime.SpecifyKind(published, DateTimeKind.Utc) > DateTime.UtcNow - LiveWindow ? ObjectId.GenerateNewId().ToString() : At(published);
|
|
|
|
static readonly TimeSpan LiveWindow = TimeSpan.FromHours(1);
|
|
|
|
public static string At(DateTime when)
|
|
{
|
|
var seconds = Math.Clamp(new DateTimeOffset(DateTime.SpecifyKind(when, DateTimeKind.Utc)).ToUnixTimeSeconds(), 0,
|
|
DateTimeOffset.UtcNow.AddDays(1).ToUnixTimeSeconds());
|
|
Span<byte> bytes = stackalloc byte[12];
|
|
BinaryPrimitives.WriteInt32BigEndian(bytes, (int)seconds);
|
|
RandomNumberGenerator.Fill(bytes[4..]);
|
|
return Convert.ToHexStringLower(bytes);
|
|
}
|
|
}
|
|
}
|