SplitMessages: add remote block-check (fail-closed) and hard chunk cap
This commit is contained in:
parent
4d06a05abc
commit
a48b49f54f
1 changed files with 82 additions and 28 deletions
|
|
@ -1,22 +1,29 @@
|
|||
import { findByProps, findByStoreName } from "@vendetta/metro";
|
||||
import { before, instead } from "@vendetta/patcher";
|
||||
import { storage } from "@vendetta/plugin";
|
||||
import { instead } from "@vendetta/patcher";
|
||||
import { id, storage } from "@vendetta/plugin";
|
||||
import { getAssetIDByName } from "@vendetta/ui/assets";
|
||||
import { showToast } from "@vendetta/ui/toasts";
|
||||
import { checkPluginStatus } from "@shared/lib/backend";
|
||||
import { checkForUpdate } from "@shared/lib/reload";
|
||||
import { intoChunks } from "./lib/split";
|
||||
import Settings from "./ui/Settings";
|
||||
|
||||
const MAX_CHUNKS = 20;
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((r) => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
let unpatchMaxLength: (() => boolean) | undefined;
|
||||
let unpatchSend: (() => boolean) | undefined;
|
||||
let unpatchEdit: (() => boolean) | undefined;
|
||||
|
||||
export default {
|
||||
onLoad() {
|
||||
storage.splitOnWords ??= false;
|
||||
|
||||
checkForUpdate(id).catch(() => {});
|
||||
|
||||
const MaxLengthModule = findByProps("getMaxMessageLength");
|
||||
const MessageActions = findByProps("sendMessage", "editMessage");
|
||||
const UserStore = findByStoreName("UserStore");
|
||||
|
|
@ -24,44 +31,91 @@ export default {
|
|||
|
||||
unpatchMaxLength = instead("getMaxMessageLength", MaxLengthModule, () => 2 ** 30);
|
||||
|
||||
unpatchSend = before("sendMessage", MessageActions, (args: any[]) => {
|
||||
const [channelId, message] = args;
|
||||
const content: string = message?.content ?? "";
|
||||
const maxLength = UserStore.getCurrentUser()?.premiumType === 2 ? 4000 : 2000;
|
||||
if (content.length <= maxLength) return;
|
||||
|
||||
const chunks = intoChunks(content, maxLength, storage.splitOnWords);
|
||||
if (!chunks) {
|
||||
message.content = "";
|
||||
showToast("Message too long to split", getAssetIDByName("Small"));
|
||||
return;
|
||||
}
|
||||
|
||||
message.content = chunks.shift();
|
||||
const maxLength = () => (UserStore.getCurrentUser()?.premiumType === 2 ? 4000 : 2000);
|
||||
|
||||
const delayFor = (channelId: string) => {
|
||||
const channel = ChannelStore.getChannel(channelId);
|
||||
const delay = Math.max((channel?.rateLimitPerUser ?? 0) * 1000, 1000);
|
||||
return Math.max((channel?.rateLimitPerUser ?? 0) * 1000, 1000);
|
||||
};
|
||||
|
||||
(async () => {
|
||||
const sendChunks = async (channelId: string, chunks: string[], template: any) => {
|
||||
for (const chunk of chunks) {
|
||||
await sleep(delay);
|
||||
await sleep(delayFor(channelId));
|
||||
await MessageActions._sendMessage(
|
||||
channelId,
|
||||
{
|
||||
invalidEmojis: message.invalidEmojis,
|
||||
validNonShortcutEmojis: message.validNonShortcutEmojis,
|
||||
invalidEmojis: template.invalidEmojis,
|
||||
validNonShortcutEmojis: template.validNonShortcutEmojis,
|
||||
tts: false,
|
||||
content: chunk,
|
||||
},
|
||||
{}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
unpatchSend = instead("sendMessage", MessageActions, ([channelId, message, promise, options]: any[], orig: (a: any[]) => any) => {
|
||||
const content: string = message?.content ?? "";
|
||||
const limit = maxLength();
|
||||
const hasAttachments = !!options?.attachmentsToUpload?.length;
|
||||
|
||||
if (content.length <= limit && !hasAttachments) return orig([channelId, message, promise, options]);
|
||||
|
||||
const chunks = content ? intoChunks(content, limit, storage.splitOnWords) : [];
|
||||
if (chunks === false || chunks.length > MAX_CHUNKS) {
|
||||
showToast("Message too long to split", getAssetIDByName("Small"));
|
||||
return;
|
||||
}
|
||||
|
||||
return (async () => {
|
||||
const status = await checkPluginStatus(UserStore.getCurrentUser()?.id, id);
|
||||
if (status.blocked) {
|
||||
showToast("Split Messages is unavailable right now", getAssetIDByName("Small"));
|
||||
return orig([channelId, message, promise, options]);
|
||||
}
|
||||
|
||||
if (hasAttachments) {
|
||||
await sendChunks(channelId, chunks, message);
|
||||
if (chunks.length) await sleep(delayFor(channelId));
|
||||
await orig([channelId, { ...message, content: "" }, promise, options]);
|
||||
return;
|
||||
}
|
||||
|
||||
const first = { ...message, content: chunks.shift() };
|
||||
await orig([channelId, first, promise, options]);
|
||||
await sendChunks(channelId, chunks, message);
|
||||
})();
|
||||
});
|
||||
|
||||
unpatchEdit = instead("editMessage", MessageActions, ([channelId, messageId, message]: any[], orig: (a: any[]) => any) => {
|
||||
const content: string = message?.content ?? "";
|
||||
const limit = maxLength();
|
||||
|
||||
if (content.length <= limit) return orig([channelId, messageId, message]);
|
||||
|
||||
const chunks = intoChunks(content, limit, storage.splitOnWords);
|
||||
if (!chunks || chunks.length > MAX_CHUNKS) {
|
||||
showToast("Message too long to split", getAssetIDByName("Small"));
|
||||
return;
|
||||
}
|
||||
|
||||
return (async () => {
|
||||
const status = await checkPluginStatus(UserStore.getCurrentUser()?.id, id);
|
||||
if (status.blocked) {
|
||||
showToast("Split Messages is unavailable right now", getAssetIDByName("Small"));
|
||||
return orig([channelId, messageId, message]);
|
||||
}
|
||||
|
||||
const result = await orig([channelId, messageId, { ...message, content: chunks.shift() }]);
|
||||
await sendChunks(channelId, chunks, message);
|
||||
return result;
|
||||
})();
|
||||
});
|
||||
},
|
||||
onUnload() {
|
||||
unpatchMaxLength?.();
|
||||
unpatchSend?.();
|
||||
unpatchEdit?.();
|
||||
},
|
||||
settings: Settings,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue