|
1 |
| -import { spawn } from "node:child_process"; |
2 |
| -import { EventEmitter } from "node:events"; |
3 |
| -import chalk from "chalk"; |
4 |
| -import { EmbedBuilder, Client, GatewayIntentBits, Events, ActivityType } from "discord.js"; |
5 |
| -import stripAnsi from "strip-ansi"; |
6 |
| -import { cpuTemperature, currentLoad, mem } from "systeminformation"; |
7 | 1 | import "dotenv/config";
|
8 |
| -console.log(chalk.cyan(chalk.bold("[DISCORD] > Starting SSH..."))); |
9 |
| - |
10 |
| -const client = new Client({ |
11 |
| - allowedMentions: { |
12 |
| - parse: ["users", "roles"], |
13 |
| - repliedUser: false, |
14 |
| - }, |
15 |
| - presence: { |
16 |
| - status: "online", |
17 |
| - afk: false, |
18 |
| - }, |
19 |
| - intents: GatewayIntentBits.Guilds | GatewayIntentBits.GuildMembers | GatewayIntentBits.GuildPresences | GatewayIntentBits.GuildMessages | GatewayIntentBits.MessageContent, |
20 |
| -}); |
21 |
| - |
22 |
| -client.config = { |
23 |
| - channel: process.env.CHANNEL_ID, |
24 |
| - owner: process.env.OWNER_ID, |
25 |
| - token: process.env.TOKEN, |
26 |
| - cwd: process.env.CUSTOM_CWD, |
27 |
| -}; |
28 |
| - |
29 |
| -EventEmitter.prototype._maxListeners = 100; |
30 |
| - |
31 |
| -// Cache stats to eliminate "lag" on command |
32 |
| -setInterval(() => { |
33 |
| - cpuTemperature().then((data) => { |
34 |
| - client.cpuTemperature = data.main; |
35 |
| - }); |
36 |
| - |
37 |
| - currentLoad().then((data) => { |
38 |
| - client.cpuUsage = data.currentLoad.toFixed(2); |
39 |
| - }); |
40 |
| - |
41 |
| - mem().then((data) => { |
42 |
| - const total = (data.total / 1048576).toFixed(2); |
43 |
| - const used = (data.used / 1048576).toFixed(2); |
44 |
| - client.memoryPercentage = ((used * 100) / total).toFixed(2); |
| 2 | +import { Client, GatewayIntentBits } from "discord.js"; |
| 3 | +import loadEvents from "./utils/loadEvents.js"; |
| 4 | +import { logger } from "./utils/logger.js"; |
| 5 | + |
| 6 | +logger("event", "Starting SSH Bot session..."); |
| 7 | +logger("info", `Running version v${process.env.npm_package_version} on Node.js ${process.version} on ${process.platform} ${process.arch}`); |
| 8 | +logger("info", "Check out the source code at https://github.com/igorkowalczyk/discord-ssh!"); |
| 9 | +logger("info", "Don't forget to star the repository, it helps a lot!"); |
| 10 | + |
| 11 | +try { |
| 12 | + const client = new Client({ |
| 13 | + allowedMentions: { |
| 14 | + parse: ["users", "roles"], |
| 15 | + repliedUser: false, |
| 16 | + }, |
| 17 | + intents: GatewayIntentBits.Guilds | GatewayIntentBits.GuildMembers | GatewayIntentBits.GuildPresences | GatewayIntentBits.GuildMessages | GatewayIntentBits.MessageContent, |
45 | 18 | });
|
46 |
| -}, 5000); |
47 | 19 |
|
48 |
| -async function exec(input, options, customCWD) { |
49 |
| - if (options?.terminal) |
50 |
| - await (await client.config.channel.fetchWebhooks()).first().send(input, { |
51 |
| - username: client.config.channel.guild.members.cache.get(client.config.owner.id)?.nickname || client.config.owner.username, |
52 |
| - avatarURL: client.config.owner.displayAvatarURL({ format: "png" }), |
53 |
| - }); |
54 |
| - let output = ""; |
55 |
| - const args = input.split(" "); |
56 |
| - const command = args.shift(); |
57 |
| - const cmd = spawn(`${command}`, args, { |
58 |
| - shell: true, |
59 |
| - env: { COLUMNS: 128 }, |
60 |
| - cwd: customCWD || client.config.cwd || process.cwd(), |
61 |
| - }); |
| 20 | + client.customCWD = process.env.CUSTOM_CWD || process.cwd(); |
62 | 21 |
|
63 |
| - cmd.stdout.on("data", (data) => { |
64 |
| - output += data; |
65 |
| - }); |
66 |
| - cmd.stderr.on("data", (data) => { |
67 |
| - output += data; |
68 |
| - }); |
69 |
| - cmd.on("exit", async () => { |
70 |
| - if (output) { |
71 |
| - //await client.config.channel.bulkDelete(1); |
72 |
| - const chunkStr = (str, n, acc) => { |
73 |
| - if (str.length === 0) { |
74 |
| - return acc; |
75 |
| - } else { |
76 |
| - acc.push(str.substring(0, n)); |
77 |
| - return chunkStr(str.substring(n), n, acc); |
78 |
| - } |
79 |
| - }; |
80 |
| - const outputDiscord = chunkStr(output, 4000, []); |
| 22 | + logger("info", "Loading events..."); |
| 23 | + await loadEvents(client); |
81 | 24 |
|
82 |
| - const embed = new EmbedBuilder().setColor("#4f545c").setTitle("📤 Output").setTimestamp(); |
83 |
| - let i = 0; |
84 |
| - outputDiscord.forEach((item) => { |
85 |
| - i++; |
86 |
| - embed.setFooter({ text: `Page ${i}/${outputDiscord.length}`, icon: client.user.displayAvatarURL() }); |
87 |
| - embed.setDescription(`\`\`\`${stripAnsi(item, true) || "No output!"}\`\`\``); |
88 |
| - if (i == outputDiscord.length) embed.addFields([{ name: "\u200B", value: `\`\`\`CWD: ${customCWD}\nCPU: ${client.cpuUsage}% | RAM: ${client.memoryPercentage}% | Temp: ${client.cpuTemperature}°C\`\`\`` }]); |
89 |
| - const finalMessage = client.config.channel.messages.cache.first(); |
90 |
| - if (i !== 1) { |
91 |
| - client.config.channel.send({ embeds: [embed] }); |
92 |
| - } else { |
93 |
| - finalMessage.reply({ embeds: [embed] }); |
94 |
| - } |
95 |
| - }); |
96 |
| - } |
97 |
| - }); |
| 25 | + logger("info", "Logging in..."); |
| 26 | + await client.login(process.env.TOKEN); |
| 27 | +} catch (error) { |
| 28 | + logger("error", error); |
| 29 | + process.exit(1); |
98 | 30 | }
|
99 | 31 |
|
100 |
| -client.on(Events.MessageCreate, (msg) => { |
101 |
| - if (msg.author.bot) return; |
102 |
| - if (msg.channel === client.config.channel && msg.author === client.config.owner) { |
103 |
| - if (msg.content.startsWith("cd")) { |
104 |
| - const cd = new EmbedBuilder().setDescription("↪️ **Changed directory from `" + client.config.cwd + "` to `" + msg.content.split(" ")[1] + "`**\n\n<a:loading:895227261752582154> **Waiting for server response...**").setColor("#5865f2"); |
105 |
| - msg.reply({ embeds: [cd] }); |
106 |
| - exec(msg.content.split(" ").slice(2).join(" "), null, msg.content.split(" ")[1].toString()); |
107 |
| - } else { |
108 |
| - const wait = new EmbedBuilder().setDescription("<a:loading:895227261752582154> **Waiting for server response...**").setColor("#5865f2"); |
109 |
| - msg.reply({ embeds: [wait] }); |
110 |
| - exec(msg.content, null, client.config.cwd); |
111 |
| - } |
112 |
| - } |
113 |
| -}); |
114 |
| - |
115 |
| -client.once(Events.ClientReady, async () => { |
116 |
| - client.config.channel = client.channels.cache.get(client.config.channel); |
117 |
| - if (!client.config.channel) { |
118 |
| - throw new Error("Invalid CHANNEL_ID in .env!"); |
119 |
| - } |
120 |
| - client.config.owner = await client.users.fetch(client.config.owner); |
121 |
| - if (!client.config.owner) { |
122 |
| - throw new Error("Invalid OWNER_ID in .env!"); |
123 |
| - } |
124 |
| - |
125 |
| - if (!(await client.config.channel.fetchWebhooks()).size) await client.config.channel.createWebhook(client.config.owner.tag, { avatar: client.config.owner.displayAvatarURL({ format: "png" }) }); |
126 |
| - console.log(chalk.cyan(chalk.bold(`[DISCORD] > Logged in as ${client.user.tag}`))); |
127 |
| - client.user.setActivity("all ports!", { type: ActivityType.Watching }); |
128 |
| -}); |
129 |
| - |
130 |
| -process.stdin.on("data", (data) => exec(data.toString(), { terminal: true })); |
131 |
| - |
132 |
| -client.login(client.config.token).catch(() => { |
133 |
| - throw new Error("Invalid TOKEN in .env"); |
134 |
| -}); |
135 |
| - |
136 | 32 | process.on("unhandledRejection", async (reason) => {
|
137 |
| - return console.log(chalk.red(chalk.bold(`[ERROR] > Unhandled Rejection: ${reason}`))); |
| 33 | + return logger("error", reason); |
138 | 34 | });
|
| 35 | + |
139 | 36 | process.on("uncaughtException", async (err) => {
|
140 |
| - return console.log(chalk.red(chalk.bold(`[ERROR] > Uncaught Exception: ${err}`))); |
141 |
| -}); |
142 |
| -process.on("uncaughtExceptionMonitor", async (err) => { |
143 |
| - return console.log(chalk.red(chalk.bold(`[ERROR] > Uncaught Exception Monitor: ${err}`))); |
| 37 | + return logger("error", err); |
144 | 38 | });
|
0 commit comments