From 6d4eca013133591af31643569ec5edaa7b66b6e6 Mon Sep 17 00:00:00 2001 From: Nikita Karamov Date: Sat, 18 Mar 2023 15:05:53 +0100 Subject: [PATCH] Improve instance list This now returns the list of instances of multiple Fediverse projects. Currently pretty slow because of the Mastodon and Pleroma being too big. --- src/constants.ts | 14 +++++++++++++ src/pages/api/instances.ts | 42 +++++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 src/constants.ts diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..bf8093c --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,14 @@ +/** + * Enumeration of the supported fediverse projects. + * + * The values of this enum are used as the keys for the fediverse.observer API, + * as the icon names, etc. + */ +export enum FediverseProject { + Friendica = "friendica", + GNUSocial = "gnusocial", + Hubzilla = "hubzilla", + Mastodon = "mastodon", + Misskey = "misskey", + Pleroma = "pleroma", +} diff --git a/src/pages/api/instances.ts b/src/pages/api/instances.ts index 1a16534..58da7d1 100644 --- a/src/pages/api/instances.ts +++ b/src/pages/api/instances.ts @@ -4,20 +4,52 @@ */ import type { APIRoute } from "astro"; +import { FediverseProject } from "../../constants"; -interface MastodonServer { - [key: string]: unknown; +interface ProjectInstance { domain: string; + score: number; + active_users_monthly: number; + status: number; } +const PROJECTS = Object.values(FediverseProject); + +export const fetchInstances = async ( + projectId: string, +): Promise => { + const response = await fetch("https://api.fediverse.observer/", { + headers: { + Accept: "*/*", + "Accept-Language": "en;q=1.0", + "Content-Type": "application/json", + }, + referrer: "https://api.fediverse.observer/", + body: `{"query":"{\\n nodes(softwarename: \\"${projectId}\\") {\\n domain\\n score\\n active_users_monthly\\n status\\n }\\n}\\n"}`, + method: "POST", + }); + const json = await response.json(); + const instances: ProjectInstance[] = json.data.nodes; + return instances.filter( + (instance) => instance.score > 0 && instance.status === 1, + ); +}; + export const get: APIRoute = async () => { try { - const response = await fetch("https://api.joinmastodon.org/servers"); - const instances = await response.json(); + const response = await Promise.all( + PROJECTS.map((projectId) => fetchInstances(projectId)), + ); + const instances = response.flat(); + instances.sort((a, b) => { + return b.active_users_monthly - a.active_users_monthly; + }); return new Response( JSON.stringify( - instances.map((instance: MastodonServer) => instance.domain), + instances + .slice(0, 200) + .map((instance: ProjectInstance) => instance.domain), ), { headers: {