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.
 
 

128 lines
4.5 KiB

/**
* Welcome to Cloudflare Workers! This is your first worker.
*
* - Run `npm run dev` in your terminal to start a development server
* - Open a browser tab at http://localhost:8787/ to see your worker in action
* - Run `npm run deploy` to publish your worker
*
* Learn more at https://developers.cloudflare.com/workers/
*/
import { CloudflareWorkerServer, SlashCreator } from 'slash-create/web';
import { GenerateCommand, ResponseCommand } from './commands.js';
import { DbAccess } from './dbAccess.js';
import { isSnowflake, type Snowflake } from 'discord-snowflake';
import { RollTableOrder } from './rolltable.js';
import { RollTableEmbedTitles, RollTableEmoji, RollTableNames } from './generated.js';
export interface Env {
BASE_URL: string;
DISCORD_APP_ID: string
DISCORD_APP_SECRET: string
DISCORD_PUBLIC_KEY: string
DISCORD_DEV_GUILD_IDS: string
DB: D1Database
}
function getHandler(env: Env, token?: string) {
const dbAccess = new DbAccess(env.DB)
const server = new CloudflareWorkerServer()
const creator = new SlashCreator({
allowedMentions: {everyone: false, roles: false, users: false},
applicationID: env.DISCORD_APP_ID,
componentTimeouts: true,
defaultImageSize: 0,
disableTimeouts: false,
endpointPath: '/discord/interactions',
handleCommandsManually: false,
publicKey: env.DISCORD_PUBLIC_KEY,
unknownCommandResponse: true,
token: token,
})
const withGuilds: Snowflake[] = env.DISCORD_DEV_GUILD_IDS ? env.DISCORD_DEV_GUILD_IDS.split(",").flatMap(v => isSnowflake(v) ? [v] : []) : []
creator.withServer(server)
creator.registerCommand(new GenerateCommand(creator, dbAccess))
creator.registerCommand(new ResponseCommand(creator, dbAccess, env.BASE_URL))
creator.registerCommand(new GenerateCommand(creator, dbAccess, withGuilds))
creator.registerCommand(new ResponseCommand(creator, dbAccess, env.BASE_URL, withGuilds))
return {
fetch: server.fetch.bind(server),
syncCommands: creator.syncCommands.bind(creator),
db: dbAccess,
}
}
function getAuthorization(username: string, password: string): string {
return btoa(username + ":" + password)
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
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)
return new Response(`Could not sync commands: Failed getting token: ${tokenResponse.status} ${tokenResponse.statusText}\n${text}`, {status: 500})
}
const json = await tokenResponse.json() as {access_token: string}
const handler = getHandler(env, "Bearer " + json.access_token)
const url = new URL(request.url)
if (url.pathname === "/discord/interactions") {
try {
return handler.fetch(request, env, ctx)
} catch (e) {
console.error("Failed to respond to interactions endpoint", e);
return new Response(`Could not respond to interaction: ${e}`, {
status: 500
})
}
} else if (url.pathname === "/discord/sync") {
try {
await handler.syncCommands({
deleteCommands: true,
syncGuilds: true,
})
} catch (e) {
console.error("Failed to respond to sync endpoint", e)
return new Response(`Could not sync commands: ${e}`, {
status: 500,
})
}
return new Response(`Synced commands!`, {
status: 200,
})
} else if (url.pathname === "/responses") {
try {
const response = []
const server = url.searchParams.get("server")
const tables = await (server === null
? handler.db.getGlobalResponses()
: handler.db.getResponsesInServer(server))
for (const table of RollTableOrder) {
response.push(`${RollTableNames[table]} - ${RollTableEmoji[table]} ${RollTableEmbedTitles[table]}`)
for (const value of tables[table]) {
response.push(` * ${value}`)
}
response.push('')
}
return new Response(response.join('\n'), {status: 200})
} catch (e) {
console.error("Failed to respond to list endpoint", e)
return new Response(`Could not list responses: ${e}`, {
status: 500,
})
}
} else {
return new Response(`Invalid path ${url.pathname}`, {status: 404})
}
},
};