mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-13 14:33:15 +00:00
Compare commits
6 Commits
@revanced/
...
@revanced/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9897f244e0 | ||
|
|
eaa25f2eb5 | ||
|
|
a976dd2acc | ||
|
|
c567ef25c6 | ||
|
|
de8bef6520 | ||
|
|
98dea81eeb |
@@ -1,3 +1,19 @@
|
|||||||
|
# @revanced/discord-bot [1.0.0-dev.21](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.20...@revanced/discord-bot@1.0.0-dev.21) (2024-08-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** correct sticky messages logic ([de8bef6](https://github.com/revanced/revanced-helper/commit/de8bef6520d53a1299f0478458320a7eb75c5e1d))
|
||||||
|
* **bots/discord:** make `/eval` work ([eaa25f2](https://github.com/revanced/revanced-helper/commit/eaa25f2eb58a9e2d25bb98633ad668485e099714))
|
||||||
|
* **bots/discord:** some configuration values not applying after running `/reload` ([a976dd2](https://github.com/revanced/revanced-helper/commit/a976dd2accc4b74914651245acde0979c30c92f5))
|
||||||
|
|
||||||
|
# @revanced/discord-bot [1.0.0-dev.20](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.19...@revanced/discord-bot@1.0.0-dev.20) (2024-08-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** await when putting entries into db ([4da6175](https://github.com/revanced/revanced-helper/commit/4da6175cf58b1fa6144bdc71ec806766d32c1025))
|
||||||
|
|
||||||
# @revanced/discord-bot [1.0.0-dev.19](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.18...@revanced/discord-bot@1.0.0-dev.19) (2024-08-03)
|
# @revanced/discord-bot [1.0.0-dev.19](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.18...@revanced/discord-bot@1.0.0-dev.19) (2024-08-03)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "@revanced/discord-bot",
|
"name": "@revanced/discord-bot",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0-dev.19",
|
"version": "1.0.0-dev.21",
|
||||||
"description": "🤖 Discord bot assisting ReVanced",
|
"description": "🤖 Discord bot assisting ReVanced",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { inspect } from 'util'
|
import { inspect } from 'util'
|
||||||
import { runInThisContext } from 'vm'
|
|
||||||
import { ApplicationCommandOptionType } from 'discord.js'
|
import { ApplicationCommandOptionType } from 'discord.js'
|
||||||
|
|
||||||
import { AdminCommand } from '$/classes/Command'
|
import { AdminCommand } from '$/classes/Command'
|
||||||
@@ -26,7 +25,14 @@ export default new AdminCommand({
|
|||||||
embeds: [
|
embeds: [
|
||||||
createSuccessEmbed('Evaluate', `\`\`\`js\n${code}\`\`\``).addFields({
|
createSuccessEmbed('Evaluate', `\`\`\`js\n${code}\`\`\``).addFields({
|
||||||
name: 'Result',
|
name: 'Result',
|
||||||
value: `\`\`\`js\n${inspect(runInThisContext(code), { depth: 1, showHidden, getters: true, numericSeparator: true, showProxy: true })}\`\`\``,
|
// biome-ignore lint/security/noGlobalEval: This is fine as it's an admin command
|
||||||
|
value: `\`\`\`js\n${inspect(eval(code), {
|
||||||
|
depth: 1,
|
||||||
|
showHidden,
|
||||||
|
getters: true,
|
||||||
|
numericSeparator: true,
|
||||||
|
showProxy: true,
|
||||||
|
})}\`\`\``,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,11 +7,29 @@ export default new AdminCommand({
|
|||||||
name: 'reload',
|
name: 'reload',
|
||||||
description: 'Reload configuration',
|
description: 'Reload configuration',
|
||||||
async execute(context, trigger) {
|
async execute(context, trigger) {
|
||||||
|
const { api, logger, discord } = context
|
||||||
context.config = ((await import(join(dirname(Bun.main), '..', 'config.js'))) as { default: Config }).default
|
context.config = ((await import(join(dirname(Bun.main), '..', 'config.js'))) as { default: Config }).default
|
||||||
|
|
||||||
await trigger.reply({
|
if ('deferReply' in trigger) await trigger.deferReply({ ephemeral: true })
|
||||||
content: 'Reloaded configuration',
|
|
||||||
ephemeral: true,
|
logger.info('Reinitializing API client to reload configuration...')
|
||||||
})
|
await api.client.ws.setOptions(
|
||||||
|
{
|
||||||
|
url: context.config.api.url,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
api.intentionallyDisconnecting = true
|
||||||
|
api.client.disconnect(true)
|
||||||
|
api.disconnectCount = 0
|
||||||
|
api.intentionallyDisconnecting = false
|
||||||
|
await api.client.connect()
|
||||||
|
|
||||||
|
logger.info('Reinitializing Discord client to reload configuration...')
|
||||||
|
await discord.client.destroy()
|
||||||
|
await discord.client.login()
|
||||||
|
|
||||||
|
// @ts-expect-error: TypeScript dum
|
||||||
|
await trigger[('deferReply' in trigger ? 'editReply' : 'reply')]({ content: 'Reloaded configuration' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -90,13 +90,20 @@ export const discord = {
|
|||||||
Record<
|
Record<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
forceSendTimerActive?: boolean
|
/**
|
||||||
timeoutMs: number
|
* Chat is active, so force send timer is also active
|
||||||
forceSendMs?: number
|
*/
|
||||||
|
forceTimerActive: boolean
|
||||||
|
/**
|
||||||
|
* There was a message sent, so the timer is active
|
||||||
|
*/
|
||||||
|
timerActive: boolean
|
||||||
|
timerMs: number
|
||||||
|
forceTimerMs?: number
|
||||||
send: (forced?: boolean) => Promise<void>
|
send: (forced?: boolean) => Promise<void>
|
||||||
currentMessage?: Message<true>
|
currentMessage?: Message<true>
|
||||||
interval?: NodeJS.Timeout
|
timer?: NodeJS.Timeout
|
||||||
forceSendInterval?: NodeJS.Timeout
|
forceTimer?: NodeJS.Timeout
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
>,
|
>,
|
||||||
|
|||||||
@@ -7,24 +7,31 @@ withContext(on, 'messageCreate', async ({ discord, logger }, msg) => {
|
|||||||
const store = discord.stickyMessages[msg.guildId]?.[msg.channelId]
|
const store = discord.stickyMessages[msg.guildId]?.[msg.channelId]
|
||||||
if (!store) return
|
if (!store) return
|
||||||
|
|
||||||
if (!store.interval) store.interval = setTimeout(store.send, store.timeoutMs) as NodeJS.Timeout
|
// If there isn't a timer, start it up
|
||||||
|
store.timerActive = true
|
||||||
|
if (!store.timer) store.timer = setTimeout(store.send, store.timerMs) as NodeJS.Timeout
|
||||||
else {
|
else {
|
||||||
store.interval.refresh()
|
// If there is a timer, but it isn't active, restart it
|
||||||
|
if (!store.timerActive) store.timer.refresh()
|
||||||
|
// If there is a timer and it is active, but the force timer isn't active...
|
||||||
|
else if (!store.forceTimerActive && store.forceTimerMs) {
|
||||||
|
logger.debug(`Channel ${msg.channelId} in guild ${msg.guildId} is active, starting force send timer and clearing existing timer`)
|
||||||
|
|
||||||
if (!store.forceSendTimerActive && store.forceSendMs) {
|
// Clear the timer
|
||||||
logger.debug(`Channel ${msg.channelId} in guild ${msg.guildId} is active, starting force send timer`)
|
clearTimeout(store.timer)
|
||||||
|
store.timerActive = false
|
||||||
|
store.forceTimerActive = true
|
||||||
|
|
||||||
store.forceSendTimerActive = true
|
// (Re)start the force timer
|
||||||
|
if (!store.forceTimer)
|
||||||
if (!store.forceSendInterval)
|
store.forceTimer = setTimeout(
|
||||||
store.forceSendInterval = setTimeout(
|
|
||||||
() =>
|
() =>
|
||||||
store.send(true).then(() => {
|
store.send(true).then(() => {
|
||||||
store.forceSendTimerActive = false
|
store.forceTimerActive = false
|
||||||
}),
|
}),
|
||||||
store.forceSendMs,
|
store.forceTimerMs,
|
||||||
) as NodeJS.Timeout
|
) as NodeJS.Timeout
|
||||||
else store.forceSendInterval.refresh()
|
else store.forceTimer.refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,11 +14,16 @@ export default withContext(on, 'ready', async ({ config, discord, logger }, clie
|
|||||||
if (config.stickyMessages)
|
if (config.stickyMessages)
|
||||||
for (const [guildId, channels] of Object.entries(config.stickyMessages)) {
|
for (const [guildId, channels] of Object.entries(config.stickyMessages)) {
|
||||||
const guild = await client.guilds.fetch(guildId)
|
const guild = await client.guilds.fetch(guildId)
|
||||||
|
// In case of configuration refresh, this will not be nullable
|
||||||
|
const oldStore = discord.stickyMessages[guildId]
|
||||||
discord.stickyMessages[guildId] = {}
|
discord.stickyMessages[guildId] = {}
|
||||||
|
|
||||||
for (const [channelId, { message, timeout, forceSendTimeout }] of Object.entries(channels)) {
|
for (const [channelId, { message, timeout, forceSendTimeout }] of Object.entries(channels)) {
|
||||||
const channel = await guild.channels.fetch(channelId)
|
const channel = await guild.channels.fetch(channelId)
|
||||||
if (!channel?.isTextBased()) return
|
if (!channel?.isTextBased())
|
||||||
|
return void logger.warn(
|
||||||
|
`Channel ${channelId} in guild ${guildId} is not a text channel, sticky messages will not be sent`,
|
||||||
|
)
|
||||||
|
|
||||||
const send = async (forced = false) => {
|
const send = async (forced = false) => {
|
||||||
try {
|
try {
|
||||||
@@ -33,17 +38,19 @@ export default withContext(on, 'ready', async ({ config, discord, logger }, clie
|
|||||||
await store.currentMessage?.delete().catch()
|
await store.currentMessage?.delete().catch()
|
||||||
store.currentMessage = msg
|
store.currentMessage = msg
|
||||||
|
|
||||||
if (!forced) {
|
// Clear any remaining timers
|
||||||
clearTimeout(store.forceSendInterval)
|
clearTimeout(store.timer)
|
||||||
|
clearTimeout(store.forceTimer)
|
||||||
|
store.forceTimerActive = store.timerActive = false
|
||||||
|
|
||||||
|
if (!forced)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Timeout ended for sticky message in channel ${channelId} in guild ${guildId}, channel is inactive`,
|
`Timeout ended for sticky message in channel ${channelId} in guild ${guildId}, channel is inactive`,
|
||||||
)
|
)
|
||||||
} else {
|
else
|
||||||
clearTimeout(store.interval)
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Forced send timeout for sticky message in channel ${channelId} in guild ${guildId} ended, channel is too active`,
|
`Forced send timeout for sticky message in channel ${channelId} in guild ${guildId} ended, channel is too active`,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug(`Sent sticky message to channel ${channelId} in guild ${guildId}`)
|
logger.debug(`Sent sticky message to channel ${channelId} in guild ${guildId}`)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -54,12 +61,19 @@ export default withContext(on, 'ready', async ({ config, discord, logger }, clie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up the store
|
||||||
discord.stickyMessages[guildId]![channelId] = {
|
discord.stickyMessages[guildId]![channelId] = {
|
||||||
forceSendMs: forceSendTimeout,
|
forceTimerActive: false,
|
||||||
timeoutMs: timeout,
|
timerActive: false,
|
||||||
|
forceTimerMs: forceSendTimeout,
|
||||||
|
timerMs: timeout,
|
||||||
send,
|
send,
|
||||||
forceSendTimerActive: false,
|
// If the store exists before the configuration refresh, take its current message
|
||||||
|
currentMessage: oldStore?.[channelId]?.currentMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send a new sticky message immediately, as well as deleting the old/outdated message, if it exists
|
||||||
|
await send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { type RawData, WebSocket } from 'ws'
|
|||||||
* This is the only relevant class for the time being. But in the future, there may be more classes to handle different protocols of the API.
|
* This is the only relevant class for the time being. But in the future, there may be more classes to handle different protocols of the API.
|
||||||
*/
|
*/
|
||||||
export class ClientWebSocketManager {
|
export class ClientWebSocketManager {
|
||||||
readonly url: string
|
url: string
|
||||||
timeout: number
|
timeout: number
|
||||||
|
|
||||||
connecting = false
|
connecting = false
|
||||||
@@ -33,6 +33,21 @@ export class ClientWebSocketManager {
|
|||||||
this.timeout = options.timeout ?? 10000
|
this.timeout = options.timeout ?? 10000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL to connect to
|
||||||
|
*
|
||||||
|
* **Requires a reconnect to take effect**
|
||||||
|
*/
|
||||||
|
async setOptions({ url, timeout }: Partial<ClientWebSocketManagerOptions>, autoReconnect = true) {
|
||||||
|
if (url) this.url = url
|
||||||
|
this.timeout = timeout ?? this.timeout
|
||||||
|
|
||||||
|
if (autoReconnect) {
|
||||||
|
this.disconnect(true)
|
||||||
|
await this.connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects to the WebSocket API
|
* Connects to the WebSocket API
|
||||||
* @returns A promise that resolves when the client is ready
|
* @returns A promise that resolves when the client is ready
|
||||||
|
|||||||
Reference in New Issue
Block a user