This repository was archived by the owner on Nov 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.mjs
220 lines (190 loc) · 6.51 KB
/
index.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import 'dotenv/config';
import Discord from 'discord.js-selfbot-v13';
import Fastify from 'fastify';
import cors from '@fastify/cors'
// Initialize Discord
const client = new Discord.Client();
let discord_ready = false;
let clyde_user_id = process.env.CLYDE_USER_ID || '1081004946872352958';
client.once('ready', async () => {
console.log(`Logged in as ${client.user.tag}!`);
discord_ready = true;
// Prune channels on startup
pruneChannels(process.env.SERVER_ID);
});
async function sendMessageToChannel(id, message) {
const channel = await client.channels.fetch(id);
channel.send(message);
}
async function createChannelinServer(serverId, channelName) {
const server = await client.guilds.fetch(serverId);
const channel = await server.channels.create(channelName, {
type: 'text',
permissionOverwrites: [
{
id: server.roles.everyone,
deny: ['VIEW_CHANNEL'],
},
],
});
return channel;
}
async function getChannelByName(serverId, channelName) {
const server = await client.guilds.fetch(serverId);
const channels = await server.channels.fetch();
const channel = channels.find(channel => channel.name === channelName);
return channel;
}
// Delete all channels in a server
async function deleteAllChannels(serverId) {
const server = await client.guilds.fetch(serverId);
const channels = await server.channels.fetch();
channels.forEach(async channel => {
console.log(`Deleting channel ${channel.name}`);
await channel.delete();
});
}
// Function to get the amount of channels in a server
async function getChannelCount(serverId) {
const server = await client.guilds.fetch(serverId);
const channels = await server.channels.fetch();
return channels.size;
}
// Function that deletes all channels if the channel count is greater than the max (default 450)
async function pruneChannels(serverId, max = 450) {
const channelCount = await getChannelCount(serverId);
if (channelCount > max) {
console.log(`Channel count is ${channelCount}, deleting all channels...`)
await deleteAllChannels(serverId);
} else {
console.log(`Channel count is ${channelCount}, not deleting channels.`)
}
}
// Prune channels every 15 minutes
setInterval(() => {
pruneChannels(process.env.SERVER_ID);
}, 15 * 60 * 1000);
// Initialize Fastify
const fastify = Fastify({ logger: true });
// Register CORS
await fastify.register(cors, {
origin: process.env.CORS_ORIGIN || false,
})
// Register rate limiter
if (process.env.RATELIMIT_MAX_RPS) {
const ratelimit_max = parseInt(process.env.RATELIMIT_MAX_RPS) || 4;
console.log(`Rate limiting to ${ratelimit_max} requests per second`);
await fastify.register(import('@fastify/rate-limit'), {
max: ratelimit_max,
timeWindow: '1 second'
});
} else {
console.log(`Rate limiting disabled`);
}
// Health check route
fastify.get('/healthcheck', async (request, reply) => {
reply.send({
status: discord_ready ? 'ok' : 'not ready',
});
});
// Route to send a message
fastify.get('/', async (request, reply) => {
// Ensure Discord is ready
if (!discord_ready) {
reply.send({
error: 'Discord is not ready yet',
});
return;
}
const message = request.query.message;
const conversationID = request.query.conversationID.toLowerCase();
// Make sure message and conversationID are provided
if (!message || !conversationID) {
reply.send({
error: 'Please provide a message and conversationID',
});
return;
}
// Ensure message is under 1850 characters
if (message.length > 1850) {
reply.send({
error: 'Message is too long. Must be under 1850 characters',
});
return;
}
// Validate that the conversationID is a string with only letters and numbers, no spaces and no more than 32 characters
// If not, return an error
if (!/^[a-zA-Z0-9]{1,32}$/.test(conversationID)) {
reply.send({
error: 'Invalid conversationID. Must be a string with only letters and numbers, no spaces and no more than 32 characters',
});
return;
}
// Check if conversation exists
let channel = await getChannelByName(process.env.SERVER_ID, conversationID);
if (!channel) {
// Create channel
channel = await createChannelinServer(process.env.SERVER_ID, conversationID);
}
// Send message to channel
await sendMessageToChannel(channel.id, `<@${clyde_user_id}> ${message}`);
// Wait for response from Clyde
const response = await new Promise((resolve, reject) => {
// TODO: We might want to end the promise after a certain amount of time
// as well as to stop listening for messages after we get a response
client.on('messageCreate', msg => {
if (msg.channel.id === channel.id && msg.author.id === clyde_user_id) {
resolve(msg.content);
}
});
});
// Return response to the client
reply.send({
response: response,
});
});
// Route to delete a conversation
fastify.delete('/', async (request, reply) => {
// Ensure Discord is ready
if (!discord_ready) {
reply.send({
error: 'Discord is not ready yet',
});
return;
}
const conversationID = request.query.conversationID.toLowerCase();
// Make sure conversationID is provided
if (!conversationID) {
reply.send({
error: 'Please provide a conversationID',
});
return;
}
// Validate that the conversationID is a string with only letters and numbers, no spaces and no more than 32 characters
// If not, return an error
if (!/^[a-zA-Z0-9]{1,32}$/.test(conversationID)) {
reply.send({
error: 'Invalid conversationID. Must be a string with only letters and numbers, no spaces and no more than 32 characters',
});
return;
}
// Check if conversation exists
let channel = await getChannelByName(process.env.SERVER_ID, conversationID);
if (!channel) {
reply.send({
error: 'Conversation does not exist',
});
return;
}
// Delete channel
await channel.delete();
// Return response to the client
reply.send({
response: 'Conversation deleted',
success: true,
});
});
// Login to Discord
client.login(process.env.TOKEN);
// Start Fastify
fastify.listen({ port: process.env.PORT || 53195 });