From c55ce3b828272788d6e322f1fd37fbc3880848b9 Mon Sep 17 00:00:00 2001 From: Katalina Okano Date: Tue, 15 Dec 2020 15:29:25 -0500 Subject: [PATCH] feat(api): add get-slug --- src/backend-emulator/kv.js | 12 ++++-- src/backend-emulator/main.js | 57 +++++++++++++++---------- src/backend-worker/handlers/get-slug.ts | 45 ++++++++++++++++--- src/backend-worker/router.ts | 2 +- src/backend-worker/utils/api-tools.ts | 11 +++-- src/backend-worker/utils/guild.ts | 4 ++ src/backend-worker/webpack.config.js | 7 ++- 7 files changed, 100 insertions(+), 38 deletions(-) diff --git a/src/backend-emulator/kv.js b/src/backend-emulator/kv.js index ac9994b..a8f58d6 100644 --- a/src/backend-emulator/kv.js +++ b/src/backend-emulator/kv.js @@ -51,13 +51,17 @@ class KVShim { } async get(key, type = 'text') { - const result = JSON.parse(await this.level.get(key)); + try { + const result = JSON.parse(await this.level.get(key)); - if (!this.validate(result)) { + if (!this.validate(result)) { + return null; + } + + return getConversion[type](result.value); + } catch (e) { return null; } - - return getConversion[type](result.value); } async getWithMetadata(key, type) { diff --git a/src/backend-emulator/main.js b/src/backend-emulator/main.js index de26969..e053b5b 100644 --- a/src/backend-emulator/main.js +++ b/src/backend-emulator/main.js @@ -30,14 +30,7 @@ const context = () => listeners.push(fn); } }, - Response: class { - constructor(body, opts = {}) { - this.body = Buffer.from(body || ''); - this.headers = opts.headers || {}; - this.url = opts.url || {}; - this.status = opts.status || 200; - } - }, + Response: fetch.Response, URL: URL, crypto: crypto, setTimeout: setTimeout, @@ -45,6 +38,7 @@ const context = () => clearInterval: clearInterval, clearTimeout: clearTimeout, fetch: fetch, + console: console, ...workerShims, }, { @@ -59,24 +53,37 @@ const server = http.createServer((req, res) => { const event = { respondWith: async (value) => { const timeStart = Date.now(); - const response = await value; + let loggedStatus = 'xxx'; + try { + const response = await value; + if (!response) { + throw new Error( + `response was invalid, got ${JSON.stringify(response)}` + ); + } + res.statusCode = response.status; + loggedStatus = String(response.status); + Object.entries(response.headers).forEach(([k, v]) => res.setHeader(k, v)); + res.end(response.body); + } catch (e) { + console.error(e); + res.statusCode = 500; + loggedStatus = '500'; + res.end(JSON.stringify({ error: 'internal server error' })); + } const timeEnd = Date.now(); console.log( - `${response.status} [${timeEnd - timeStart}ms] - ${req.method} ${req.url}` + `${loggedStatus} [${timeEnd - timeStart}ms] - ${req.method} ${req.url}` ); - res.statusCode = response.status; - Object.entries(response.headers).forEach(([k, v]) => res.setHeader(k, v)); - res.end(response.body); - }, - request: { - url: `http://${req.headers.host || 'localhost'}${req.url}`, - body: req, - headers: Object.entries(req.headers).reduce( - (acc, [k, v]) => acc.set(k, v), - new Map() - ), - method: req.method, }, + request: new fetch.Request( + new URL(`http://${req.headers.host || 'localhost'}${req.url}`), + { + body: ['GET', 'HEAD'].includes(req.method) ? undefined : req, + headers: req.headers, + method: req.method, + } + ), }; event.request.headers.set('cf-client-ip', req.connection.remoteAddress); @@ -110,6 +117,7 @@ const reload = () => { context(), { displayErrors: true, + filename: 'worker.js', } ) ); @@ -124,6 +132,11 @@ const rebuild = () => console.log('Compilation failed.', err); reject(err); } else { + if (stats.hasErrors()) { + console.error('Compilation errored:', stats.compilation.errors); + return; + } + console.log('Compilation done.'); resolve(); } diff --git a/src/backend-worker/handlers/get-slug.ts b/src/backend-worker/handlers/get-slug.ts index bb042bd..1183002 100644 --- a/src/backend-worker/handlers/get-slug.ts +++ b/src/backend-worker/handlers/get-slug.ts @@ -1,9 +1,42 @@ -import { Guild } from "roleypoly/common/types"; -import { discordFetch } from "../utils/api-tools"; +import { GuildSlug } from 'roleypoly/common/types'; +import { respond } from '../utils/api-tools'; +import { getGuild } from '../utils/guild'; export const GetSlug = async (request: Request): Promise => { - const reqURL = new URL(request.url) - const serverID = reqURL.pathname.split('/')[2] - - const serverPayload = discordFetch + // return respond({ hello: 'world' }); + const reqURL = new URL(request.url); + const [, , serverID] = reqURL.pathname.split('/'); + + if (!serverID) { + return respond( + { + error: 'missing server ID', + }, + { + status: 400, + } + ); + } + + const guild = await getGuild(serverID); + if (!guild) { + return respond( + { + error: 'guild not found', + }, + { + status: 404, + } + ); + } + + const { id, name, icon } = guild; + const guildSlug: GuildSlug = { + id, + name, + icon, + permissionLevel: 0, + }; + console.log({ guildSlug }); + return respond(guildSlug); }; diff --git a/src/backend-worker/router.ts b/src/backend-worker/router.ts index e00c0e9..36cd96c 100644 --- a/src/backend-worker/router.ts +++ b/src/backend-worker/router.ts @@ -34,7 +34,7 @@ export class Router { this.routingTree[lowerMethod][rootPath] = handler; } - handle(request: Request): Promise | Response { + async handle(request: Request): Promise | Response { const url = new URL(request.url); if (url.pathname === '/' || url.pathname === '') { diff --git a/src/backend-worker/utils/api-tools.ts b/src/backend-worker/utils/api-tools.ts index b746745..8f849a3 100644 --- a/src/backend-worker/utils/api-tools.ts +++ b/src/backend-worker/utils/api-tools.ts @@ -23,7 +23,7 @@ export const resolveFailures = ( return handler(request); } catch (e) { console.error(e); - return handleWith; + return handleWith || respond({ error: 'internal server error' }, { status: 500 }); } }; @@ -60,7 +60,7 @@ export const discordFetch = async ( url: string, auth: string, authType: 'Bearer' | 'Bot' = 'Bearer' -): Promise => { +): Promise => { const response = await fetch('https://discord.com/api/v8' + url, { headers: { authorization: `${authType} ${auth}`, @@ -69,7 +69,11 @@ export const discordFetch = async ( }, }); - return (await response.json()) as T; + if (response.ok) { + return (await response.json()) as T; + } else { + return null; + } }; export const cacheLayer = ( @@ -86,7 +90,6 @@ export const cacheLayer = ( } const fallbackValue = await missHandler(identity); - if (!fallbackValue) { return null; } diff --git a/src/backend-worker/utils/guild.ts b/src/backend-worker/utils/guild.ts index da4d4c7..bd4f16c 100644 --- a/src/backend-worker/utils/guild.ts +++ b/src/backend-worker/utils/guild.ts @@ -26,6 +26,10 @@ export const getGuild = cacheLayer( async (id: string) => { const guildRaw = await discordFetch(`/guilds/${id}`, botToken, 'Bot'); + if (!guildRaw) { + return null; + } + // Filters the raw guild data into data we actually want const guild: Guild = { id: guildRaw.id, diff --git a/src/backend-worker/webpack.config.js b/src/backend-worker/webpack.config.js index f04820f..1fe5214 100644 --- a/src/backend-worker/webpack.config.js +++ b/src/backend-worker/webpack.config.js @@ -1,4 +1,5 @@ const path = require('path'); +const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); const mode = process.env.NODE_ENV || 'production'; @@ -12,7 +13,11 @@ module.exports = { mode, resolve: { extensions: ['.ts', '.tsx', '.js'], - plugins: [], + plugins: [ + new TsconfigPathsPlugin({ + configFile: path.resolve(__dirname, './tsconfig.json'), + }), + ], }, module: { rules: [