testbot/src/index.js

139 lines
5.1 KiB
JavaScript

const irc = require("irc-upd")
const childProcess = require("child_process")
const syllables = require("syllable")
const R = require("ramda")
const pluralize = require("pluralize")
const { DB, SQL } = require("./db")
var client = new irc.Client(process.argv[2] || "irc.osmarks.net", "testbot", {
channels: ["#a", "#botrobots", "#b"],
userName: "testbot",
encoding: "utf8",
port: 6667
});
let links = null
let linksResolve = null
const logEv = (ty, thing) => SQL`INSERT INTO thing_log (timestamp, type, thing) VALUES (${Date.now()}, ${ty}, ${thing})`.run()
const scanlinks = () => {
return new Promise(resolve => {
if (!linksResolve) {
client.send("LINKS")
linksResolve = [resolve]
links = []
} else {
linksResolve.push(resolve)
}
})
}
let sylhist = []
let mhist = []
// pluralize seems to drop unicode sometimes
// hackily cope with this
const safelyOperate = (s, fn) => {
let res = fn(s)
if (res.trim() === "") { return s }
return res
}
const handleOf = (thing, fn) => {
const ofsplt = /^(.*)\W+of\W+(.*)$/.exec(thing)
if (ofsplt) {
return `${fn(ofsplt[1])} of ${ofsplt[2]}`
} else {
return fn(thing)
}
}
const renderItem = x => x.quantity === 1 ? x.thing : `${x.quantity} ${handleOf(x.thing, pluralize.plural)}`
client.addListener("message", (nick, channel, message, ev) => {
const e = /^<([^>]+)> (.*)$/.exec(message)
if (e) {
nick = e[1]
message = e[2]
}
const res = /^([A-Za-z0-9_-]+)[:, ]*([A-Za-z0-9_-]+) *(.*)$/.exec(message)
if (res) {
let [_, tnick, cmd, args] = res
tnick = tnick.toLowerCase()
args = args.trim().replace(/[.!?]$/, "")
cmd = cmd.toLowerCase()
if (tnick === client.nick) {
console.log(nick, cmd, channel)
if (cmd === "starch") {
client.say(channel, `starch exists (${Math.random() * 20 + 80}% confidence).`)
} else if (cmd === "stats") {
client.say(channel, "haha no")
} else if (cmd === "help") {
client.say(channel, "nobody can help you now")
} else if (cmd === "fortune") {
childProcess.exec("fortune", (err, out) => {
if (err) { return console.warn(err) }
client.say(channel, out)
})
} else if (cmd === "cat") {
client.say(channel, "meow")
} else if (cmd === "servers") {
scanlinks().then(links => client.say(channel, links.map(x => `${x[1]}: ${/^[0-9]+ (.*)$/.exec(x[3])[1]}`).join("\n")))
} else if (cmd === "take" || cmd === "have") {
const things = args.split(/(,| and )/).map(x => x.trim().replace(",", "").replace(/^(an?|the) /, "")).filter(x => x !== "" && x !== "and")
for (let thing of things) {
let qty = 1
const res = /^([-0-9.]+|some|many|half)\b\s*(.*)$/iu.exec(thing)
if (res) {
const [_, rrqty, rthing] = res
thing = rthing
const rqty = rrqty.toLowerCase()
if (rqty === "some") {
qty = Math.floor(Math.random() * 17)
} else if (rqty === "many") {
qty = Math.floor(Math.random() * 2300)
} else if (rqty === "half") {
qty = 0.5
} else {
qty = parseFloat(rqty)
}
}
thing = handleOf(thing, pluralize.singular)
const currQty = SQL`SELECT * FROM inventory WHERE thing = ${thing}`.get()?.quantity
if (currQty) { qty += currQty }
qty = qty || 0
SQL`INSERT OR REPLACE INTO inventory VALUES (${thing}, ${Date.now()}, ${qty})`.run()
console.log("attained", qty, thing)
client.say(channel, `I have ${renderItem({ thing, quantity: qty })}.`)
}
} else if (cmd.startsWith("inv")) {
const inv = SQL`SELECT * FROM inventory ORDER BY obtained_at DESC LIMIT 10`.all()
client.say(channel, inv.map(renderItem).join("\n"))
} else if (cmd === "deploy") {
client.say(channel, `Deploying ${args}`)
}
}
}
const messageContent = message.replace(/^(\s*[<\[][A-Za-z0-9_-]+[>\]]\s*)+/, "")
sylhist = R.takeLast(3, R.append(syllables(messageContent), sylhist))
mhist = R.takeLast(50, R.append(messageContent, mhist))
if (R.equals(sylhist, [5, 7, 5])) {
client.say(channel, "haiku detected!")
logEv("haiku", R.takeLast(3, mhist).join("\n"))
}
console.log(sylhist)
})
client.addListener("raw", ev => {
if (ev.command === "rpl_links") {
links.push(ev.args)
} else if (ev.command === "rpl_endoflinks" && linksResolve) {
linksResolve.forEach(r => r(links))
linksResolve = null
links = []
}
})