Recently Written · git

bd-plugin-profiler

BetterDiscord plugin that measures the main-thread time of each plugin

git clone https://github.com/equwal/bd-plugin-profiler

Log | Files | Refs


test/helpers/installed.js (2413 bytes)

1 "use strict";
2 // Loads code from the installed BetterDiscord and BDFDB, so the tests check the versions that Discord runs.
3 const fs = require("node:fs");
4 const path = require("node:path");
5 
6 const BD_FOLDER = path.join(process.env.APPDATA || "", "BetterDiscord");
7 const BD_ASAR = path.join(BD_FOLDER, "data", "betterdiscord.asar");
8 const BDFDB_FILE = path.join(BD_FOLDER, "plugins", "0BDFDB.plugin.js");
9 
10 /** Reads one top-level file from an asar archive. */
11 function readAsarFile(archive, name) {
12     const buffer = fs.readFileSync(archive);
13     const headerPickleSize = buffer.readUInt32LE(4);
14     const jsonLength = buffer.readUInt32LE(12);
15     const header = JSON.parse(buffer.toString("utf8", 16, 16 + jsonLength));
16     const entry = header.files[name];
17     const start = 8 + headerPickleSize + Number(entry.offset);
18     return buffer.toString("utf8", start, start + entry.size);
19 }
20 
21 /** Returns the index of the brace that closes the brace at openIndex. */
22 function closingBrace(text, openIndex) {
23     let depth = 0;
24     for (let i = openIndex; i < text.length; i++) {
25         if (text[i] === "{") depth++;
26         else if (text[i] === "}" && --depth === 0) return i;
27     }
28     throw new Error("no closing brace");
29 }
30 
31 /** Returns the internal Patcher class of the installed BetterDiscord. */
32 function loadBdPatcher(logger) {
33     const source = readAsarFile(BD_ASAR, "betterdiscord.js");
34     const marker = source.indexOf("static getPatchesByCaller(");
35     if (marker < 0) throw new Error("BetterDiscord Patcher not found");
36     const classStart = source.lastIndexOf("=class{", marker) + 1;
37     const body = source.slice(classStart, closingBrace(source, classStart + "class".length) + 1);
38     // The minified class uses g (logger), w (module cache), and ae (module search) from its bundle.
39     return new Function("g", "w", "ae", `return ${body};`)(logger, {}, () => null);
40 }
41 
42 /** Returns BDFDB.TimeUtils.suppress from the installed BDFDB library. */
43 function loadBdfdbSuppress(logUtils) {
44     const source = fs.readFileSync(BDFDB_FILE, "utf8");
45     const match = /BDFDB\.TimeUtils\.suppress = (function \(callback, strings, config\) \{[\s\S]*?\n\t*\}\};)/.exec(source);
46     if (!match) throw new Error("BDFDB TimeUtils.suppress not found");
47     return new Function("BDFDB", `return ${match[1].slice(0, -1)}`)({LogUtils: logUtils});
48 }
49 
50 module.exports = {BD_ASAR, BDFDB_FILE, loadBdPatcher, loadBdfdbSuppress};