Fix DB peer.paste

This commit is contained in:
Raven Scott
2026-05-27 23:20:35 -04:00
parent 83b7f210a3
commit 996969de19
2 changed files with 48 additions and 21 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "Peer Paste",
"version": "1.3.0",
"version": "1.3.1",
"domain": "peer.paste",
"enabled": true,
"description": "Temporary P2P text snippets with expiration and burn-after-read options",
+47 -20
View File
@@ -219,7 +219,28 @@ function shouldDeleteAfterRead(paste, nextReadCount) {
}
async function deletePaste(paste) {
await sdk.db.delete(COLLECTION, { id: paste.id });
await withDbRecovery('deletePaste', () => sdk.db.delete(COLLECTION, { id: paste.id }));
}
function isUnknownCollectionError(err) {
const msg = (err && err.message) || '';
return /unknown collection/i.test(msg);
}
async function withDbRecovery(context, fn) {
try {
return await fn();
} catch (err) {
if (!isUnknownCollectionError(err)) throw err;
sdk.log.warn('peer.paste', `${context}: unknown collection, running db.update() then retry`);
try {
await sdk.db.update();
await sdk.db.ready(10000);
} catch (refreshErr) {
sdk.log.warn('peer.paste', `${context}: db refresh failed: ${refreshErr.message}`);
}
return fn();
}
}
function isQueryTimeoutError(err) {
@@ -236,7 +257,7 @@ async function safeFindPastes(options = {}) {
} = options;
const queryOptions = { limit: maxEntries };
const run = async () => sdk.db.find(COLLECTION, {}, queryOptions);
const run = async () => withDbRecovery(context, () => sdk.db.find(COLLECTION, {}, queryOptions));
try {
let rows = await run();
@@ -354,8 +375,10 @@ async function createPaste(req, res) {
expiresAt
};
await sdk.db.insert(COLLECTION, paste);
await sdk.db.flush();
await withDbRecovery('createPaste.insert', async () => {
await sdk.db.insert(COLLECTION, paste);
await sdk.db.flush();
});
return sdk.router.json(res, {
success: true,
@@ -404,7 +427,7 @@ async function listPastes(req, res, ownerOnly = false) {
}
async function getPasteMetadata(res, pasteId) {
const raw = await sdk.db.get(COLLECTION, { id: pasteId });
const raw = await withDbRecovery('getPasteMetadata.get', () => sdk.db.get(COLLECTION, { id: pasteId }));
const paste = normalizeStoredPaste(raw);
if (!paste) return sdk.router.notFound(res, 'Paste not found');
let attachments = [];
@@ -426,7 +449,7 @@ async function getPasteMetadata(res, pasteId) {
}
async function getPasteAttachments(res, pasteId, attachmentId = null) {
const raw = await sdk.db.get(COLLECTION, { id: pasteId });
const raw = await withDbRecovery('getPasteAttachments.get', () => sdk.db.get(COLLECTION, { id: pasteId }));
const paste = normalizeStoredPaste(raw);
if (!paste) return sdk.router.notFound(res, 'Paste not found');
let attachments = [];
@@ -451,7 +474,7 @@ async function getPasteAttachments(res, pasteId, attachmentId = null) {
}
async function consumePaste(res, pasteId) {
const raw = await sdk.db.get(COLLECTION, { id: pasteId });
const raw = await withDbRecovery('consumePaste.get', () => sdk.db.get(COLLECTION, { id: pasteId }));
const paste = normalizeStoredPaste(raw);
if (!paste || !isConsumable(paste)) {
return sdk.router.notFound(res, 'Paste not found or expired');
@@ -463,12 +486,12 @@ async function consumePaste(res, pasteId) {
if (consumed) {
await deletePaste(paste);
} else {
await sdk.db.insert(COLLECTION, {
await withDbRecovery('consumePaste.insert', () => sdk.db.insert(COLLECTION, {
...paste,
readCount: nextReadCount
});
}));
}
await sdk.db.flush();
await withDbRecovery('consumePaste.flush', () => sdk.db.flush());
const encryptedPayload = decodeEncryptedContent(paste.content);
let attachments = [];
@@ -494,7 +517,7 @@ async function updatePaste(req, res, pasteId) {
const localPeer = await sdk.auth.requireLocalPeer(req, res);
if (!localPeer) return true;
const existing = normalizeStoredPaste(await sdk.db.get(COLLECTION, { id: pasteId }));
const existing = normalizeStoredPaste(await withDbRecovery('updatePaste.get', () => sdk.db.get(COLLECTION, { id: pasteId })));
if (!existing) return sdk.router.notFound(res, 'Paste not found');
if (existing.ownerPeerId && existing.ownerPeerId !== localPeer) {
return sdk.router.forbidden(res, 'Only the owner can update this paste');
@@ -539,8 +562,10 @@ async function updatePaste(req, res, pasteId) {
: existing.expiresAt
};
await sdk.db.insert(COLLECTION, updated);
await sdk.db.flush();
await withDbRecovery('updatePaste.insert', async () => {
await sdk.db.insert(COLLECTION, updated);
await sdk.db.flush();
});
return sdk.router.json(res, {
success: true,
@@ -552,7 +577,7 @@ async function deletePasteRoute(req, res, pasteId) {
const localPeer = await sdk.auth.requireLocalPeer(req, res);
if (!localPeer) return true;
const paste = normalizeStoredPaste(await sdk.db.get(COLLECTION, { id: pasteId }));
const paste = normalizeStoredPaste(await withDbRecovery('deletePasteRoute.get', () => sdk.db.get(COLLECTION, { id: pasteId })));
if (!paste) return sdk.router.notFound(res, 'Paste not found');
if (paste.ownerPeerId && paste.ownerPeerId !== localPeer) {
return sdk.router.forbidden(res, 'Only the owner can delete this paste');
@@ -1139,8 +1164,10 @@ function setupWebSocketHandlers() {
expiresAt
};
await sdk.db.insert(COLLECTION, paste);
await sdk.db.flush();
await withDbRecovery('ws.create.insert', async () => {
await sdk.db.insert(COLLECTION, paste);
await sdk.db.flush();
});
metrics.createCount += 1;
sdk.websocket.send(ws, {
@@ -1164,7 +1191,7 @@ function setupWebSocketHandlers() {
return;
}
const localPeer = sdk.state.localPeerId || '';
const paste = await sdk.db.get(COLLECTION, { id: pasteId });
const paste = await withDbRecovery('ws.destroy.get', () => sdk.db.get(COLLECTION, { id: pasteId }));
if (!paste) {
sdk.websocket.send(ws, { type: 'error', error: 'Paste not found', requestId: message.requestId || null });
return;
@@ -1264,7 +1291,7 @@ async function handler(req, res) {
if (path.startsWith('p/') && method === 'GET') {
const pasteId = path.slice('p/'.length);
const paste = await sdk.db.get(COLLECTION, { id: pasteId });
const paste = await withDbRecovery('viewPaste.get', () => sdk.db.get(COLLECTION, { id: pasteId }));
if (!paste || !isConsumable(paste)) {
return sdk.router.notFound(res, 'Paste not found or expired');
}
@@ -1274,9 +1301,9 @@ async function handler(req, res) {
if (consumed) {
await deletePaste(paste);
} else {
await sdk.db.insert(COLLECTION, { ...paste, readCount: nextReadCount });
await withDbRecovery('viewPaste.insert', () => sdk.db.insert(COLLECTION, { ...paste, readCount: nextReadCount }));
}
await sdk.db.flush();
await withDbRecovery('viewPaste.flush', () => sdk.db.flush());
return sdk.router.html(res, renderPastePage(paste), 200);
}