forked from pcarrier/purgatorial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
127 lines (120 loc) · 3.38 KB
/
index.ts
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
import {load} from "https://deno.land/[email protected]/dotenv/mod.ts";
const env = await load(),
token = env["TOKEN"],
msgTimeout = Number(env["MSG_TIMEOUT"] || "10800000"),
channelIDs = (env["CHANNEL_IDS"] || "").split(",").map((id) => id.trim());
function error(err: Event | ErrorEvent): never {
console.log("error", err);
Deno.exit(1);
}
function fetchWith429Retry(url: string, init?: RequestInit): Promise<Response> {
return new Promise((resolve, reject) => {
fetch(url, init).then((res) => {
if (res.status === 429) {
setTimeout(() => {
fetchWith429Retry(url, init).then(resolve, reject);
}, Number(res.headers.get("retry-after")) * 1000);
} else {
resolve(res);
}
}).catch(reject);
});
}
async function deleteMessage(channelID: string, messageID: string) {
const res = await fetchWith429Retry(
`https://discord.com/api/v10/channels/${channelID}/messages/${messageID}`,
{
method: "DELETE",
headers: {
"Authorization": `Bot ${token}`,
},
});
if (!res.ok && res.status !== 404) {
console.log("failed to delete message", res.status);
Deno.exit(1);
}
}
async function backfillChannel(channelID: string) {
let after: string | undefined = undefined;
while (true) {
const res = await fetchWith429Retry(
`https://discord.com/api/v10/channels/${channelID}/messages${
after ? `?after=${after}` : ""
}`,
{
headers: {
"Authorization": `Bot ${token}`,
},
},
);
if (!res.ok) {
console.log("failed to fetch messages", res.status);
Deno.exit(1);
}
const messages = await res.json();
if (messages.length === 0) {
return;
}
for (const message of messages) {
const date = new Date(message.timestamp);
if (Date.now() - date.getTime() > msgTimeout) {
await deleteMessage(channelID, message.id);
} else {
setTimeout(() => {
deleteMessage(channelID, message.id);
}, date.getTime() + msgTimeout - Date.now());
}
}
after = messages[0].id;
}
}
function connect(): WebSocket {
let d: number | null = null;
const ws = new WebSocket("wss://gateway.discord.gg/");
ws.onmessage = async (msg) => {
const payload = JSON.parse(msg.data);
d = payload.s || d;
switch (payload.op) {
case 10:
setInterval(() => {
ws.send(JSON.stringify({ op: 1, d }));
}, payload.d.heartbeat_interval);
ws.send(JSON.stringify({
op: 2,
d: {
token,
intents: 1 << 9,
properties: {
os: "deno",
browser: "deno",
device: "deno",
},
},
}));
break;
case 0:
switch (payload.t) {
case "READY":
for (const channelID of channelIDs) {
await backfillChannel(channelID);
}
break;
case "MESSAGE_CREATE": {
const channelID = payload.d.channel_id;
if (channelIDs.includes(channelID)) {
const msgID = payload.d.id;
setTimeout(() => deleteMessage(channelID, msgID), msgTimeout);
}
break;
}
}
}
};
ws.onclose = (e) => {
console.log("oops!", e.reason);
Deno.exit(1);
};
ws.onerror = (err) => error(err);
return ws;
}
connect();