From 3bfec456bfb076cb1a74978dc9209d2d60168448 Mon Sep 17 00:00:00 2001 From: bravo68web Date: Sun, 31 Dec 2023 21:04:56 +0530 Subject: [PATCH] wordle api upload --- .gitignore | 175 ++++++++++++++++++++++++++++++++++++++ README.md | 15 ++++ bun.lockb | Bin 0 -> 6010 bytes package.json | 18 ++++ scripts/.gitignore | 2 + scripts/extract.py | 24 ++++++ scripts/output/.gitkeep | 0 scripts/wordbank/.gitkeep | 0 server.ts | 73 ++++++++++++++++ tsconfig.json | 22 +++++ upload.ts | 28 ++++++ 11 files changed, 357 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100755 bun.lockb create mode 100644 package.json create mode 100644 scripts/.gitignore create mode 100644 scripts/extract.py create mode 100644 scripts/output/.gitkeep create mode 100644 scripts/wordbank/.gitkeep create mode 100644 server.ts create mode 100644 tsconfig.json create mode 100644 upload.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..468f82a --- /dev/null +++ b/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..10487fd --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# wordle-api + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.0.15. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..0778a8c18b644d24fad77ebec699a75edd6b4514 GIT binary patch literal 6010 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 Sr>$T(o*szD;9mX@|9%He%$HgK literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 0000000..899f03e --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "wordle-api", + "module": "index.ts", + "type": "module", + "scripts": { + "gen": "cd scripts && python extract.py" + }, + "devDependencies": { + "bun-types": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "hono": "^3.11.6", + "ioredis": "^5.3.2" + } +} \ No newline at end of file diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 0000000..7b96400 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1,2 @@ +wordbank/*.txt +output/*.txt \ No newline at end of file diff --git a/scripts/extract.py b/scripts/extract.py new file mode 100644 index 0000000..7cc6c9e --- /dev/null +++ b/scripts/extract.py @@ -0,0 +1,24 @@ +import re +import os + +def process_text(input_filename, output_filename): + with open(input_filename, 'r') as input_file: + content = input_file.read() + + # Use regular expression to extract words containing only alphabets + words = re.findall(r'\b[a-zA-Z]+\b', content) + + # Filter words with length 6 + five_letter_words = list(set([word.lower() for word in words if len(word) == 5])) + + with open(output_filename, 'w') as output_file: + # Write each 6-letter word on a new line in the output file + output_file.write('\n'.join(five_letter_words)) + +if __name__ == '__main__': + # Read wordbank directory, and process each file and write to same filename.txt, ignoring .gitkeep file + print('Processing...') + for filename in os.listdir('wordbank'): + if filename != '.gitkeep': + process_text('wordbank/' + filename, 'output/' + filename) + print('Done!') \ No newline at end of file diff --git a/scripts/output/.gitkeep b/scripts/output/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/wordbank/.gitkeep b/scripts/wordbank/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server.ts b/server.ts new file mode 100644 index 0000000..723f0a0 --- /dev/null +++ b/server.ts @@ -0,0 +1,73 @@ +import { Context, Hono } from 'hono'; +import { cors } from 'hono/cors'; +import { logger } from 'hono/logger'; +import Redis from 'ioredis'; + +const app = new Hono(); +const client = new Redis(process.env.REDIS_URI as string); + +app.use("*", cors()); +app.use("*", logger()); + +app.get("/", async (ctx: Context) => { + return ctx.text("Wordle API"); +}); + +app.patch("/gen", async (ctx: Context) => { + const { key } = ctx.req.query(); + if(key !== process.env.SECRET_KEY) { + return ctx.json({ + message: 'Invalid key', + }, 401); + } + let wordForToday = await client.randomkey(); + if(wordForToday == 'today') { + wordForToday = await client.randomkey(); + } + await client.set('today', wordForToday as string); + // await client.del(wordForToday as string); + return ctx.json({ + today: wordForToday, + }); +}) + +app.post("/check", async (ctx: Context) => { + const { word } = await ctx.req.json(); + if(!word) { + return ctx.json({ + message: 'Missing word', + }, 400); + } + + const input = word.split('') + const today = await client.get('today') as string; + const todayWord = today.split(''); + let response: any = []; + + for (let i = 0; i < input.length; i++) { + const letter = input[i]; + let isCorrect = false; + if(todayWord[i] === input[i]) { + isCorrect = true; + } + let isLetterInWord = false; + for (const l of todayWord) { + if(l === letter) { + isLetterInWord = true; + break; + } + } + response.push({ + letter, + isCorrectPos: isCorrect, + isLetterInWord, + }); + } + + return ctx.json(response); +}); + +export default { + port: 3000, + fetch: app.fetch, +} as any; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7556e1d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" // add Bun global + ] + } +} diff --git a/upload.ts b/upload.ts new file mode 100644 index 0000000..fd5993f --- /dev/null +++ b/upload.ts @@ -0,0 +1,28 @@ +import fs from 'fs'; +import Redis from "ioredis" + +const client = new Redis(process.env.REDIS_URI as string); + +const getFilesForUpload = () => { + const files = fs.readdirSync('scripts/output'); + return files; +} + +const extractWords = async () => { + console.log('Uploading words to redis collection ...'); + const files = getFilesForUpload(); + const wordList: string[] = []; + for (const file of files) { + if(file === '.gitkeep') continue; + const fileData = fs.readFileSync(`scripts/output/${file}`, 'utf-8'); + const words = fileData.split('\n'); + wordList.push(...words); + } + for (const word of wordList) { + await client.set(word, 0); + } + console.log('Done'); + process.exit(0); +} + +await extractWords(); \ No newline at end of file