Build / Build (push) Successful in 36s
- ObjectRecord, one per stored remote object: the raw JSON (up to 256 KB, always hashed), delivered or fetched, refetched from origin or not, the activity that brought it (or caused the fetch), shared or personal inbox, the signature's key, algorithm and signed headers, received time, published and updated, the delivering activity's @context, and up to ten later revisions from Update. - Delivery details travel from InboxReceiver through the inbox job to the handlers as Arrival.Current. - A host is described from its NodeInfo when we first hear from it, at most weekly (DescribeInstance job), never when someone opens the details view. - GET /api/privapub/v1/statuses/:id/provenance and /api/privapub/v1/instances/:host, with the extensions an object used detected from its raw form (044f quotes, interaction policies, contexts, proofs, Misskey fields, MFM, FEP-8967 links, emoji, polls, language maps, url variants, Markdown content). Checked live: a GoToSocial reply shows as delivered to the shared inbox, signed hs2019 with GoToSocial's fragment-less key id, with its interaction policy detected, and gts.test is described as gotosocial 0.22.1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
129 lines
6.0 KiB
C#
129 lines
6.0 KiB
C#
using MongoDB.Bson;
|
|
using MongoDB.Driver;
|
|
using MongoDB.Entities;
|
|
|
|
using PrivaPub.Models.Federation;
|
|
using PrivaPub.Models.Group;
|
|
using PrivaPub.Models.Jobs;
|
|
using PrivaPub.Models.Post;
|
|
using PrivaPub.Models.Social;
|
|
using PrivaPub.Models.User;
|
|
|
|
namespace PrivaPub.Infrastructure.Data
|
|
{
|
|
public static class Indexes
|
|
{
|
|
public static async Task Create(CancellationToken token = default)
|
|
{
|
|
await Unique<Post>(p => p.ObjectURI, Builders<Post>.Filter.Type(p => p.ObjectURI, BsonType.String), token);
|
|
await Plain<Post>(token, p => p.GroupUserId, p => p.ID);
|
|
await Plain<Post>(token, p => p.GroupId, p => p.ID);
|
|
await Plain<Post>(token, p => p.ActorURI);
|
|
await Plain<Post>(token, p => p.ConversationId, p => p.ID);
|
|
await Plain<Post>(token, p => p.InReplyToURI);
|
|
await DB.Default.Index<Post>().Key(p => p.Geo, KeyType.Geo2DSphere).CreateAsync(token);
|
|
|
|
await Unique<DmPost>(p => p.ObjectURI, Builders<DmPost>.Filter.Type(p => p.ObjectURI, BsonType.String), token);
|
|
await Plain<DmPost>(token, p => p.GroupId, p => p.ID);
|
|
|
|
await Unique<ForeignAvatar>(a => a.ActorURI, Builders<ForeignAvatar>.Filter.Type(a => a.ActorURI, BsonType.String), token);
|
|
await Plain<ForeignAvatar>(token, a => a.PublicKeyId);
|
|
|
|
await DB.Default.Index<Follower>()
|
|
.Key(f => f.LocalActorId, KeyType.Ascending)
|
|
.Key(f => f.LocalActorKind, KeyType.Ascending)
|
|
.Key(f => f.ActorURI, KeyType.Ascending)
|
|
.Option(o => o.Unique = true)
|
|
.CreateAsync(token);
|
|
await Plain<Follower>(token, f => f.ActorURI);
|
|
|
|
await DB.Default.Index<RootToAvatar>()
|
|
.Key(r => r.RootId, KeyType.Ascending)
|
|
.Key(r => r.AvatarId, KeyType.Ascending)
|
|
.Option(o => o.Unique = true)
|
|
.CreateAsync(token);
|
|
await Plain<RootToAvatar>(token, r => r.AvatarId);
|
|
|
|
await Unique<ReservedName>(r => r.Name, Builders<ReservedName>.Filter.Type(r => r.Name, BsonType.String), token);
|
|
await Unique<RootUser>(u => u.UserName, Builders<RootUser>.Filter.Type(u => u.UserName, BsonType.String), token);
|
|
await Plain<Avatar>(token, a => a.UserName);
|
|
await Plain<Group>(token, g => g.UserName);
|
|
await Plain<Group>(token, g => g.InvitationCode);
|
|
|
|
await Plain<DmGroup>(token, g => g.ParticipantsKey);
|
|
|
|
await Plain<Delivery>(token, d => d.DeliveredAt, d => d.AbandonedAt, d => d.NextAttemptAt);
|
|
|
|
await Plain<Job>(token, j => j.Kind, j => j.State, j => j.RunAt);
|
|
await Plain<Job>(token, j => j.State, j => j.LeasedUntil);
|
|
await Unique<Job>(j => j.DedupeKey, Builders<Job>.Filter.Type(j => j.DedupeKey, BsonType.String), token);
|
|
await DB.Default.Index<Job>()
|
|
.Key(j => j.FinishedAt, KeyType.Ascending)
|
|
.Option(o => o.ExpireAfter = TimeSpan.FromDays(7))
|
|
.CreateAsync(token);
|
|
await DB.Default.Index<Following>()
|
|
.Key(f => f.AvatarId, KeyType.Ascending)
|
|
.Key(f => f.TargetActorURI, KeyType.Ascending)
|
|
.Option(o => o.Unique = true)
|
|
.CreateAsync(token);
|
|
await Plain<Following>(token, f => f.TargetActorURI, f => f.State);
|
|
await Plain<Following>(token, f => f.TargetAccountId, f => f.State);
|
|
await Plain<Following>(token, f => f.FollowActivityURI);
|
|
await DB.Default.Index<TimelineEntry>()
|
|
.Key(e => e.AvatarId, KeyType.Ascending)
|
|
.Key(e => e.PostId, KeyType.Ascending)
|
|
.Option(o => o.Unique = true)
|
|
.CreateAsync(token);
|
|
await Plain<TimelineEntry>(token, e => e.PostId);
|
|
await Unique<Notification>(n => n.DedupeKey, Builders<Notification>.Filter.Type(n => n.DedupeKey, BsonType.String), token);
|
|
await Plain<Notification>(token, n => n.AvatarId, n => n.ID);
|
|
await DB.Default.Index<Favourite>()
|
|
.Key(f => f.AccountId, KeyType.Ascending)
|
|
.Key(f => f.PostId, KeyType.Ascending)
|
|
.Option(o => o.Unique = true)
|
|
.CreateAsync(token);
|
|
await Plain<Favourite>(token, f => f.ActivityURI);
|
|
await DB.Default.Index<Marker>()
|
|
.Key(m => m.AvatarId, KeyType.Ascending)
|
|
.Key(m => m.Timeline, KeyType.Ascending)
|
|
.Option(o => o.Unique = true)
|
|
.CreateAsync(token);
|
|
foreach (var pair in new (Func<Task>, string)[]
|
|
{
|
|
(() => DB.Default.Index<Block>().Key(b => b.AvatarId, KeyType.Ascending).Key(b => b.TargetActorURI, KeyType.Ascending).Option(o => o.Unique = true).CreateAsync(token), "block"),
|
|
(() => DB.Default.Index<Mute>().Key(m => m.AvatarId, KeyType.Ascending).Key(m => m.TargetActorURI, KeyType.Ascending).Option(o => o.Unique = true).CreateAsync(token), "mute"),
|
|
(() => DB.Default.Index<AccountDomainBlock>().Key(b => b.AvatarId, KeyType.Ascending).Key(b => b.Domain, KeyType.Ascending).Option(o => o.Unique = true).CreateAsync(token), "domain block"),
|
|
(() => DB.Default.Index<Bookmark>().Key(b => b.AvatarId, KeyType.Ascending).Key(b => b.PostId, KeyType.Ascending).Option(o => o.Unique = true).CreateAsync(token), "bookmark"),
|
|
(() => DB.Default.Index<Pin>().Key(p => p.AvatarId, KeyType.Ascending).Key(p => p.PostId, KeyType.Ascending).Option(o => o.Unique = true).CreateAsync(token), "pin")
|
|
})
|
|
await pair.Item1();
|
|
await Plain<Block>(token, b => b.TargetActorURI);
|
|
await Plain<Mute>(token, m => m.TargetActorURI);
|
|
await Plain<Report>(token, r => r.IsResolved, r => r.ID);
|
|
await Unique<DomainBlock>(b => b.Domain, Builders<DomainBlock>.Filter.Type(b => b.Domain, BsonType.String), token);
|
|
await Unique<RemoteInstance>(i => i.Host, Builders<RemoteInstance>.Filter.Type(i => i.Host, BsonType.String), token);
|
|
await Unique<ObjectRecord>(r => r.ObjectURI, Builders<ObjectRecord>.Filter.Type(r => r.ObjectURI, BsonType.String), token);
|
|
await Plain<ObjectRecord>(token, r => r.PostId);
|
|
}
|
|
|
|
static async Task Unique<T>(System.Linq.Expressions.Expression<Func<T, object>> key, FilterDefinition<T> partial,
|
|
CancellationToken token) where T : IEntity =>
|
|
await DB.Default.Index<T>()
|
|
.Key(key, KeyType.Ascending)
|
|
.Option(o =>
|
|
{
|
|
o.Unique = true;
|
|
o.PartialFilterExpression = partial;
|
|
})
|
|
.CreateAsync(token);
|
|
|
|
static async Task Plain<T>(CancellationToken token, params System.Linq.Expressions.Expression<Func<T, object>>[] keys) where T : IEntity
|
|
{
|
|
var index = DB.Default.Index<T>();
|
|
foreach (var key in keys)
|
|
index.Key(key, KeyType.Ascending);
|
|
await index.CreateAsync(token);
|
|
}
|
|
}
|
|
}
|