Skip to content

Commit

Permalink
Add a run-fuzzy-command function
Browse files Browse the repository at this point in the history
This is exposed over a server so that my Mac can contact the bot to get
it to run commands that I vocalize.
  • Loading branch information
AdamLearns committed Feb 9, 2024
1 parent 180e746 commit ffce71f
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 1 deletion.
6 changes: 6 additions & 0 deletions packages/bots/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,9 @@ MIGRATE_DATABASE_ON_STARTUP=true

# This is where we'll save database back-ups if a migration was needed
DATABASE_BACKUP_LOCATION=

# This is the port that the bot's server listens on.
SERVER_PORT=3001

# This is the password that must be specified in requests to the bot's server.
SERVER_PASSWORD="blah"
3 changes: 3 additions & 0 deletions packages/bots/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"dependencies": {
"@d-fischer/typed-event-emitter": "^3.3.3",
"@hono/node-server": "^1.7.0",
"@twurple/api": "^7.0.7",
"@twurple/auth": "^7.0.7",
"@twurple/chat": "^7.0.7",
Expand All @@ -22,6 +23,8 @@
"date-fns": "^3.0.6",
"discord.js": "^14.14.1",
"dotenv-flow": "^4.0.1",
"fuse.js": "^7.0.0",
"hono": "^4.0.0",
"tsx": "^4.6.2",
"typescript": "^5.3.2"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/bots/src/server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Reason why this exists

For the code jam, I wanted the bot to be able to type commands in chat based on what I _say_, e.g. saying "check out the keyboard command" would type `!keyboard` in chat. In order for this to work, I need my main computer to have a way of interfacing with the bot. The web interface _seems_ like it would be the right approach, but we would still need a communication route between the web interface and the bot. That means that the bot needs its own server eventually, which is what this code is!
56 changes: 56 additions & 0 deletions packages/bots/src/server/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { serve } from "@hono/node-server"
import dotenvFlow from "dotenv-flow"
import { Hono, type Context } from "hono"
import type { BlankInput, Env } from "hono/types"

import type { Bot } from "../twitch/Bot.js"

dotenvFlow.config()

const serverPassword = process.env.SERVER_PASSWORD
const serverPort = process.env.SERVER_PORT

interface FuzzyCommandRequestBody {
query: string
password: string
}

async function handleRunFuzzyCommand(
bot: Bot,
c: Context<Env, "/run-fuzzy-command", BlankInput>,
) {
const { password, query } = await c.req.json<FuzzyCommandRequestBody>()

if (password !== serverPassword) {
return c.text("Invalid password.", 403)
}

await bot.emitFuzzyCommand(query)

return c.text("Successfully emitted a command.")
}

function startServer(bot: Bot) {
const app = new Hono()

app.post("/run-fuzzy-command", (c) => handleRunFuzzyCommand(bot, c))

const port = Number.parseInt(serverPort as string, 10)
console.log(`Server is running on port ${port}`)

serve({
fetch: app.fetch,
hostname: "0.0.0.0",
port,
})
}

export function init(bot: Bot) {
if (serverPassword === undefined || serverPort === undefined) {
throw new Error(
"Missing environment variables. Make sure to copy .env.example to .env and fill out the values.",
)
}

startServer(bot)
}
24 changes: 24 additions & 0 deletions packages/bots/src/twitch/Bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
} from "abbott-database"
import { BotDatabase, UUID, uuidv7 } from "abbott-database"
import { formatISO } from "date-fns"
import Fuse, { type FuseResult } from "fuse.js"

import type { CommandData } from "../commands/CommandData.js"
import { emitter } from "../events/emitter.js"
Expand Down Expand Up @@ -851,4 +852,27 @@ get-tokens.ts.`,
) => {
await this.processPotentialCommand(channel, user, text, msg)
}

async emitFuzzyCommand(query: string) {
const dbCommands = await this.storageLayer.loadTextCommands()
const fuse = new Fuse(dbCommands, { keys: ["name"] })

const results = fuse.search(query)
if (results.length === 0) {
await this.say(
this.twitchChannelName,
`Adam tried getting you to check out a command, but I couldn't find one matching "${query}".`,
)
} else {
const firstResult = results[0] as FuseResult<DatabaseTextCommand>

const { name, response } = firstResult.item

await this.say(
this.twitchChannelName,
`Adam suggested that you check out the !${name} command. I'll run that for you now. MrDestructoid`,
)
await this.say(this.twitchChannelName, response)
}
}
}
4 changes: 3 additions & 1 deletion packages/bots/src/twitch/init.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RefreshingAuthProvider } from "@twurple/auth"

import { init as initServer } from "../server/init.js"
import { onProcessClose } from "../setup/termination-handler.js"

import { Bot } from "./Bot.js"
Expand Down Expand Up @@ -52,5 +53,6 @@ async function createBot(): Promise<Bot> {
}

export async function init() {
await createBot()
const bot = await createBot()
initServer(bot)
}
19 changes: 19 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ffce71f

Please sign in to comment.