initial port to cfworkers i guess

This commit is contained in:
41666 2020-12-03 00:32:07 -05:00
parent ab9fe30b42
commit 9eeb946389
37 changed files with 367 additions and 1098 deletions

1
src/backend-worker/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
dist

10
src/backend-worker/bindings.d.ts vendored Normal file
View file

@ -0,0 +1,10 @@
export {};
declare global {
const BOT_CLIENT_ID: string;
const BOT_CLIENT_SECRET: string;
const UI_PUBLIC_URI: string;
const API_PUBLIC_URI: string;
const ROOT_USERS: string;
const KV_PREFIX: string;
}

View file

@ -0,0 +1,35 @@
import { Bounce } from '../utils/bounce';
const validGuildID = /^[0-9]+$/;
type URLParams = {
clientID: string;
permissions: number;
guildID?: string;
};
const buildURL = (params: URLParams) => {
let url = `https://discord.com/api/oauth2/authorize?client_id=${params.clientID}&scope=bot&permissions=${params.permissions}`;
if (params.guildID) {
url += `&guild_id=${params.guildID}&disable_guild_select=true`;
}
return url;
};
export const BotJoin = (request: Request): Response => {
let guildID = new URL(request.url).searchParams.get('guild') || '';
if (guildID && !validGuildID.test(guildID)) {
guildID = '';
}
return Bounce(
buildURL({
clientID: BOT_CLIENT_ID,
permissions: 268435456,
guildID,
})
);
};

View file

@ -0,0 +1,23 @@
import { v4 as uuidv4 } from 'uuid';
import { Bounce } from '../utils/bounce';
type URLParams = {
clientID: string;
redirectURI: string;
state: string;
};
const buildURL = (params: URLParams) =>
`https://discord.com/api/oauth2/authorize?client_id=${
params.clientID
}&response_type=code&scope=identify%20guilds&redirect_uri=${encodeURIComponent(
params.redirectURI
)}&state=${params.state}`;
export const LoginBounce = (request: Request): Response => {
const state = uuidv4();
const redirectURI = `${API_PUBLIC_URI}/login-callback`;
const clientID = BOT_CLIENT_ID;
return Bounce(buildURL({ state, redirectURI, clientID }));
};

View file

@ -0,0 +1,3 @@
export const LoginCallback = (request: Request): Response => {
return new Response('login-callback!');
};

View file

@ -0,0 +1,14 @@
import { BotJoin } from './handlers/bot-join';
import { LoginBounce } from './handlers/login-bounce';
import { LoginCallback } from './handlers/login-callback';
import { Router } from './router';
const router = new Router();
router.add('GET', 'bot-join', BotJoin);
router.add('GET', 'login-bounce', LoginBounce);
router.add('GET', 'login-callback', LoginCallback);
addEventListener('fetch', (event: FetchEvent) => {
event.respondWith(router.handle(event.request));
});

View file

@ -0,0 +1,73 @@
export type Handler = (request: Request) => Promise<Response> | Response;
type RoutingTree = {
[method: string]: {
[path: string]: Handler;
};
};
type Fallbacks = {
root: Handler;
404: Handler;
500: Handler;
};
export class Router {
private routingTree: RoutingTree = {};
private fallbacks: Fallbacks = {
root: this.respondToRoot,
404: this.notFound,
500: this.serverError,
};
addFallback(which: keyof Fallbacks, handler: Handler) {
this.fallbacks[which] = handler;
}
add(method: string, rootPath: string, handler: Handler) {
const lowerMethod = method.toLowerCase();
if (!this.routingTree[lowerMethod]) {
this.routingTree[lowerMethod] = {};
}
this.routingTree[lowerMethod][rootPath] = handler;
}
handle(request: Request): Promise<Response> | Response {
if (request.url === '/') {
return this.fallbacks.root(request);
}
const lowerMethod = request.method.toLowerCase();
const url = new URL(request.url);
const rootPath = url.pathname.split('/')[1];
const handler = this.routingTree[lowerMethod]?.[rootPath];
if (handler) {
try {
return handler(request);
} catch (e) {
console.error(e);
return this.fallbacks[500](request);
}
}
return this.fallbacks[404](request);
}
private respondToRoot(): Response {
return new Response('Hi there!');
}
private notFound(): Response {
return new Response(JSON.stringify({ error: 'not_found' }), {
status: 404,
});
}
private serverError(): Response {
return new Response(JSON.stringify({ error: 'internal_server_error' }), {
status: 500,
});
}
}

View file

@ -0,0 +1,14 @@
{
"compilerOptions": {
"outDir": "./dist",
"lib": ["esnext", "webworker"],
"types": ["@cloudflare/workers-types"]
},
"include": [
"./*.ts",
"./**/*.ts",
"../../node_modules/@cloudflare/workers-types/index.d.ts"
],
"exclude": ["./**/*.spec.ts"],
"extends": "../../tsconfig.json"
}

View file

@ -0,0 +1,7 @@
export const Bounce = (url: string): Response =>
new Response(null, {
status: 303,
headers: {
location: url,
},
});

View file

@ -0,0 +1,29 @@
const path = require('path');
const mode = process.env.NODE_ENV || 'production';
module.exports = {
target: 'webworker',
entry: path.join(__dirname, 'index.ts'),
output: {
filename: `worker.${mode}.js`,
path: path.join(__dirname, 'dist'),
},
mode,
resolve: {
extensions: ['.ts', '.tsx', '.js'],
plugins: [],
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
transpileOnly: true,
configFile: path.join(__dirname, 'tsconfig.json'),
},
},
],
},
};