A Bluesky labeler that labels accounts hosted on PDSes operated by entities other than Bluesky PBC
1import type { FastifyRequest, FastifyReply } from "fastify";
2import type { KnownPDSStorage } from "./knownPDSStorage";
3import type { ActiveLabelsStorage } from "./activeLabelsStorage";
4import { CacheableMemory } from "cacheable";
5
6export class InfoServer {
7 private knownPDSStorage: KnownPDSStorage;
8 private activeLabelsStorage: ActiveLabelsStorage;
9 private maxPDSDedicatedLabels: number;
10
11 private statsCache = new CacheableMemory({ ttl: '10s' });
12
13 constructor(knownPDSStorage: KnownPDSStorage, activeLabelsStorage: ActiveLabelsStorage, maxPDSDedicatedLabels: number) {
14 this.knownPDSStorage = knownPDSStorage;
15 this.activeLabelsStorage = activeLabelsStorage;
16 this.maxPDSDedicatedLabels = maxPDSDedicatedLabels;
17 }
18
19 private readonly cacheKey = "stats";
20
21 private async computeStats(): Promise<number[]> {
22 const v = [
23 await this.knownPDSStorage.countKnownPDSs(),
24 await this.knownPDSStorage.countPDSCrawlingFailures(),
25 await this.activeLabelsStorage.countActiveLabelSubjects(),
26 ];
27 this.statsCache.set(this.cacheKey, v);
28 return v;
29 }
30
31 async indexPage(req: FastifyRequest, resp: FastifyReply) {
32 let [totalPDS, failures, activeLabels] = (
33 this.statsCache.get(this.cacheKey) ??
34 await this.computeStats()
35 ) as number[];
36 resp.type("text/html").send(`
37 <!DOCTYPE html>
38 <html lang="en">
39 <head>
40 <meta charset="UTF-8" />
41 <title>Independent PDS Labeler</title>
42 <meta name="viewport" content="width=device-width,initial-scale=1" />
43 <meta name="description" content="Information page for the independent PDS labeler for Bluesky - @pds.labeler.tny.im" />
44 </head>
45
46 <body>
47 <h1>pds.labeler.tny.im</h1>
48 <p>
49 This community ran Bluesky labeler identifies accounts that are hosted on a
50 <a rel="noreferrer nofollow" href="https://github.com/bluesky-social/pds">PDS</a>
51 not operated by
52 <a rel="noreferrer nofollow" href="https://bsky.social/about/faq">Bluesky PBC</a>, and which is, therefore, considered "independent."
53 Some PDS meet this criteria but are not considered, for technical or logistical reasons.
54 </p>
55 <p>This labeler provides dedicated labels for the ${this.maxPDSDedicatedLabels} biggest independent PDS that it is aware of, by number of accounts.</p>
56 <p><a rel="noreferrer nofollow" href="https://bsky.app/profile/pds.labeler.tny.im">Subscribe to the labeler on Bluesky to use it.</a></p>
57 <p>
58 This labeler works by enumerating accounts (repositories) within each PDS that it finds.
59 It finds new PDS by consuming some events from the Bluesky firehose, and fetching the DID documents of the respective accounts, in order to identify or confirm their current PDS host.
60 Additionally, known PDS are rescanned periodically in order to find and label new accounts.
61 </p>
62 <p>The source code for the labeler is available on <a rel="noreferrer nofollow" href="https://tangled.org/gbl08ma.com/pdslabeler">Tangled</a> under a dual MIT and Apache-2.0 licensing scheme.</p>
63 <p>
64 This labeler is aware of ${activeLabels} accounts hosted on a total of ${totalPDS} independent PDS.
65 It is failing to crawl ${failures} of these PDS, most of which correspond to nonexistent, offline or otherwise malfunctioning or misidentified PDS.
66 </p>
67 </body>
68
69 </html>
70 `);
71 }
72}