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 { findByProps, findByStoreName } from "@vendetta/metro";
|
||||||
import { before, instead } from "@vendetta/patcher";
|
import { instead } from "@vendetta/patcher";
|
||||||
import { storage } from "@vendetta/plugin";
|
import { id, storage } from "@vendetta/plugin";
|
||||||
import { getAssetIDByName } from "@vendetta/ui/assets";
|
import { getAssetIDByName } from "@vendetta/ui/assets";
|
||||||
import { showToast } from "@vendetta/ui/toasts";
|
import { showToast } from "@vendetta/ui/toasts";
|
||||||
|
import { checkPluginStatus } from "@shared/lib/backend";
|
||||||
|
import { checkForUpdate } from "@shared/lib/reload";
|
||||||
import { intoChunks } from "./lib/split";
|
import { intoChunks } from "./lib/split";
|
||||||
import Settings from "./ui/Settings";
|
import Settings from "./ui/Settings";
|
||||||
|
|
||||||
|
const MAX_CHUNKS = 20;
|
||||||
|
|
||||||
function sleep(ms: number): Promise<void> {
|
function sleep(ms: number): Promise<void> {
|
||||||
return new Promise((r) => setTimeout(r, ms));
|
return new Promise((r) => setTimeout(r, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
let unpatchMaxLength: (() => boolean) | undefined;
|
let unpatchMaxLength: (() => boolean) | undefined;
|
||||||
let unpatchSend: (() => boolean) | undefined;
|
let unpatchSend: (() => boolean) | undefined;
|
||||||
|
let unpatchEdit: (() => boolean) | undefined;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
onLoad() {
|
onLoad() {
|
||||||
storage.splitOnWords ??= false;
|
storage.splitOnWords ??= false;
|
||||||
|
|
||||||
|
checkForUpdate(id).catch(() => {});
|
||||||
|
|
||||||
const MaxLengthModule = findByProps("getMaxMessageLength");
|
const MaxLengthModule = findByProps("getMaxMessageLength");
|
||||||
const MessageActions = findByProps("sendMessage", "editMessage");
|
const MessageActions = findByProps("sendMessage", "editMessage");
|
||||||
const UserStore = findByStoreName("UserStore");
|
const UserStore = findByStoreName("UserStore");
|
||||||
|
|
@ -24,44 +31,91 @@ export default {
|
||||||
|
|
||||||
unpatchMaxLength = instead("getMaxMessageLength", MaxLengthModule, () => 2 ** 30);
|
unpatchMaxLength = instead("getMaxMessageLength", MaxLengthModule, () => 2 ** 30);
|
||||||
|
|
||||||
unpatchSend = before("sendMessage", MessageActions, (args: any[]) => {
|
const maxLength = () => (UserStore.getCurrentUser()?.premiumType === 2 ? 4000 : 2000);
|
||||||
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 delayFor = (channelId: string) => {
|
||||||
const channel = ChannelStore.getChannel(channelId);
|
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) {
|
for (const chunk of chunks) {
|
||||||
await sleep(delay);
|
await sleep(delayFor(channelId));
|
||||||
await MessageActions._sendMessage(
|
await MessageActions._sendMessage(
|
||||||
channelId,
|
channelId,
|
||||||
{
|
{
|
||||||
invalidEmojis: message.invalidEmojis,
|
invalidEmojis: template.invalidEmojis,
|
||||||
validNonShortcutEmojis: message.validNonShortcutEmojis,
|
validNonShortcutEmojis: template.validNonShortcutEmojis,
|
||||||
tts: false,
|
tts: false,
|
||||||
content: chunk,
|
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() {
|
onUnload() {
|
||||||
unpatchMaxLength?.();
|
unpatchMaxLength?.();
|
||||||
unpatchSend?.();
|
unpatchSend?.();
|
||||||
|
unpatchEdit?.();
|
||||||
},
|
},
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue