From 20e17e639d5bf0387ab1c40cc04ee73650c06b25 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 15 Apr 2026 12:39:14 -0400 Subject: [PATCH] refactor: move ap analytics methods to its own file --- src/activitypub/analytics.js | 60 ++++++++++++++++++++++++++++ src/activitypub/index.js | 58 +-------------------------- src/controllers/activitypub/index.js | 4 +- 3 files changed, 64 insertions(+), 58 deletions(-) create mode 100644 src/activitypub/analytics.js diff --git a/src/activitypub/analytics.js b/src/activitypub/analytics.js new file mode 100644 index 0000000000..c3297c879b --- /dev/null +++ b/src/activitypub/analytics.js @@ -0,0 +1,60 @@ +'use strict'; + +const db = require('../database'); +const analytics = require('../analytics'); + +const activitypub = module.parent.exports; + +const Analytics = module.exports; + +Analytics.receipt = async ({ id, type, actor }) => { + const now = Date.now(); + const { hostname } = new URL(actor); + + await Promise.all([ + db.sortedSetAdd(`activities:datetime`, now, id), + activitypub.instances.log(hostname), + analytics.increment(['activities', `activities:byType:${type}`, `activities:byHost:${hostname}`]), + ]); +}; + +Analytics.send = async ({ type, target }) => { + const { hostname } = new URL(target); + + await Promise.all([ + activitypub.instances.log(hostname), + analytics.increment(['ap.out', `ap.out:byType:${type}`, `ap.out:byHost:${hostname}`]), + ]); +}; + +Analytics.sendError = async ({ payload, uri, error }) => { + const { id } = payload; + const now = Date.now(); + const { hostname } = new URL(uri); + await Promise.all([ + db.sortedSetAdd('ap.errors', now, id), + db.setObject(`ap.errors:${id}`, { + type: 'out', + body: JSON.stringify(payload), + stack: error.message, + }), + analytics.increment(['ap.outErr', `ap.outErr:byType:${payload.type}`, `ap.outErr:byHost:${hostname}`]), + ]); + await db.expire(`ap.errors:${id}`, 60 * 60 * 24); // 24 hours +}; + +Analytics.receiptError = async (body, error) => { + const { id, actor } = body; + const now = Date.now(); + const { hostname } = new URL(actor); + await Promise.all([ + db.sortedSetAdd('ap.errors', now, id), + db.setObject(`ap.errors:${id}`, { + type: 'in', + body: JSON.stringify(body), + stack: error.stack, + }), + analytics.increment(['ap.inErr', `ap.inErr:byHost:${hostname}`]), + ]); + await db.expire(`ap.errors:${id}`, 60 * 60 * 24); // 24 hours +}; \ No newline at end of file diff --git a/src/activitypub/index.js b/src/activitypub/index.js index 1f601df4f6..170e5ab65a 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -386,7 +386,7 @@ ActivityPub._sendMessage = async function (uri, keyData, payload, digest) { }); if (String(response.statusCode).startsWith('2')) { - ActivityPub.record.send({ + ActivityPub.analytics.send({ type: payload.type, target: uri, }); @@ -399,7 +399,7 @@ ActivityPub._sendMessage = async function (uri, keyData, payload, digest) { throw new Error(String(body)); } catch (e) { ActivityPub.helpers.log(`[activitypub/send] Could not send ${payload.type} to ${uri}; error: ${e.message}`); - ActivityPub.record.sendError({ + ActivityPub.analytics.sendError({ payload, uri, error: e, @@ -477,60 +477,6 @@ ActivityPub.send = async (type, id, targets, payload) => { }); }; -ActivityPub.record = {}; - -ActivityPub.record.receipt = async ({ id, type, actor }) => { - const now = Date.now(); - const { hostname } = new URL(actor); - - await Promise.all([ - db.sortedSetAdd(`activities:datetime`, now, id), - ActivityPub.instances.log(hostname), - analytics.increment(['activities', `activities:byType:${type}`, `activities:byHost:${hostname}`]), - ]); -}; - -ActivityPub.record.send = async ({ type, target }) => { - const { hostname } = new URL(target); - - await Promise.all([ - ActivityPub.instances.log(hostname), - analytics.increment(['ap.out', `ap.out:byType:${type}`, `ap.out:byHost:${hostname}`]), - ]); -}; - -ActivityPub.record.sendError = async ({ payload, uri, error }) => { - const { id } = payload; - const now = Date.now(); - const { hostname } = new URL(uri); - await Promise.all([ - db.sortedSetAdd('ap.errors', now, id), - db.setObject(`ap.errors:${id}`, { - type: 'out', - body: JSON.stringify(payload), - stack: error.message, - }), - analytics.increment(['ap.outErr', `ap.outErr:byType:${payload.type}`, `ap.outErr:byHost:${hostname}`]), - ]); - await db.expire(`ap.errors:${id}`, 60 * 60 * 24); // 24 hours -}; - -ActivityPub.record.receiptError = async (body, error) => { - const { id, actor } = body; - const now = Date.now(); - const { hostname } = new URL(actor); - await Promise.all([ - db.sortedSetAdd('ap.errors', now, id), - db.setObject(`ap.errors:${id}`, { - type: 'in', - body: JSON.stringify(body), - stack: error.stack, - }), - analytics.increment(['ap.inErr', `ap.inErr:byHost:${hostname}`]), - ]); - await db.expire(`ap.errors:${id}`, 60 * 60 * 24); // 24 hours -}; - ActivityPub.buildRecipients = async function (object, options) { /** * - Builds a list of targets for activitypub.send to consume diff --git a/src/controllers/activitypub/index.js b/src/controllers/activitypub/index.js index 021b404ca4..79f1ec87ff 100644 --- a/src/controllers/activitypub/index.js +++ b/src/controllers/activitypub/index.js @@ -269,10 +269,10 @@ Controller.postInbox = async (req, res) => { try { await activitypub.inbox[method](req); - await activitypub.record.receipt(req.body); + await activitypub.analytics.receipt(req.body); await helpers.formatApiResponse(202, res); } catch (e) { - activitypub.record.receiptError(req.body, e); + activitypub.analytics.receiptError(req.body, e); if (req.body?.type && req.body?.object && req.body?.actor) { activitypub.inbox._reject(req.body.type, req.body.object, req.body.actor); } else {