1
0
Fork 0
mirror of https://github.com/muerwre/vk-tg-bot.git synced 2025-04-25 15:06:41 +07:00

add roll command

This commit is contained in:
Fedor Katurov 2023-12-30 17:02:36 +07:00
parent 6230217741
commit 2a08ec9f86
3 changed files with 150 additions and 2 deletions

107
src/commands/roll.ts Normal file
View file

@ -0,0 +1,107 @@
import axios from "axios";
interface RollResult {
distance: number;
id: string;
title: string;
}
const url = `https://backend-map.vault48.org/api/route/random`;
const successMessages = [
"Вот маршрут для тебя: {link}, {dist}км",
"Ну вот есть, например, {link}, всего {dist}км",
"Нашёл {link}, всего {dist}км, надо ехать",
"Вот, {link}, всего {dist}км, катал его, нет?",
];
const failureMessages = [
"Ничего не нашёл 🤷",
"Не, такого нет, попробуй снова",
"Может, что-то и было такое, но сейчас я не ничего не нашёл.",
];
const say = (vals: string[]) =>
vals[Math.floor(Math.random() * (vals.length - 1))];
const parseVal = (val?: string) => {
const parsed = val && parseInt(val, 10);
if (!parsed || !Number.isFinite(parsed) || parsed <= 0 || parsed >= 10000) {
return;
}
return parsed;
};
const escape = (val?: string) => val && val.replace(/([-.\[\]])/g, "\\$1");
const deviate = (max: number, factor: number) => [
Math.round(max * (1 - factor)),
Math.round(max * (1 + factor)),
];
// begin search in range of 80%-120% of specified distance
const startDeviation = 0.2;
// add 10% each time we haven't found anything
const deviationStep = 0.1;
// perform this amount of tries, increasing deviation each time we haven't found anything
const deviationTries = 8;
const getRoute = async (
min?: number,
max?: number
): Promise<RollResult | undefined> => {
if (!min && !max) {
return axios.get<RollResult>(url).then((it) => it.data);
}
if (min && max && min > max) {
return axios
.get<RollResult>(url, { params: { min: max, max: min } })
.then((it) => it.data);
}
if (min && max) {
return axios
.get<RollResult>(url, { params: { min, max } })
.then((it) => it.data);
}
if (!min) {
return;
}
for (let i = 0; i < deviationTries; i += 1) {
const deviation = startDeviation + deviationStep * i;
let [devMin, devMax] = deviate(min, deviation);
try {
return await axios
.get<RollResult>(url, { params: { min: devMin, max: devMax } })
.then((it) => it.data)
.catch();
} catch (error) {}
}
};
export const roll = async (text: string) => {
try {
const parts = text.trim().split(" ");
const result = await getRoute(parseVal(parts[1]), parseVal(parts[2]));
if (!result || !result?.id) {
return say(failureMessages);
}
const link = `https://map.vault48.org/${result.id}`;
const distance = result.distance.toFixed(0);
const message = say(successMessages);
return message
.replace("{dist}", distance)
.replace("{link}", `[${escape(result.title ?? link)}](${escape(link)})`);
} catch (error) {
console.warn("Error, when trying to fetch random route", error);
}
};

View file

@ -6,6 +6,7 @@ import { TelegramApi } from "./api/telegram";
import { HttpApi } from "./api/http"; import { HttpApi } from "./api/http";
import { PostgresDB } from "./service/db/postgres"; import { PostgresDB } from "./service/db/postgres";
import { PgTransport } from "./service/db/postgres/loggerTransport"; import { PgTransport } from "./service/db/postgres/loggerTransport";
import { roll } from "./commands/roll";
async function main() { async function main() {
try { try {
@ -29,9 +30,11 @@ async function main() {
await httpApi.listen(); await httpApi.listen();
await telegramApi.probe(); await telegramApi.probe();
telegram.hears(/\/roll(.*)/, roll);
logger.info("bot successfully started"); logger.info("bot successfully started");
} catch (e) { } catch (e) {
logger.error(`FATAL EXCEPTION ${e.message}`); logger.error(`FATAL EXCEPTION ${e}`);
} }
} }

View file

@ -8,6 +8,8 @@ import { ExtraReplyMessage } from "telegraf/typings/telegram-types";
// import SocksProxyAgent from 'socks-proxy-agent'; // import SocksProxyAgent from 'socks-proxy-agent';
const maxMessageAge = 3 * 60e3; // skip messages older than this seconds
export class TelegramService { export class TelegramService {
public readonly bot: Telegraf; public readonly bot: Telegraf;
public readonly webhook: WebhookConfig = {}; public readonly webhook: WebhookConfig = {};
@ -18,7 +20,7 @@ export class TelegramService {
telegram: { telegram: {
webhookReply: true, webhookReply: true,
apiMode: "bot", apiMode: "bot",
// agent, // TODO: add proxy support // agent, // TODO: add proxy support if they block it
}, },
}; };
@ -158,4 +160,40 @@ export class TelegramService {
!!username && !!this.props.owners && this.props.owners.includes(username) !!username && !!this.props.owners && this.props.owners.includes(username)
); );
}; };
public hears = (
what: string | RegExp,
callback: (
text: string
) => string | Promise<string | undefined> | undefined | void
) =>
this.bot.hears(what, async (ctx) => {
let text: string | void | undefined = "%% not received %%";
try {
const age = Date.now() - ctx.message.date * 1000;
const message = ctx.update.message.text;
if (age > maxMessageAge) {
console.warn(
`skipped message "${message}", since its age ${age / 1000} seconds`
);
return;
}
text = await callback(message);
if (!text) {
return;
}
ctx.reply(text, { parse_mode: "MarkdownV2" });
} catch (error) {
console.warn(
`error replying to ${what} (${ctx.update.message.text}) with message "${text}"`,
error
);
}
});
} }