/* * Vencord, a Discord client mod * Copyright (c) 2023 Vendicated and contributors * SPDX-License-Identifier: GPL-3.0-or-later */ import { readdir, readFile, unlink, writeFile } from "node:fs/promises"; import path from "node:path"; import { Queue } from "@utils/Queue"; import { dialog, IpcMainInvokeEvent, shell } from "electron"; import { DATA_DIR } from "../../../main/utils/constants"; import { getSettings, saveSettings } from "./settings"; import { ensureDirectoryExists, getAttachmentIdFromFilename } from "./utils"; export { getSettings }; // so we can filter the native helpers by this key export function messageLoggerEnhancedUniqueIdThingyIdkMan() { } // Map() const nativeSavedImages = new Map(); export const getNativeSavedImages = () => nativeSavedImages; let logsDir: string; let imageCacheDir: string; const getImageCacheDir = async () => imageCacheDir ?? await getDefaultNativeImageDir(); const getLogsDir = async () => logsDir ?? await getDefaultNativeDataDir(); export async function initDirs() { const { logsDir: ld, imageCacheDir: icd } = await getSettings(); logsDir = ld || await getDefaultNativeDataDir(); imageCacheDir = icd || await getDefaultNativeImageDir(); } initDirs(); export async function init(_event: IpcMainInvokeEvent) { const imageDir = await getImageCacheDir(); await ensureDirectoryExists(imageDir); const files = await readdir(imageDir); for (const filename of files) { const attachmentId = getAttachmentIdFromFilename(filename); nativeSavedImages.set(attachmentId, path.join(imageDir, filename)); } } export async function getImageNative(_event: IpcMainInvokeEvent, attachmentId: string): Promise { const imagePath = nativeSavedImages.get(attachmentId); if (!imagePath) return null; return await readFile(imagePath); } export async function writeImageNative(_event: IpcMainInvokeEvent, filename: string, content: Uint8Array) { if (!filename || !content) return; const imageDir = await getImageCacheDir(); // returns the file name // ../../someMalicousPath.png -> someMalicousPath const attachmentId = getAttachmentIdFromFilename(filename); const existingImage = nativeSavedImages.get(attachmentId); if (existingImage) return; const imagePath = path.join(imageDir, filename); await ensureDirectoryExists(imageDir); await writeFile(imagePath, content); nativeSavedImages.set(attachmentId, imagePath); } export async function deleteFileNative(_event: IpcMainInvokeEvent, attachmentId: string) { const imagePath = nativeSavedImages.get(attachmentId); if (!imagePath) return; await unlink(imagePath); } const LOGS_DATA_FILENAME = "message-logger-logs.json"; const dataWriteQueue = new Queue(); export async function getLogsFromFs(_event: IpcMainInvokeEvent) { const logsDir = await getLogsDir(); await ensureDirectoryExists(logsDir); try { return JSON.parse(await readFile(path.join(logsDir, LOGS_DATA_FILENAME), "utf-8")); } catch { } return null; } export async function writeLogs(_event: IpcMainInvokeEvent, contents: string) { const logsDir = await getLogsDir(); dataWriteQueue.push(() => writeFile(path.join(logsDir, LOGS_DATA_FILENAME), contents)); } export async function getDefaultNativeImageDir(): Promise { return path.join(await getDefaultNativeDataDir(), "savedImages"); } export async function getDefaultNativeDataDir(): Promise { return path.join(DATA_DIR, "MessageLoggerData"); } export async function chooseDir(event: IpcMainInvokeEvent, logKey: "logsDir" | "imageCacheDir") { const settings = await getSettings(); const defaultPath = settings[logKey] || await getDefaultNativeDataDir(); const res = await dialog.showOpenDialog({ properties: ["openDirectory"], defaultPath: defaultPath }); const dir = res.filePaths[0]; if (!dir) throw Error("Invalid Directory"); settings[logKey] = dir; await saveSettings(settings); switch (logKey) { case "logsDir": logsDir = dir; break; case "imageCacheDir": imageCacheDir = dir; break; } if (logKey === "imageCacheDir") await init(event); return dir; } export async function showItemInFolder(_event: IpcMainInvokeEvent, filePath: string) { shell.showItemInFolder(filePath); }