refactor: move 1b12 announce logic out of inbox and into separate feps module

1b12 announces were previously only happening for local creates and received
activities, but they should happen for all local activities as well.

re: #13072
This commit is contained in:
Julian Lam
2025-02-07 08:21:41 -05:00
parent 608317ba28
commit 9fd6ac6bb8
4 changed files with 71 additions and 57 deletions

36
src/activitypub/feps.js Normal file
View File

@@ -0,0 +1,36 @@
'use strict';
const nconf = require('nconf');
const winston = require('winston');
const posts = require('../posts');
const activitypub = module.parent.exports;
const Feps = module.exports;
Feps.announce = async function announce(id, activity) {
let localId;
if (String(id).startsWith(nconf.get('url'))) {
({ id: localId } = await activitypub.helpers.resolveLocalId(id));
}
const cid = await posts.getCidByPid(localId || id);
const followers = await activitypub.notes.getCategoryFollowers(cid);
if (!followers.length) {
return;
}
const { actor } = activity;
if (actor && !actor.startsWith(nconf.get('url'))) {
followers.unshift(actor);
}
winston.info(`[activitypub/inbox.announce(1b12)] Announcing ${activity.type} to followers of cid ${cid}`);
await activitypub.send('cid', cid, followers, {
id: `${nconf.get('url')}/post/${encodeURIComponent(id)}#activity/announce/${Date.now()}`,
type: 'Announce',
to: [`${nconf.get('url')}/category/${cid}/followers`],
cc: [actor, activitypub._constants.publicAddress],
object: activity,
});
};

View File

@@ -32,34 +32,6 @@ function reject(type, object, target, senderType = 'uid', id = 0) {
}).catch(err => winston.error(err.stack)); }).catch(err => winston.error(err.stack));
} }
// FEP 1b12
async function announce(id, activity) {
let localId;
if (id.startsWith(nconf.get('url'))) {
({ id: localId } = await activitypub.helpers.resolveLocalId(id));
}
const cid = await posts.getCidByPid(localId || id);
const followers = await activitypub.notes.getCategoryFollowers(cid);
if (!followers.length) {
return;
}
const { actor } = activity;
followers.unshift(actor);
winston.info(`[activitypub/inbox.announce(1b12)] Announcing ${activity.type} to followers of cid ${cid}`);
await Promise.all([activity, activity.object].map(async (object) => {
await activitypub.send('cid', cid, followers, {
id: `${nconf.get('url')}/post/${encodeURIComponent(id)}#activity/announce/${Date.now()}`,
type: 'Announce',
to: [`${nconf.get('url')}/category/${cid}/followers`],
cc: [actor, activitypub._constants.publicAddress],
object,
});
}));
}
inbox.create = async (req) => { inbox.create = async (req) => {
const { object } = req.body; const { object } = req.body;
@@ -71,7 +43,7 @@ inbox.create = async (req) => {
const asserted = await activitypub.notes.assert(0, object); const asserted = await activitypub.notes.assert(0, object);
if (asserted) { if (asserted) {
announce(object.id, req.body); activitypub.feps.announce(object.id, req.body);
api.activitypub.add(req, { pid: object.id }); api.activitypub.add(req, { pid: object.id });
} }
}; };
@@ -141,7 +113,7 @@ inbox.update = async (req) => {
const asserted = await activitypub.notes.assert(0, object.id); const asserted = await activitypub.notes.assert(0, object.id);
if (asserted) { if (asserted) {
announce(object.id, req.body); activitypub.feps.announce(object.id, req.body);
} }
break; break;
} }
@@ -229,7 +201,7 @@ inbox.delete = async (req) => {
switch (true) { switch (true) {
case isNote: { case isNote: {
const uid = await posts.getPostField(pid, 'uid'); const uid = await posts.getPostField(pid, 'uid');
await announce(pid, req.body); await activitypub.feps.announce(pid, req.body);
await api.posts[method]({ uid }, { pid }); await api.posts[method]({ uid }, { pid });
break; break;
} }
@@ -263,7 +235,7 @@ inbox.like = async (req) => {
winston.verbose(`[activitypub/inbox/like] id ${id} via ${actor}`); winston.verbose(`[activitypub/inbox/like] id ${id} via ${actor}`);
const result = await posts.upvote(id, actor); const result = await posts.upvote(id, actor);
announce(object.id, req.body); activitypub.feps.announce(object.id, req.body);
socketHelpers.upvote(result, 'notifications:upvoted-your-post-in'); socketHelpers.upvote(result, 'notifications:upvoted-your-post-in');
}; };
@@ -529,7 +501,7 @@ inbox.undo = async (req) => {
} }
await posts.unvote(id, actor); await posts.unvote(id, actor);
announce(object.object, req.body); activitypub.feps.announce(object.object, req.body);
notifications.rescind(`upvote:post:${id}:uid:${actor}`); notifications.rescind(`upvote:post:${id}:uid:${actor}`);
break; break;
} }

View File

@@ -56,6 +56,7 @@ ActivityPub.notes = require('./notes');
ActivityPub.contexts = require('./contexts'); ActivityPub.contexts = require('./contexts');
ActivityPub.actors = require('./actors'); ActivityPub.actors = require('./actors');
ActivityPub.instances = require('./instances'); ActivityPub.instances = require('./instances');
ActivityPub.feps = require('./feps');
ActivityPub.startJobs = () => { ActivityPub.startJobs = () => {
ActivityPub.helpers.log('[activitypub/jobs] Registering jobs.'); ActivityPub.helpers.log('[activitypub/jobs] Registering jobs.');

View File

@@ -128,8 +128,6 @@ activitypubApi.create.note = enabledCheck(async (caller, { pid, post }) => {
const { to, cc, targets } = await activitypub.buildRecipients(object, { pid, uid: post.user.uid }); const { to, cc, targets } = await activitypub.buildRecipients(object, { pid, uid: post.user.uid });
object.to = to; object.to = to;
object.cc = cc; object.cc = cc;
const { cid } = post.category;
const followers = await activitypub.notes.getCategoryFollowers(cid);
const payload = { const payload = {
id: `${object.id}#activity/create/${Date.now()}`, id: `${object.id}#activity/create/${Date.now()}`,
@@ -140,22 +138,11 @@ activitypubApi.create.note = enabledCheck(async (caller, { pid, post }) => {
object, object,
}; };
await activitypub.send('uid', caller.uid, Array.from(targets), payload); await Promise.all([
activitypub.send('uid', caller.uid, Array.from(targets), payload),
setTimeout(() => { // Delay sending to avoid potential race condition activitypub.feps.announce(pid, payload),
if (followers.length) { activitypubApi.add(caller, { pid }),
Promise.all([payload, payload.object].map(async (object) => { ]);
await activitypub.send('cid', cid, followers, {
id: `${nconf.get('url')}/post/${encodeURIComponent(object.object ? object.object.id : object.id)}#activity/announce/${Date.now()}`,
type: 'Announce',
to: [activitypub._constants.publicAddress],
cc: [`${nconf.get('url')}/category/${cid}/followers`],
object,
});
})).catch(err => winston.error(err.stack));
}
activitypubApi.add(caller, { pid });
}, 5000);
}); });
activitypubApi.create.privateNote = enabledCheck(async (caller, { messageObj }) => { activitypubApi.create.privateNote = enabledCheck(async (caller, { messageObj }) => {
@@ -232,7 +219,10 @@ activitypubApi.update.note = enabledCheck(async (caller, { post }) => {
object, object,
}; };
await activitypub.send('uid', caller.uid, Array.from(targets), payload); await Promise.all([
activitypub.send('uid', caller.uid, Array.from(targets), payload),
activitypub.feps.announce(post.pid, payload),
]);
}); });
activitypubApi.update.privateNote = enabledCheck(async (caller, { messageObj }) => { activitypubApi.update.privateNote = enabledCheck(async (caller, { messageObj }) => {
@@ -286,7 +276,10 @@ activitypubApi.delete.note = enabledCheck(async (caller, { pid }) => {
origin: object.context, origin: object.context,
}; };
await activitypub.send('uid', caller.uid, Array.from(targets), payload); await Promise.all([
activitypub.send('uid', caller.uid, Array.from(targets), payload),
activitypub.feps.announce(pid, payload),
]);
}); });
activitypubApi.like = {}; activitypubApi.like = {};
@@ -301,11 +294,17 @@ activitypubApi.like.note = enabledCheck(async (caller, { pid }) => {
return; return;
} }
await activitypub.send('uid', caller.uid, [uid], { const payload = {
id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`, id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`,
type: 'Like', type: 'Like',
actor: `${nconf.get('url')}/uid/${caller.uid}`,
object: pid, object: pid,
}); };
await Promise.all([
activitypub.send('uid', caller.uid, [uid], payload),
activitypub.feps.announce(pid, payload),
]);
}); });
activitypubApi.announce = {}; activitypubApi.announce = {};
@@ -355,16 +354,22 @@ activitypubApi.undo.like = enabledCheck(async (caller, { pid }) => {
return; return;
} }
await activitypub.send('uid', caller.uid, [uid], { const payload = {
id: `${nconf.get('url')}/uid/${caller.uid}#activity/undo:like/${encodeURIComponent(pid)}/${Date.now()}`, id: `${nconf.get('url')}/uid/${caller.uid}#activity/undo:like/${encodeURIComponent(pid)}/${Date.now()}`,
type: 'Undo', type: 'Undo',
actor: `${nconf.get('url')}/uid/${caller.uid}`,
object: { object: {
actor: `${nconf.get('url')}/uid/${caller.uid}`, actor: `${nconf.get('url')}/uid/${caller.uid}`,
id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`, id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`,
type: 'Like', type: 'Like',
object: pid, object: pid,
}, },
}); };
await Promise.all([
activitypub.send('uid', caller.uid, [uid], payload),
activitypub.feps.announce(pid, payload),
]);
}); });
activitypubApi.flag = enabledCheck(async (caller, flag) => { activitypubApi.flag = enabledCheck(async (caller, flag) => {