import { IsNull } from "typeorm"; import { renderFollowRelay } from "../remote/activitypub/renderer/follow-relay.js"; import { renderActivity, attachLdSignature } from "../remote/activitypub/renderer/index.js"; import renderUndo from "../remote/activitypub/renderer/undo.js"; import { deliver } from "../queue/index.js"; import { Users, Relays } from "../models/index.js"; import { genId } from "../misc/gen-id.js"; import { Cache } from "../misc/cache.js"; import { createSystemUser } from "./create-system-user.js"; const ACTOR_USERNAME = "relay.actor"; const relaysCache = new Cache("relay", 60 * 60); export async function getRelayActor() { const user = await Users.findOneBy({ host: IsNull(), username: ACTOR_USERNAME }); if (user) return user; const created = await createSystemUser(ACTOR_USERNAME); return created; } export async function addRelay(inbox) { const relay = await Relays.insert({ id: genId(), inbox, status: "requesting" }).then((x)=>Relays.findOneByOrFail(x.identifiers[0])); const relayActor = await getRelayActor(); const follow = renderFollowRelay(relay, relayActor); const activity = renderActivity(follow); deliver(relayActor, activity, relay.inbox); return relay; } export async function removeRelay(inbox) { const relay = await Relays.findOneBy({ inbox }); if (relay == null) { throw new Error("relay not found"); } const relayActor = await getRelayActor(); const follow = renderFollowRelay(relay, relayActor); const undo = renderUndo(follow, relayActor); const activity = renderActivity(undo); deliver(relayActor, activity, relay.inbox); await Relays.delete(relay.id); await updateRelaysCache(); } export async function listRelay() { const relays = await Relays.find(); return relays; } export async function getCachedRelays() { return await relaysCache.fetch(null, ()=>Relays.findBy({ status: "accepted" })); } export async function relayAccepted(id) { const result = await Relays.update(id, { status: "accepted" }); await updateRelaysCache(); return JSON.stringify(result); } async function updateRelaysCache() { const relays = await Relays.findBy({ status: "accepted" }); await relaysCache.set(null, relays); } export async function relayRejected(id) { const result = await Relays.update(id, { status: "rejected" }); return JSON.stringify(result); } export async function deliverToRelays(user, activity) { if (activity == null) return; const relays = await getCachedRelays(); if (relays.length === 0) return; // TODO //const copy = structuredClone(activity); const copy = JSON.parse(JSON.stringify(activity)); if (!copy.to) copy.to = [ "https://www.w3.org/ns/activitystreams#Public" ]; const signed = await attachLdSignature(copy, user); for (const relay of relays){ deliver(user, signed, relay.inbox); } }