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:
parent
6230217741
commit
2a08ec9f86
3 changed files with 150 additions and 2 deletions
107
src/commands/roll.ts
Normal file
107
src/commands/roll.ts
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
|
@ -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}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue