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
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})
|
|
}
|
|
},
|
|
};
|
|
|