From 2688b6bbdcd31f4c2af116924eca449de5f587c2 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 25 Mar 2024 14:55:25 -0400 Subject: [PATCH] feat: add assertion lock on activitypub.notes.assert --- src/activitypub/notes.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index f8330849df..5c3bd70e8f 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -16,6 +16,15 @@ const utils = require('../utils'); const activitypub = module.parent.exports; const Notes = module.exports; +async function lock(value) { + const count = await db.incrObjectField('locks', value); + return count <= 1; +} + +async function unlock(value) { + await db.deleteObjectField('locks', value); +} + Notes.assert = async (uid, input) => { /** * Given the id or object of any as:Note, traverses up to cache the entire threaded context @@ -25,8 +34,16 @@ Notes.assert = async (uid, input) => { */ const object = !activitypub.helpers.isUri(input) && input; + const id = object ? object.id : input; + + const lockStatus = await lock(id, '[[error:activitypub.already-asserting]]'); + if (!lockStatus) { // unable to achieve lock, stop processing. + return null; + } + const chain = Array.from(await Notes.getParentChain(uid, input)); if (!chain.length) { + unlock(id); return null; } @@ -39,6 +56,7 @@ Notes.assert = async (uid, input) => { if (tid && members.every(Boolean)) { // All cached, return early. winston.verbose('[notes/assert] No new notes to process.'); + unlock(id); return tid; } @@ -60,6 +78,7 @@ Notes.assert = async (uid, input) => { const privilege = `topics:${tid ? 'reply' : 'create'}`; const allowed = await privileges.categories.can(privilege, cid, activitypub._constants.uid); if (!allowed) { + unlock(id); return null; } @@ -141,7 +160,10 @@ Notes.assert = async (uid, input) => { } } - await Notes.syncUserInboxes(tid); + await Promise.all([ + Notes.syncUserInboxes(tid), + unlock(id), + ]); return { tid, count }; };