mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-11 13:56:15 +00:00
157 lines
5.1 KiB
TypeScript
157 lines
5.1 KiB
TypeScript
import { Database } from 'bun:sqlite'
|
|
import { existsSync, readFileSync, readdirSync } from 'fs'
|
|
import { join } from 'path'
|
|
import { Client as APIClient } from '@revanced/bot-api'
|
|
import { createLogger } from '@revanced/bot-shared'
|
|
import { Client as DiscordClient, type Message, Options, Partials } from 'discord.js'
|
|
import { drizzle } from 'drizzle-orm/bun-sqlite'
|
|
|
|
import * as schemas from './database/schemas'
|
|
|
|
import type { default as Command, CommandOptionsOptions, CommandType } from './classes/Command'
|
|
|
|
import { __getConfig, config } from './config'
|
|
export { config, __getConfig }
|
|
|
|
export const logger = createLogger({
|
|
level: config.logLevel === 'none' ? Number.MAX_SAFE_INTEGER : config.logLevel,
|
|
})
|
|
|
|
// Export a few things before we initialize commands
|
|
import * as commands from './commands'
|
|
|
|
export const api = {
|
|
client: new APIClient({
|
|
api: {
|
|
websocket: {
|
|
url: config.api.url,
|
|
},
|
|
},
|
|
}),
|
|
intentionallyDisconnecting: false,
|
|
disconnectCount: 0,
|
|
}
|
|
|
|
const DatabasePath = process.env['DATABASE_PATH']
|
|
const DatabaseSchemaDir = join(import.meta.dir, '..', '.drizzle')
|
|
|
|
let dbSchemaFileName: string | undefined
|
|
|
|
if (DatabasePath && !existsSync(DatabasePath)) {
|
|
logger.warn('Database file not found, trying to create from schema...')
|
|
|
|
try {
|
|
const file = readdirSync(DatabaseSchemaDir, { withFileTypes: true })
|
|
.filter(file => file.isFile() && file.name.endsWith('.sql'))
|
|
.sort()
|
|
.at(-1)
|
|
|
|
if (!file) throw new Error('No schema file found')
|
|
|
|
dbSchemaFileName = file.name
|
|
logger.debug(`Using schema file: ${dbSchemaFileName}`)
|
|
} catch (e) {
|
|
logger.fatal('Could not create database from schema, check if the schema file exists and is accessible')
|
|
logger.fatal(e)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
const db = new Database(DatabasePath, { readwrite: true, create: true })
|
|
if (dbSchemaFileName) db.run(readFileSync(join(DatabaseSchemaDir, dbSchemaFileName)).toString())
|
|
|
|
export const database = drizzle(db, {
|
|
schema: schemas,
|
|
})
|
|
|
|
export const discord = {
|
|
client: new DiscordClient({
|
|
intents: [
|
|
'Guilds',
|
|
'GuildMembers',
|
|
'GuildModeration',
|
|
'GuildMessages',
|
|
'GuildMessageReactions',
|
|
'DirectMessages',
|
|
'DirectMessageReactions',
|
|
'MessageContent',
|
|
],
|
|
allowedMentions: {
|
|
parse: ['users'],
|
|
repliedUser: true,
|
|
},
|
|
sweepers: {
|
|
...Options.DefaultSweeperSettings,
|
|
messages: {
|
|
interval: 1_800, // Every 30m
|
|
lifetime: 3_600, // Remove messages older than 1h
|
|
},
|
|
},
|
|
makeCache: Options.cacheWithLimits({
|
|
...Options.DefaultMakeCacheSettings,
|
|
UserManager: 50,
|
|
GuildMemberManager: {
|
|
maxSize: 50,
|
|
// Always keep client guild member in cache
|
|
keepOverLimit: member => member.id === member.client.user.id,
|
|
},
|
|
ThreadManager: {
|
|
maxSize: 0,
|
|
// Always keep threads that are used for moderation logging
|
|
keepOverLimit: thread => config.moderation?.log?.thread === thread.id,
|
|
},
|
|
GuildMessageManager: {
|
|
maxSize: 0,
|
|
// Always keep messages posted by the client in cache
|
|
keepOverLimit: message => message.author.id === message.client.user.id,
|
|
},
|
|
// Unneeded cache
|
|
MessageManager: 0,
|
|
ReactionManager: 0,
|
|
VoiceStateManager: 0,
|
|
ThreadMemberManager: 0,
|
|
StageInstanceManager: 0,
|
|
ReactionUserManager: 0,
|
|
PresenceManager: 0,
|
|
GuildTextThreadManager: 0,
|
|
GuildStickerManager: 0,
|
|
DMMessageManager: 0,
|
|
GuildEmojiManager: 0,
|
|
GuildBanManager: 0,
|
|
GuildScheduledEventManager: 0,
|
|
EntitlementManager: 0,
|
|
AutoModerationRuleManager: 0,
|
|
GuildForumThreadManager: 0,
|
|
BaseGuildEmojiManager: 0,
|
|
GuildInviteManager: 0,
|
|
}),
|
|
partials: [Partials.Message, Partials.Reaction, Partials.GuildMember],
|
|
}),
|
|
commands: Object.fromEntries(Object.values(commands).map(cmd => [cmd.name, cmd])) as Record<
|
|
string,
|
|
Command<CommandType, CommandOptionsOptions | undefined, boolean>
|
|
>,
|
|
stickyMessages: {} as Record<
|
|
string,
|
|
Record<
|
|
string,
|
|
{
|
|
/**
|
|
* Chat is active, so force send timer is also active
|
|
*/
|
|
forceTimerActive: boolean
|
|
/**
|
|
* There was a message sent, so the timer is active
|
|
*/
|
|
timerActive: boolean
|
|
timerMs: number
|
|
forceTimerMs?: number
|
|
send: () => Promise<void>
|
|
currentMessage?: Message<true>
|
|
timer?: NodeJS.Timeout
|
|
forceTimer?: NodeJS.Timeout
|
|
}
|
|
>
|
|
>,
|
|
} as const
|