initial stats collection

This commit is contained in:
Ryan Cao 2022-11-12 21:28:21 +08:00
parent 4e2afcc7f8
commit ff5cc9c4aa
No known key found for this signature in database
7 changed files with 186 additions and 19 deletions

2
.gitignore vendored
View file

@ -7,3 +7,5 @@ dist
.env.local
eslint_report.json
/_test.ts

View file

@ -10,10 +10,13 @@
},
"dependencies": {
"@discordjs/rest": "^1.3.0",
"date-fns": "^2.29.3",
"discord.js": "^14.6.0",
"gray-matter": "^4.0.3",
"just-random": "^3.1.1",
"kleur": "^4.1.5",
"node-fetch": "^3.2.10",
"redis": "^4.5.0",
"remove-markdown": "^0.5.0",
"tsx": "^3.10.3",
"url-regex": "^5.0.0"
@ -23,9 +26,7 @@
"@typescript-eslint/eslint-plugin": "^5.40.1",
"@typescript-eslint/parser": "^5.40.1",
"dotenv": "^16.0.3",
"esbuild": "^0.15.11",
"eslint": "^8.25.0",
"gray-matter": "^4.0.3",
"prettier": "^2.7.1",
"typescript": "^4.8.4"
}

View file

@ -20,6 +20,7 @@ import { jokeCommand } from './commands/joke';
import random from 'just-random';
import { green, bold, yellow } from 'kleur/colors';
import 'dotenv/config';
import { collectStats } from './stats';
const client = new Client({
intents: [
@ -69,25 +70,27 @@ client.once('ready', async () => {
activities: [{ name: `Minecraft ${mcVersion}` }],
status: 'online',
});
});
client.on('messageCreate', async (e) => {
if (!e.content) return;
if (!e.channel.isTextBased()) return;
client.on('messageCreate', async (e) => {
if (!e.content) return;
if (!e.channel.isTextBased()) return;
if (e.author === client.user) return;
if (e.author === client.user) return;
if (e.cleanContent.match(BuildConfig.ETA_REGEX)) {
await e.reply(
`${random(BuildConfig.ETA_MESSAGES)} <:pofat:1031701005559144458>`
);
}
if (e.cleanContent.match(BuildConfig.ETA_REGEX)) {
await e.reply(
`${random(BuildConfig.ETA_MESSAGES)} <:pofat:1031701005559144458>`
);
}
const log = await parseLog(e.content);
if (log != null) {
e.reply({ embeds: [log] });
return;
}
});
const log = await parseLog(e.content);
if (log != null) {
e.reply({ embeds: [log] });
return;
}
await collectStats(e);
});
client.on('interactionCreate', async (interaction) => {

7
src/stats/datetime.ts Normal file
View file

@ -0,0 +1,7 @@
import { addMinutes, format } from 'date-fns';
export const getTimeIntervalID = () => {
const today = new Date();
return format(addMinutes(today, today.getTimezoneOffset()), 'yyyy.MM.dd.HH');
};

61
src/stats/index.ts Normal file
View file

@ -0,0 +1,61 @@
import { ChannelType, Message, PermissionFlagsBits } from 'discord.js';
import { getTimeIntervalID } from './datetime';
import { incr } from './redis';
const processMember = async (msg: Message<boolean>) => {
const id = msg.author.id;
await incr(`member:${id}:${getTimeIntervalID()}`, true);
};
const processChannel = async (msg: Message<boolean>) => {
const guildChannel = await msg.guild!.channels.fetch(msg.channelId);
if (!guildChannel) return;
if (
guildChannel.type === ChannelType.GuildStageVoice ||
guildChannel.type === ChannelType.GuildVoice
)
return;
let channelId = guildChannel.id;
// this is a text thread or forum post
if (
guildChannel.parent &&
(guildChannel.parent.type === ChannelType.GuildText ||
guildChannel.parent.type === ChannelType.GuildForum)
) {
channelId = guildChannel.parent.id;
// if this is a thread in a text channel, track the thread as well
if (guildChannel.parent.type === ChannelType.GuildText) {
await incr(`thread:${guildChannel.id}:${getTimeIntervalID()}`, true);
}
}
await incr(`channel:${channelId}:${getTimeIntervalID()}`, true);
};
export const collectStats = async (msg: Message<boolean>) => {
// reject bots (and webhooks)
if (msg.author.bot) return;
// only collect stats on publicly accessible channels
if (!msg.guild) return;
const guildChannel = await msg.guild.channels.fetch(msg.channelId);
if (!guildChannel) return;
const everyonesPermsInChannel = guildChannel.permissionsFor(
msg.guild.roles.everyone,
false
);
if (!everyonesPermsInChannel.has(PermissionFlagsBits.ViewChannel, false))
return;
await incr(`total:forever`);
await incr(`total:${getTimeIntervalID()}`, true);
await processMember(msg);
await processChannel(msg);
};

32
src/stats/redis.ts Normal file
View file

@ -0,0 +1,32 @@
import { createClient } from 'redis';
const ONE_MONTH_IN_SECONDS = 2629746;
const client = createClient({ url: process.env.REDIS_URI });
export const get = async (key: string) => {
await client.connect();
const data = await client.get(key);
await client.disconnect();
return data;
};
export const set = async (key: string, value: string, autoExpire = false) => {
await client.connect();
await client.set(key, value);
if (autoExpire && (await client.ttl(key)) === -1) {
await client.expire(key, ONE_MONTH_IN_SECONDS);
}
await client.disconnect();
};
export const incr = async (key: string, autoExpire = false) => {
await client.connect();
await client.incr(key);
if (autoExpire && (await client.ttl(key)) === -1) {
await client.expire(key, ONE_MONTH_IN_SECONDS);
}
await client.disconnect();
};

View file

@ -127,6 +127,40 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@redis/bloom@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.1.0.tgz#64e310ddee72010676e14296076329e594a1f6c7"
integrity sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ==
"@redis/client@1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.4.0.tgz#d2c56ce26c3e2fe3412db5cfb1814169662167eb"
integrity sha512-1gEj1AkyXPlkcC/9/T5xpDcQF8ntERURjLBgEWMTdUZqe181zfI9BY3jc2OzjTLkvZh5GV7VT4ktoJG2fV2ufw==
dependencies:
cluster-key-slot "1.1.1"
generic-pool "3.9.0"
yallist "4.0.0"
"@redis/graph@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.0.tgz#cc2b82e5141a29ada2cce7d267a6b74baa6dd519"
integrity sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==
"@redis/json@1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.4.tgz#f372b5f93324e6ffb7f16aadcbcb4e5c3d39bda1"
integrity sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==
"@redis/search@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.1.0.tgz#7abb18d431f27ceafe6bcb4dd83a3fa67e9ab4df"
integrity sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==
"@redis/time-series@1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.4.tgz#af85eb080f6934580e4d3b58046026b6c2b18717"
integrity sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==
"@sapphire/async-queue@^1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@sapphire/async-queue/-/async-queue-1.5.0.tgz#2f255a3f186635c4fb5a2381e375d3dfbc5312d8"
@ -353,6 +387,11 @@ chalk@^4.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
cluster-key-slot@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz#10ccb9ded0729464b6d2e7d714b100a2d1259d43"
integrity sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
@ -384,6 +423,11 @@ data-uri-to-buffer@^4.0.0:
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
date-fns@^2.29.3:
version "2.29.3"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8"
integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==
debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
@ -538,7 +582,7 @@ esbuild-windows-arm64@0.15.11:
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.11.tgz#018624023b5c3f0cca334cc99f5ef7134d396333"
integrity sha512-VwUHFACuBahrvntdcMKZteUZ9HaYrBRODoKe4tIWxguQRvvYoYb7iu5LrcRS/FQx8KPZNaa72zuqwVtHeXsITw==
esbuild@^0.15.11, esbuild@~0.15.10:
esbuild@~0.15.10:
version "0.15.11"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.11.tgz#524d48612a9aa7edc1753c83459cb6fcae0cb66e"
integrity sha512-OgHGuhlfZ//mToxjte1D5iiiQgWfJ2GByVMwEC/IuoXsBGkuyK1+KrjYu0laSpnN/L1UmLUCv0s25vObdc1bVg==
@ -800,6 +844,11 @@ fsevents@~2.3.2:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
generic-pool@3.9.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4"
integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==
get-tsconfig@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.2.0.tgz#ff368dd7104dab47bf923404eb93838245c66543"
@ -1170,6 +1219,18 @@ readable-web-to-node-stream@^3.0.2:
dependencies:
readable-stream "^3.6.0"
redis@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/redis/-/redis-4.5.0.tgz#8a461c8718e380ea899ba3711aa0bb217b112089"
integrity sha512-oZGAmOKG+RPnHo0UxM5GGjJ0dBd/Vi4fs3MYwM1p2baDoXC0wpm0yOdpxVS9K+0hM84ycdysp2eHg2xGoQ4FEw==
dependencies:
"@redis/bloom" "1.1.0"
"@redis/client" "1.4.0"
"@redis/graph" "1.1.0"
"@redis/json" "1.0.4"
"@redis/search" "1.1.0"
"@redis/time-series" "1.0.4"
regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
@ -1432,7 +1493,7 @@ ws@^8.9.0:
resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e"
integrity sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==
yallist@^4.0.0:
yallist@4.0.0, yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==