Scenario generator for vore roleplay and story ideas.
https://scenario-generator.deliciousreya.net/responses
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.7 KiB
101 lines
3.7 KiB
import { Database } from '../db/database';
|
|
import { CloudflareWorkerServer, SlashCreator } from 'slash-create/web';
|
|
import { isSnowflake, type Snowflake } from 'discord-snowflake';
|
|
import { AuthorCommand, GenerateCommand, ResponseCommand } from './commands';
|
|
import { type IRequestStrict, Router } from 'itty-router';
|
|
import { getQueryArray } from '../request/query';
|
|
|
|
function getAuthorization(username: string, password: string): string {
|
|
return btoa(username + ':' + password);
|
|
}
|
|
|
|
async function getToken(env: Pick<DiscordEnv, 'DISCORD_APP_ID' | 'DISCORD_APP_SECRET'>) {
|
|
const tokenRequest = new Request(`https://discord.com/api/v10/oauth2/token`, {
|
|
headers: new Headers({
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'Authorization': `Basic ${getAuthorization(env.DISCORD_APP_ID, env.DISCORD_APP_SECRET)}`
|
|
}),
|
|
body: new URLSearchParams({ 'grant_type': 'client_credentials', 'scope': 'applications.commands.update' }),
|
|
method: 'POST'
|
|
});
|
|
const tokenResponse = await fetch(tokenRequest);
|
|
if (tokenResponse.status !== 200) {
|
|
const text = await tokenResponse.text();
|
|
console.error(`Failed getting token`, text);
|
|
throw Error(text);
|
|
}
|
|
const json = await tokenResponse.json() as { access_token: string };
|
|
return 'Bearer ' + json.access_token;
|
|
}
|
|
|
|
export interface DiscordEnv {
|
|
readonly BASE_URL: string;
|
|
readonly DISCORD_APP_ID: string;
|
|
readonly DISCORD_APP_SECRET: string;
|
|
readonly DISCORD_PUBLIC_KEY: string;
|
|
readonly DISCORD_DEV_GUILD_IDS?: string;
|
|
}
|
|
|
|
interface SlashCreatorContext {
|
|
cfServer: CloudflareWorkerServer;
|
|
slashCreator: SlashCreator;
|
|
}
|
|
|
|
async function getSlashCreator(
|
|
{ DISCORD_APP_ID, DISCORD_APP_SECRET, DISCORD_PUBLIC_KEY, DISCORD_DEV_GUILD_IDS, BASE_URL }: DiscordEnv,
|
|
db: Database
|
|
): Promise<SlashCreatorContext> {
|
|
if (DISCORD_APP_ID === "" || DISCORD_APP_SECRET === "" || DISCORD_PUBLIC_KEY === "") {
|
|
throw Error("Discord is not configured on this build")
|
|
}
|
|
const server = new CloudflareWorkerServer();
|
|
const creator = new SlashCreator({
|
|
allowedMentions: { everyone: false, roles: false, users: false },
|
|
applicationID: DISCORD_APP_ID,
|
|
componentTimeouts: true,
|
|
defaultImageSize: 0,
|
|
disableTimeouts: false,
|
|
handleCommandsManually: false,
|
|
publicKey: DISCORD_PUBLIC_KEY,
|
|
unknownCommandResponse: true,
|
|
token: await getToken({ DISCORD_APP_ID, DISCORD_APP_SECRET })
|
|
});
|
|
const withGuilds: Snowflake[] = DISCORD_DEV_GUILD_IDS ? DISCORD_DEV_GUILD_IDS.split(',').flatMap(v => isSnowflake(v) ? [v] : []) : [];
|
|
creator.withServer(server);
|
|
creator.registerCommand(new GenerateCommand(creator, db));
|
|
creator.registerCommand(new AuthorCommand(creator, db));
|
|
creator.registerCommand(new ResponseCommand(creator, db, BASE_URL));
|
|
creator.registerCommand(new GenerateCommand(creator, db, withGuilds));
|
|
creator.registerCommand(new AuthorCommand(creator, db, withGuilds));
|
|
creator.registerCommand(new ResponseCommand(creator, db, BASE_URL, withGuilds));
|
|
return {
|
|
cfServer: server,
|
|
slashCreator: creator
|
|
};
|
|
}
|
|
|
|
export function discordRouter(base: string) {
|
|
const router = Router<IRequestStrict, [env: DiscordEnv, db: Database, ctx: ExecutionContext]>({ base });
|
|
router.all('/interactions', async (req, env, db, ctx) =>
|
|
(await getSlashCreator(env, db)).cfServer.fetch(req, null, ctx));
|
|
router.get('/sync', async (req, env, db, _ctx) => {
|
|
let servers = getQueryArray(req.query['server']);
|
|
const { slashCreator } = await getSlashCreator(env, db);
|
|
if (servers.length === 0) {
|
|
await slashCreator.syncCommands({
|
|
syncGuilds: true,
|
|
deleteCommands: true,
|
|
skipGuildErrors: false
|
|
});
|
|
} else {
|
|
for (const id of servers) {
|
|
await slashCreator.syncCommandsIn(id, true);
|
|
}
|
|
}
|
|
return new Response('Commands successfully synced!', {
|
|
status: 200,
|
|
statusText: 'OK'
|
|
});
|
|
});
|
|
return router;
|
|
}
|
|
|