Created
April 3, 2022 20:44
-
-
Save artalar/41cd6333da03aa10c87e641ee696381a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as t from 'runtypes' | |
export const oneMillisecond = 1 | |
export const oneSecond = oneMillisecond * 1000 | |
export const oneMinute = oneSecond * 60 | |
export const oneHour = oneMinute * 60 | |
export const oneDay = oneHour * 24 | |
/** 30 messages per second for all users | |
* and one message per second for one user | |
*/ | |
export const TLG_MESSAGE_LIMIT = oneSecond / 30 | |
export const TELEGRAM_API_BASE_URL = 'https://api.telegram.org' | |
export const commands = { | |
auth: `auth`, | |
info: `info`, | |
} as const | |
export const CallbackData = t.Record({ | |
kind: t.Union( | |
t.Literal(commands.auth), | |
t.Literal(commands.info), | |
), | |
data: t.Unknown, | |
}) | |
export type CallbackData = t.Static<typeof CallbackData> | |
export function createCallbackButton<T>( | |
kind: string, | |
text: string | number, | |
data: T, | |
) { | |
return { | |
text: text.toString(), | |
callback_data: JSON.stringify({ | |
kind, | |
data, | |
}), | |
} | |
} | |
export function readCallbackQuery<T>( | |
kind: keyof typeof commands, | |
callback_query: any, | |
): (CallbackData & { data: T }) | null { | |
if (typeof callback_query !== 'string') return null | |
const payload = JSON.parse(callback_query) | |
return CallbackData.withConstraint((data) => data.kind === kind).guard( | |
payload, | |
) | |
? (payload as any) | |
: null | |
} | |
export function guardCallbackQuery( | |
kind: keyof typeof commands, | |
callback_query: any, | |
): boolean { | |
return CallbackData.withConstraint((data) => data.kind === kind).guard( | |
JSON.parse(callback_query), | |
) | |
} | |
export const deleteButton = createCallbackButton( | |
commands.delete_message, | |
`Удалить`, | |
null, | |
) | |
export const deleteButtonReply = { | |
reply_markup: { | |
inline_keyboard: [[deleteButton]], | |
}, | |
} | |
if (process.env.NODE_ENV === 'development') { | |
const dotenv = require('dotenv') | |
const path = require('path') | |
dotenv.config({ | |
path: path.join(__dirname, '..', '..', `.env.local`), | |
}) | |
} | |
if (typeof process.env.API_TOKEN !== 'string') { | |
console.error('API token is not passed') | |
process.exit() | |
} | |
if (typeof process.env.BOT_TOKEN !== 'string') { | |
console.error('Bot token is not passed') | |
process.exit() | |
} | |
export const { | |
API_TOKEN, | |
BOT_TOKEN, | |
} = process.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function formatUserName({ | |
id, | |
username, | |
first_name, | |
}: { | |
id: number | string | |
username?: string | |
first_name?: string | |
}) { | |
return `<a href="tg://user?id=${id}">${username || first_name}</a>` | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Context } from 'telegraf' | |
import { APIService } from '../services/APIService' | |
import { | |
isDevUser, | |
isGroupMessage, | |
isDirectMessage, | |
} from '../types' | |
import { TLG_MESSAGE_LIMIT } from './const' | |
import { sleep } from './dates' | |
import { Fn } from './types' | |
export function forDevs< | |
F extends (ctx: Context, next?: Function) => any | |
>(api: APIService, cb: F) { | |
return async (ctx: Context, next?: Function) => { | |
if (ctx.message?.from && isDevUser(await api.getUser(ctx.message.from))) { | |
await cb(ctx) | |
} | |
return next?.() | |
} | |
} | |
export function forGroupMessage< | |
F extends (ctx: Context, next?: Function) => any | |
>(cb: F) { | |
return async (ctx: Context, next?: Function) => { | |
if (isGroupMessage(ctx)) { | |
await cb(ctx) | |
} | |
return next?.() | |
} | |
} | |
export function forDirectMessage(cb: Fn<[Context, Function?], any>) { | |
return async (ctx: Context, next?: Function) => { | |
if (isDirectMessage(ctx)) { | |
await cb(ctx) | |
} | |
return next?.() | |
} | |
} | |
/** | |
* | |
* @param percent from 0 to 100 | |
*/ | |
export function chanceGuard(percent: number) { | |
return percent / 100 > Math.random() | |
} | |
let lastLock = Date.now() | |
export function freeMsgLimit() { | |
const now = Date.now() | |
lastLock = Math.max(lastLock + TLG_MESSAGE_LIMIT, now) | |
const delay = lastLock - now | |
return sleep(delay) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Context } from 'telegraf' | |
import { log } from './log' | |
import { Fn } from './types' | |
export const handleError = Object.assign( | |
function handleError<T extends any[]>(cb: Fn<T, any>): Fn<T, any> { | |
return async (...a: T) => | |
Promise.all([ | |
new Promise((r) => r(cb(...a))).catch((error) => { | |
const errorMsg = `Error (${cb.name || `anonymous fn`}):` | |
const errorData = errorify(error) | |
log(errorMsg, errorData) | |
if (a[0] instanceof Context) { | |
a[0].reply(`${errorMsg}\n${JSON.stringify(errorData, null, 2)}`) | |
} | |
return error | |
}), | |
a[0] instanceof Context && typeof a[1] === 'function' && a[1](), | |
]) | |
}, | |
{ | |
voided: <T extends any[]>(cb: Fn<T, Promise<any>>): Fn<T, void> => { | |
const fn = handleError(cb) | |
return (...a) => void fn(...a) | |
}, | |
}, | |
) | |
export function errorify(thing: any) { | |
const error = thing instanceof Error ? thing : new Error(thing) | |
return { message: error.message, stack: error.stack, data: thing } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment