MessageLogger: suppress deletes with an inert event instead of faking MESSAGE_UPDATE
This commit is contained in:
parent
1ff57e2d80
commit
31157788c5
3 changed files with 15 additions and 54 deletions
|
|
@ -3,7 +3,6 @@ import { storage } from "@vendetta/plugin";
|
||||||
import Settings from "./ui/Settings";
|
import Settings from "./ui/Settings";
|
||||||
import { patchFluxIntercept, revertFakedMessages } from "./patches/fluxIntercept";
|
import { patchFluxIntercept, revertFakedMessages } from "./patches/fluxIntercept";
|
||||||
import { patchRowStyling } from "./patches/rowStyling";
|
import { patchRowStyling } from "./patches/rowStyling";
|
||||||
import { patchMessageRecord } from "./patches/messageRecord";
|
|
||||||
|
|
||||||
const TAG = "[MessageLogger]";
|
const TAG = "[MessageLogger]";
|
||||||
const cleanups: (() => void)[] = [];
|
const cleanups: (() => void)[] = [];
|
||||||
|
|
@ -35,9 +34,8 @@ export default {
|
||||||
let patched = 0;
|
let patched = 0;
|
||||||
if (patchFluxIntercept(cleanups)) patched++;
|
if (patchFluxIntercept(cleanups)) patched++;
|
||||||
if (patchRowStyling(cleanups)) patched++;
|
if (patchRowStyling(cleanups)) patched++;
|
||||||
if (patchMessageRecord(cleanups)) patched++;
|
|
||||||
|
|
||||||
console.log(TAG, `onLoad done - ${patched}/3 patches applied`);
|
console.log(TAG, `onLoad done - ${patched}/2 patches applied`);
|
||||||
},
|
},
|
||||||
onUnload() {
|
onUnload() {
|
||||||
console.log(TAG, "onUnload");
|
console.log(TAG, "onUnload");
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import { addLogEntry } from "../lib/store";
|
||||||
import type { FilterOptions } from "../lib/types";
|
import type { FilterOptions } from "../lib/types";
|
||||||
|
|
||||||
const TAG = "[MessageLogger]";
|
const TAG = "[MessageLogger]";
|
||||||
const FAKE_DELETE_FLAG = "__msgLoggerDeleted";
|
|
||||||
const CLEANUP_FLAG = "__msgLoggerCleanup";
|
const CLEANUP_FLAG = "__msgLoggerCleanup";
|
||||||
|
|
||||||
// A busy, high-traffic channel (flooding, spam, price-ticker bots editing the same message
|
// A busy, high-traffic channel (flooding, spam, price-ticker bots editing the same message
|
||||||
|
|
@ -93,8 +92,18 @@ function hasLoggableContent(message: any): boolean {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fakeUpdateFor(original: any): any {
|
// Any action type other than MESSAGE_DELETE stops the real removal - live-verified that
|
||||||
return { type: "MESSAGE_UPDATE", message: { ...original, [FAKE_DELETE_FLAG]: true } };
|
// MESSAGE_EDIT_FAILED_AUTOMOD (the same technique meqativ/dumsane's NoDelete uses) is a genuine
|
||||||
|
// no-op for a message not already in a pending-edit state: dispatching it left the cached
|
||||||
|
// MessageRecord byte-for-byte identical. No need to reconstruct/spread the message into a fake
|
||||||
|
// MESSAGE_UPDATE - that also avoids waking every other MESSAGE_UPDATE listener in the app (unread
|
||||||
|
// counts, embed refresh, etc.) for something that isn't really an edit.
|
||||||
|
function suppressionEventFor(original: any): any {
|
||||||
|
return {
|
||||||
|
type: "MESSAGE_EDIT_FAILED_AUTOMOD",
|
||||||
|
messageData: { type: 0, message: { channelId: original.channel_id, messageId: original.id, content: original.content } },
|
||||||
|
errorResponseBody: { code: 200000, message: "Deleted message kept inline by MessageLogger" },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function captureAndMaybeKeep(original: any, channelId: string, id: string): any | undefined {
|
function captureAndMaybeKeep(original: any, channelId: string, id: string): any | undefined {
|
||||||
|
|
@ -112,7 +121,7 @@ function captureAndMaybeKeep(original: any, channelId: string, id: string): any
|
||||||
|
|
||||||
fakedMessages.set(id, channelId);
|
fakedMessages.set(id, channelId);
|
||||||
evictOldest(fakedMessages, MAX_TRACKED_MESSAGES);
|
evictOldest(fakedMessages, MAX_TRACKED_MESSAGES);
|
||||||
return fakeUpdateFor(original);
|
return suppressionEventFor(original);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSingleDelete(event: any): any {
|
function handleSingleDelete(event: any): any {
|
||||||
|
|
@ -148,7 +157,7 @@ function handleBulkDelete(event: any): any {
|
||||||
const original = ChannelMessages?.get?.(channelId)?.get?.(id);
|
const original = ChannelMessages?.get?.(channelId)?.get?.(id);
|
||||||
if (!original) continue;
|
if (!original) continue;
|
||||||
try {
|
try {
|
||||||
FluxDispatcher.dispatch(fakeUpdateFor(original));
|
FluxDispatcher.dispatch(suppressionEventFor(original));
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(TAG, "Deferred bulk-keep dispatch failed for", id, e?.message ?? e);
|
console.error(TAG, "Deferred bulk-keep dispatch failed for", id, e?.message ?? e);
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +175,6 @@ function handleBulkDelete(event: any): any {
|
||||||
function handleUpdate(event: any): void {
|
function handleUpdate(event: any): void {
|
||||||
const updated = event?.message;
|
const updated = event?.message;
|
||||||
if (!updated?.id) return;
|
if (!updated?.id) return;
|
||||||
if (updated[FAKE_DELETE_FLAG]) return; // our own fake-delete-as-update, not a real edit
|
|
||||||
|
|
||||||
const channelId = updated.channel_id ?? updated.channelId;
|
const channelId = updated.channel_id ?? updated.channelId;
|
||||||
const original = ChannelMessages?.get?.(channelId)?.get?.(updated.id);
|
const original = ChannelMessages?.get?.(channelId)?.get?.(updated.id);
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import { findByName, findByProps } from "@vendetta/metro";
|
|
||||||
import { after, instead } from "@vendetta/patcher";
|
|
||||||
|
|
||||||
const TAG = "[MessageLogger]";
|
|
||||||
const FAKE_DELETE_FLAG = "__msgLoggerDeleted";
|
|
||||||
|
|
||||||
// Discord wraps raw message JSON into a MessageRecord class before it reaches row generation - a
|
|
||||||
// plain custom field on the raw object doesn't reliably survive that wrap without this.
|
|
||||||
export function patchMessageRecord(cleanups: (() => void)[]): boolean {
|
|
||||||
const MessageRecordUtils = findByProps("updateMessageRecord", "createMessageRecord");
|
|
||||||
const MessageRecord = findByName("MessageRecord", false);
|
|
||||||
|
|
||||||
if (!MessageRecordUtils || !MessageRecord) {
|
|
||||||
console.warn(TAG, "MessageRecord module(s) not found - deleted messages may not render styled");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
cleanups.push(
|
|
||||||
after("createMessageRecord", MessageRecordUtils, ([message]: any[], record: any) => {
|
|
||||||
if (message?.[FAKE_DELETE_FLAG]) record[FAKE_DELETE_FLAG] = true;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
cleanups.push(
|
|
||||||
instead("updateMessageRecord", MessageRecordUtils, ([oldRecord, newRecord]: any[], orig: any) => {
|
|
||||||
if (newRecord?.[FAKE_DELETE_FLAG]) {
|
|
||||||
return MessageRecordUtils.createMessageRecord(newRecord, oldRecord?.reactions);
|
|
||||||
}
|
|
||||||
return orig.apply(MessageRecordUtils, [oldRecord, newRecord]);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
cleanups.push(
|
|
||||||
after("default", MessageRecord, ([props]: any[], record: any) => {
|
|
||||||
if (props?.[FAKE_DELETE_FLAG]) record[FAKE_DELETE_FLAG] = true;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} catch (e: any) {
|
|
||||||
console.warn(TAG, "Failed to patch MessageRecord:", e?.message ?? e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue