Equicord/src/equicordplugins/messageLoggerEnhanced/LoggedMessageManager.ts

276 lines
9.3 KiB
TypeScript
Raw Normal View History

2024-04-17 14:29:47 -04:00
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { createStore } from "@api/DataStore";
import { DataStore } from "@api/index";
import { Settings } from "@api/Settings";
import { Flogger, Native, settings } from ".";
import { LoggedMessage, LoggedMessageIds, LoggedMessageJSON, LoggedMessages, MessageRecord } from "./types";
import { cleanupMessage, getNative, sortMessagesByDate } from "./utils";
import { cacheMessageImages, deleteMessageImages } from "./utils/saveImage";
export const defaultLoggedMessages = { deletedMessages: {}, editedMessages: {}, };
export const LOGGED_MESSAGES_KEY = "logged-messages-hi";
export const MessageLoggerStore = createStore("MessageLoggerData", "MessageLoggerStore");
// this gets used by the logs modal. logs modal should only use saved messages not messages that are being processed
// also hasMessageInLogs should only check saved messages not the ones that are being processed
export let savedLoggedMessages: LoggedMessages = { ...defaultLoggedMessages };
export let loggedMessages: LoggedMessages = { ...defaultLoggedMessages };
(async () => {
try {
const Native = getNative();
const res = await Native.getLogsFromFs();
if (res != null) {
Flogger.log("Got logged messages from native wont be checking DataStore");
const cleaned = await cleanMessages(res, Native);
loggedMessages = cleaned;
savedLoggedMessages = cleaned;
return;
}
if (IS_WEB) {
Flogger.log("hii. no point in checking DataStore if. we already did up there ^^");
return;
}
const data = await DataStore.get(LOGGED_MESSAGES_KEY, MessageLoggerStore);
if (data == null) {
Flogger.log("No logged messages in DataStore");
return;
}
Flogger.log("Loading logged messages from DataStore and writing to native");
Native.writeLogs(JSON.stringify(data));
loggedMessages = data;
savedLoggedMessages = res;
} catch (error) {
console.error("Error loading logged messages from the store:", error);
}
})();
// api
export const saveLoggedMessages = async () => {
if (settings.store.saveMessages) {
await Native.writeLogs(JSON.stringify(loggedMessages));
}
savedLoggedMessages = loggedMessages;
};
export const addMessage = async (message: LoggedMessage | LoggedMessageJSON, key: keyof LoggedMessageIds, isBulk = false) => {
if (settings.store.saveImages && key === "deletedMessages")
2024-04-17 14:29:47 -04:00
await cacheMessageImages(message);
const finalMessage = cleanupMessage(message);
loggedMessages[message.id] = { message: finalMessage };
2024-04-17 14:29:47 -04:00
if (!loggedMessages[key][message.channel_id])
loggedMessages[key][message.channel_id] = [];
2024-04-17 14:29:47 -04:00
if (!loggedMessages[key][message.channel_id].includes(message.id))
loggedMessages[key][message.channel_id].push(message.id);
2024-04-17 14:29:47 -04:00
// if limit is negative or 0 there is no limit
if (settings.store.messageLimit > 0 && (Object.keys(loggedMessages).length - 2) > settings.store.messageLimit)
await deleteOldestMessageWithoutSaving(loggedMessages);
2024-04-17 14:29:47 -04:00
if (!isBulk)
await saveLoggedMessages();
};
export const removeFromKey = (
message_id: string,
channel_id: string,
loggedMessages: LoggedMessages,
key: keyof LoggedMessageIds,
) => {
if (loggedMessages[key][channel_id]) {
loggedMessages[key][channel_id] = loggedMessages[key][channel_id].filter(msgid => msgid !== message_id);
if (loggedMessages[key][channel_id].length === 0) {
delete loggedMessages[key][channel_id];
}
}
};
function removeLogWithoutSaving(messageId: string, loggedMessages: LoggedMessages) {
const record = loggedMessages[messageId];
if (record) {
const channel_id = record.message?.channel_id;
if (channel_id != null) {
removeFromKey(messageId, channel_id, loggedMessages, "editedMessages");
removeFromKey(messageId, channel_id, loggedMessages, "deletedMessages");
2024-04-17 14:29:47 -04:00
}
delete loggedMessages[messageId];
}
return loggedMessages;
}
export async function removeLogs(ids: string[]) {
for (const msgId of ids) {
removeLogWithoutSaving(msgId, loggedMessages);
2024-04-17 14:29:47 -04:00
}
await saveLoggedMessages();
}
export async function removeLog(id: string) {
const record = loggedMessages[id];
if (record?.message)
deleteMessageImages(record.message);
removeLogWithoutSaving(id, loggedMessages);
await saveLoggedMessages();
}
export async function clearLogs() {
await Native.writeLogs(JSON.stringify(defaultLoggedMessages));
loggedMessages = defaultLoggedMessages;
savedLoggedMessages = defaultLoggedMessages;
}
// utils
export const hasMessageInLogs = (messageId: string) => {
const bruh = Object.values(savedLoggedMessages)
.filter(m => !Array.isArray(m)) as MessageRecord[];
return bruh.find(m => m.message?.id === messageId);
2024-04-17 14:29:47 -04:00
};
export const hasLogs = async () => {
const hasDeletedMessages = Object.keys(loggedMessages.deletedMessages).length > 0;
const hasEditedMessages = Object.keys(loggedMessages.editedMessages).length > 0;
const hasMessages = Object.keys(loggedMessages).filter(m => m !== "editedMessages" && m !== "deletedMessages").length > 0;
if (hasDeletedMessages && hasEditedMessages && hasMessages) return true;
return false;
};
export function findLoggedChannelByMessageIdSync(messageId: string, loggedMessages: LoggedMessages, key: keyof LoggedMessageIds) {
for (const channelId in loggedMessages[key]) {
if (loggedMessages[key][channelId].includes(messageId)) return channelId;
}
return null;
}
export async function findLoggedChannelByMessage(messageId: string, key?: keyof LoggedMessageIds): Promise<[string | null, keyof LoggedMessageIds]> {
if (!key) {
const id1 = findLoggedChannelByMessageIdSync(messageId, loggedMessages, "deletedMessages");
if (id1) return [id1, "deletedMessages"];
const id2 = findLoggedChannelByMessageIdSync(messageId, loggedMessages, "editedMessages");
return [id2, "editedMessages"];
}
return [findLoggedChannelByMessageIdSync(messageId, loggedMessages, key), key];
}
export function getOldestMessage(loggedMessageIds: LoggedMessages) {
const messags = Object.values(loggedMessageIds)
.filter(m => !Array.isArray(m) && m.message != null) as MessageRecord[];
const sortedMessages = messags.sort((a, b) => sortMessagesByDate(a.message.timestamp, b.message.timestamp));
const oldestMessage = sortedMessages[sortedMessages.length - 1];
return oldestMessage ?? null;
}
export function getMessage(channelId: string, messageId: string) {
const messags = Object.values(savedLoggedMessages)
.filter(m => !Array.isArray(m) && m.message != null) as MessageRecord[];
return messags.find(m => m.message.channel_id === channelId && m.message.id === messageId);
}
export async function deleteOldestMessageWithoutSaving(loggedMessages: LoggedMessages) {
const oldestMessage = getOldestMessage(loggedMessages);
if (!oldestMessage || !oldestMessage.message) {
console.warn("couldnt find oldest message. oldestMessage == null || oldestMessage.message == null");
return loggedMessages;
}
const { message } = oldestMessage;
const [channelId, key] = await findLoggedChannelByMessage(message.id);
if (!channelId || !key) {
console.warn("couldnt find oldest message. channelId =", channelId, " key =", key);
return loggedMessages;
}
removeLogWithoutSaving(message.id, loggedMessages);
// console.log("removing", message);
return loggedMessages;
}
async function cleanMessages(loggedMessages: LoggedMessages, _Native: any = Native) {
try {
const cleaned = { ...loggedMessages };
if (IS_WEB) return cleaned;
const messageRecords = Object.values(cleaned)
.filter(m => !Array.isArray(m)) as MessageRecord[];
let hasChanged = false;
for (const messageRecord of messageRecords) {
const { message } = messageRecord;
if (message?.attachments) {
for (const attachment of message.attachments) {
if (attachment.blobUrl) {
hasChanged = true;
delete attachment.blobUrl;
}
}
}
}
if (hasChanged)
await _Native.writeLogs(Settings.plugins.MessageLoggerEnhanced.logsDir, JSON.stringify(cleaned));
return cleaned;
} catch (err) {
Flogger.error("Error cleaning messages:", err);
return loggedMessages;
}
}