mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-21 17:25:10 -05:00
Chat: Support accessing the chat-plugin database (#8433)
This commit is contained in:
parent
ca1400ddc3
commit
3288a1469e
11
databases/schemas/chat-plugins.sql
Normal file
11
databases/schemas/chat-plugins.sql
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
-- Database schema for chat plugins
|
||||
|
||||
-- As per the design outlined at https://gist.github.com/AnnikaCodes/afa36fc8b17791be812eebbb22182426,
|
||||
-- each table should be prefixed by the plugin name.
|
||||
|
||||
CREATE TABLE db_info (
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
PRIMARY KEY (key)
|
||||
);
|
||||
INSERT INTO db_info VALUES ('version', '1');
|
||||
|
|
@ -24,9 +24,11 @@ To reload chat commands:
|
|||
*/
|
||||
|
||||
import type {RoomPermission, GlobalPermission} from './user-groups';
|
||||
import {FriendsDatabase, PM} from './friends';
|
||||
import type {Punishment} from './punishments';
|
||||
import type {PartialModlogEntry} from './modlog';
|
||||
import {FriendsDatabase, PM} from './friends';
|
||||
import {SQL, SQLDatabaseManager} from '../lib/sql';
|
||||
import {resolve} from 'path';
|
||||
|
||||
export type PageHandler = (this: PageContext, query: string[], user: User, connection: Connection)
|
||||
=> Promise<string | null | void> | string | null | void;
|
||||
|
|
@ -134,6 +136,8 @@ const MAX_PARSE_RECURSION = 10;
|
|||
const VALID_COMMAND_TOKENS = '/!';
|
||||
const BROADCAST_TOKEN = '!';
|
||||
|
||||
const PLUGIN_DATABASE_PATH = './databases/chat-plugins.db';
|
||||
|
||||
import {FS, Utils} from '../lib';
|
||||
import {formatText, linkRegex, stripFormatting} from './chat-formatter';
|
||||
|
||||
|
|
@ -1414,6 +1418,7 @@ export const Chat = new class {
|
|||
void this.loadTranslations().then(() => {
|
||||
Chat.translationsLoaded = true;
|
||||
});
|
||||
this.databaseReadyPromise = this.prepareDatabase();
|
||||
}
|
||||
translationsLoaded = false;
|
||||
/**
|
||||
|
|
@ -1678,6 +1683,51 @@ export const Chat = new class {
|
|||
return translated;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL handler
|
||||
*
|
||||
* All chat plugins share one database.
|
||||
* Chat.databaseReadyPromise will be truthy if the database is not yet ready.
|
||||
*/
|
||||
database: SQLDatabaseManager | null = null;
|
||||
databaseReadyPromise: Promise<void> | null = null;
|
||||
|
||||
async prepareDatabase() {
|
||||
if (process.send) return; // We don't need a database in a subprocess that requires Chat.
|
||||
if (!Config.usesqlite) return;
|
||||
this.database = SQL(module, {file: ('Config' in global && Config.nofswriting) ? ':memory:' : PLUGIN_DATABASE_PATH});
|
||||
// check if we have the db_info table, which will always be present unless the schema needs to be initialized
|
||||
let statement = await this.database.prepare(
|
||||
`SELECT count(*) AS hasDBInfo FROM sqlite_master WHERE type = 'table' AND name = 'db_info'`
|
||||
);
|
||||
if (!statement) return; // I was told this is a best practice for the SQL library
|
||||
const {hasDBInfo} = await this.database.get(statement);
|
||||
if (!hasDBInfo) await this.database.runFile('./databases/schemas/chat-plugins.sql');
|
||||
|
||||
statement = await this.database.prepare(
|
||||
`SELECT value as curVersion FROM db_info WHERE key = 'version'`
|
||||
);
|
||||
if (!statement) return;
|
||||
const result = await this.database.get(statement);
|
||||
const curVersion = parseInt(result.curVersion);
|
||||
if (!curVersion) throw new Error(`db_info table is present, but schema version could not be parsed`);
|
||||
|
||||
// automatically run migrations of the form "v{number}.sql" in the migrations/chat-plugins folder
|
||||
const migrationsFolder = './databases/migrations/chat-plugins';
|
||||
const migrationsToRun = [];
|
||||
for (const migrationFile of (await FS(migrationsFolder).readdir())) {
|
||||
const migrationVersion = parseInt(/v(\d+)\.sql$/.exec(migrationFile)?.[1] || '');
|
||||
if (!migrationVersion) continue;
|
||||
if (migrationVersion > curVersion) migrationsToRun.push({version: migrationVersion, file: migrationFile});
|
||||
}
|
||||
Utils.sortBy(migrationsToRun, ({version}) => version);
|
||||
for (const {file} of migrationsToRun) {
|
||||
await this.database.runFile(resolve(migrationsFolder, file));
|
||||
}
|
||||
|
||||
Chat.destroyHandlers.push(() => Chat.database?.destroy());
|
||||
}
|
||||
|
||||
readonly MessageContext = MessageContext;
|
||||
readonly CommandContext = CommandContext;
|
||||
readonly PageContext = PageContext;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user