diff --git a/src/endpoints/guess_letter.ts b/src/endpoints/guess_letter.ts new file mode 100644 index 0000000..f23c995 --- /dev/null +++ b/src/endpoints/guess_letter.ts @@ -0,0 +1,33 @@ +import { database } from "$/main"; +import { addLetter } from "$/utils/game"; +import { ServerRoute } from "@hapi/hapi"; +import Joi from "joi"; + +const route: ServerRoute = { + method: `POST`, path: `/{channel}/guess`, + options: { + validate: { + params: Joi.object({ + channel: Joi.string().alphanum(), + }), + payload: Joi.object({ + guess: Joi.string().length(1), + }), + }, + }, + async handler(request) { + // @ts-ignore + const guess = request.payload.guess.toUpperCase(); + const { channel } = request.params; + + let data = await database.getChannel(channel); + console.log(data) + if (data.solution.includes(guess)) { + data.current = addLetter(data.key, data.current, guess); + } else { + data.incorrect++; + }; + return `${data.current} (incorrect: ${data.incorrect}/6)`; + }, +}; +export default route; \ No newline at end of file diff --git a/src/endpoints/new_game.ts b/src/endpoints/new_game.ts new file mode 100644 index 0000000..6879483 --- /dev/null +++ b/src/endpoints/new_game.ts @@ -0,0 +1,33 @@ +import { database } from "$/main"; +import { anonymizePhrase, convertToKey, spacePhrase } from "$/utils/game"; +import { ServerRoute } from "@hapi/hapi"; +import Joi from "joi"; + +const route: ServerRoute = { + method: `POST`, path: `/{channel}/game`, + options: { + validate: { + params: Joi.object({ + channel: Joi.string().alphanum(), + }), + }, + }, + async handler(request) { + const { channel } = request.params; + + let data = await database.getChannel(channel); + + // TODO: Get the proper phrase + let phrase = "Hello world"; + + let spaced = spacePhrase(phrase.toUpperCase()); + let anonymized = anonymizePhrase(spaced); + data.current = anonymized; + data.solution = spaced; + data.incorrect = 0; + data.key = convertToKey(spaced); + + return `${data.current} (incorrect: ${data.incorrect}/6)`; + }, +}; +export default route; \ No newline at end of file diff --git a/src/endpoints/nightbot.ts b/src/endpoints/nightbot.ts new file mode 100644 index 0000000..2e689e3 --- /dev/null +++ b/src/endpoints/nightbot.ts @@ -0,0 +1,54 @@ +import { nightbotCustomHeadersSchema } from "$/schemas/nightbot"; +import { ServerRoute } from "@hapi/hapi"; +import boom from "@hapi/boom"; +import Joi from "joi"; + +const subcommands = { + "start": { + method: `POST`, + modOnly: true, + }, + "show": { + method: `GET`, + modOnly: false, + }, +}; + +const route: ServerRoute = { + method: `GET`, path: `/nightbot`, + options: { + validate: { + query: Joi.object({ + args: Joi.string().allow("").required(), + msg: Joi.string(), + }), + headers: nightbotCustomHeadersSchema.unknown(), + }, + }, + async handler(request) { + let args = (request.query.args) + .split(` `) + .filter(x => x.length > 0); + + if (args.length < 1) { + return `Not enough arguments`; + }; + + let channelData = new URLSearchParams(request.headers["nightbot-channel"]); + let channel = channelData.get(`name`); + let userData = new URLSearchParams(request.headers["nightbot-user"]); + let user = userData.get(`name`); + + if (!channel) { throw boom.badData(`Missing channel name`) }; + if (!user) { throw boom.badData(`Missing user name`) }; + + // User is guessing a letter + if (args[0].length == 1) { + return (await request.server.inject({ + method: `POST`, url: `/${channel}/guess`, + payload: { guess: args[0] } + })).payload; + }; + }, +}; +export default route; \ No newline at end of file diff --git a/src/endpoints/setup_channel.ts b/src/endpoints/setup_channel.ts new file mode 100644 index 0000000..cc47d51 --- /dev/null +++ b/src/endpoints/setup_channel.ts @@ -0,0 +1,20 @@ +import { database } from "$/main"; +import { ServerRoute } from "@hapi/hapi"; +import Joi from "joi"; + +const route: ServerRoute = { + method: `POST`, path: `/channels`, + options: { + validate: { + payload: Joi.object({ + channel: Joi.string().alphanum(), + }), + }, + }, + async handler(request, h) { + // @ts-ignore + await database.createChannel(request.payload.channel); + return h.close; + }, +}; +export default route; \ No newline at end of file diff --git a/src/schemas/nightbot.ts b/src/schemas/nightbot.ts new file mode 100644 index 0000000..4305152 --- /dev/null +++ b/src/schemas/nightbot.ts @@ -0,0 +1,13 @@ +import Joi from "joi"; + +export const nightbotCustomHeadersSchema = Joi.object({ + "nightbot-response-url": Joi + .string() + .uri({ scheme: `https` }), + "nightbot-user": Joi + .string(), + "nightbot-channel": Joi + .string(), +}) +.meta({ className: `nightbotCustomHeaders` }) +.description(`The custom headers Nightbot makes requests with`); \ No newline at end of file diff --git a/src/utils/database/json.ts b/src/utils/database/json.ts index 03a23b8..658ed96 100644 --- a/src/utils/database/json.ts +++ b/src/utils/database/json.ts @@ -2,7 +2,7 @@ import { databaseOptions } from "$/types/config"; import fs from "fs"; export class JSONDatabase { - private data = {}; + private data: any = {}; private conf: databaseOptions; constructor(conf: databaseOptions) { @@ -22,4 +22,17 @@ export class JSONDatabase { public shutdown() { fs.writeFileSync(this.conf.uri, JSON.stringify(this.data)); }; + + public async createChannel(name: string) { + this.data[name] = { + current: null, + solution: null, + key: null, + incorrect: 0, + }; + }; + + public async getChannel(name: string) { + return this.data[name]; + }; }; \ No newline at end of file diff --git a/src/utils/game.ts b/src/utils/game.ts new file mode 100644 index 0000000..6c50140 --- /dev/null +++ b/src/utils/game.ts @@ -0,0 +1,46 @@ +export function addLetter(key: any, current: string, letter: string) { + let indexes = key[letter]; + for (const i of indexes) { + current = current.slice(0, i) + letter.toUpperCase() + current.slice(i+1); + }; + return current; +}; + +export function convertToKey(phrase: string) { + let key: {[index: string]: number[]} = {}; + for (var i = 0; i < phrase.length; i++) { + let letter = phrase[i].toUpperCase(); + if (!letter.match(/[a-zA-Z]/)) { continue }; + if (key[letter] == null) { + key[letter] = []; + }; + key[letter].push(i); + }; + return key; +}; + +export function anonymizePhrase(phrase: string) { + let anon = ``; + for (const letter of phrase) { + if (letter.match(/[A-Za-z]/)) { + anon += `_`; + } else { + anon += letter; + }; + }; + return anon; +}; + +export function spacePhrase(phrase: string) { + let spaced = ``; + for (const letter of phrase) { + if (letter.match(/[A-Za-z]/)) { + spaced += `${letter} `; + } else if (letter == ` `) { + spaced += `█ `; + } else { + spaced += letter; + }; + }; + return spaced; +}; \ No newline at end of file