mirror of
https://github.com/muerwre/vk-tg-bot.git
synced 2025-04-25 15:06:41 +07:00
added http and telegram api services
This commit is contained in:
parent
5453e884c6
commit
9433cc327a
18 changed files with 687 additions and 70 deletions
|
@ -0,0 +1,59 @@
|
|||
import { HttpConfig } from "./types";
|
||||
import { VkService } from "../../service/vk";
|
||||
import express, { Express, Request, Response } from "express";
|
||||
import bodyParser from "body-parser";
|
||||
import loggerHttpMiddleware from "../../service/logger/http";
|
||||
import logger from "../../service/logger";
|
||||
import { TelegramService } from "../../service/telegram";
|
||||
import http from "http";
|
||||
|
||||
export class HttpApi {
|
||||
app: Express;
|
||||
|
||||
constructor(
|
||||
private props: HttpConfig,
|
||||
private telegram: TelegramService,
|
||||
private vk: VkService
|
||||
) {
|
||||
this.app = express();
|
||||
this.app.use(express.json());
|
||||
this.app.use(express.urlencoded({ extended: false }));
|
||||
this.app.use((req, res, next) => {
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
res.header(
|
||||
"Access-Control-Allow-Methods",
|
||||
"GET, PUT, POST, DELETE, PATCH"
|
||||
);
|
||||
res.header(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Origin, X-Requested-With, Content-Type, Accept"
|
||||
);
|
||||
next();
|
||||
});
|
||||
this.app.use(loggerHttpMiddleware);
|
||||
|
||||
this.app.use(bodyParser.json());
|
||||
this.app.use(express.json());
|
||||
|
||||
if (props?.webhook?.enabled && props?.webhook?.url) {
|
||||
logger.info(`using webhook at ${props.webhook.url}`);
|
||||
this.app.post(props.webhook.url, this.handleWebhook);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts http server
|
||||
*/
|
||||
public async listen() {
|
||||
const httpServer = http.createServer(this.app);
|
||||
httpServer.listen(this.props.port);
|
||||
logger.info(`http api listening at ${this.props.port}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles telegram webhooks
|
||||
*/
|
||||
private async handleWebhook(req: Request, res: Response) {
|
||||
return this.telegram.handleUpdate(req.body, res);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
export interface HttpConfig extends Record<string, any> {
|
||||
port: number
|
||||
port: number;
|
||||
webhook?: {
|
||||
url?: string;
|
||||
enabled?: boolean;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import { number, object } from 'yup'
|
||||
import { boolean, number, object, string } from "yup";
|
||||
|
||||
export const httpConfigSchema = object().required().shape({
|
||||
port: number().defined().required().positive(),
|
||||
})
|
||||
export const httpConfigSchema = object()
|
||||
.required()
|
||||
.shape({
|
||||
port: number().defined().required().positive(),
|
||||
webhook: object().optional().shape({
|
||||
url: string(),
|
||||
enabled: boolean(),
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { TelegramService } from "../../service/telegram";
|
||||
import logger from "../../service/logger";
|
||||
|
||||
export class TelegramApi {
|
||||
constructor(private telegram: TelegramService) {}
|
||||
|
||||
public listen() {
|
||||
this.telegram.bot.command("ping", TelegramApi.ping);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles ping command
|
||||
*/
|
||||
private static ping(ctx) {
|
||||
return ctx.replyWithSticker(
|
||||
"CAACAgIAAxkBAAIB6F82KSeJBEFer895bb7mFI7_GzYoAAISAAOwODIrOXeFNb5v4aEaBA"
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,20 +1,23 @@
|
|||
import yaml from 'js-yaml'
|
||||
import fs from 'fs'
|
||||
import path from 'path';
|
||||
import { Config } from './types';
|
||||
import { mergeRight } from 'ramda';
|
||||
import { validateConfig } from './validate';
|
||||
import logger from '../service/logger';
|
||||
import { getCmdArg } from '../utils/args';
|
||||
import yaml from "js-yaml";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { Config } from "./types";
|
||||
import { mergeRight } from "ramda";
|
||||
import { validateConfig } from "./validate";
|
||||
import { getCmdArg } from "../utils/args";
|
||||
|
||||
const configPath = getCmdArg('config')
|
||||
const defaultConfig = yaml.load<Config>(fs.readFileSync(path.join(__dirname, '../config.example.yml'), 'utf8'));
|
||||
const userConfig = yaml.load<Config>(fs.readFileSync(configPath || path.join(__dirname, '../config.yml'), 'utf8'));
|
||||
const configPath = getCmdArg("config");
|
||||
const defaultConfig = yaml.load<Config>(
|
||||
fs.readFileSync(path.join(__dirname, "../config.example.yml"), "utf8")
|
||||
);
|
||||
const userConfig = yaml.load<Config>(
|
||||
fs.readFileSync(configPath || path.join(__dirname, "../config.yml"), "utf8")
|
||||
);
|
||||
|
||||
const config = userConfig && mergeRight(defaultConfig, userConfig) || defaultConfig
|
||||
const config =
|
||||
(userConfig && mergeRight(defaultConfig, userConfig)) || defaultConfig;
|
||||
|
||||
export default function prepareConfig() {
|
||||
validateConfig(config)
|
||||
logger.debug('config is ok: ', config)
|
||||
return config
|
||||
validateConfig(config);
|
||||
return config;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { TelegramConfig } from '../service/telegram/types';
|
||||
import { VkConfig } from '../service/vk/types';
|
||||
import { HttpConfig } from '../api/http/types';
|
||||
import { TelegramConfig } from "../service/telegram/types";
|
||||
import { VkConfig } from "../service/vk/types";
|
||||
import { HttpConfig } from "../api/http/types";
|
||||
import { LoggerConfig } from "../service/logger/types";
|
||||
|
||||
export interface Config extends Record<string, any>{
|
||||
http: HttpConfig
|
||||
telegram: TelegramConfig
|
||||
vk: VkConfig
|
||||
export interface Config extends Record<string, any> {
|
||||
http: HttpConfig;
|
||||
telegram: TelegramConfig;
|
||||
vk: VkConfig;
|
||||
logger?: LoggerConfig;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { object } from 'yup'
|
||||
import { httpConfigSchema } from '../api/http/validation';
|
||||
import { Config } from './types';
|
||||
import { vkConfigSchema } from '../service/vk/validation';
|
||||
import { telegramConfigSchema } from '../service/telegram/validation';
|
||||
import { object } from "yup";
|
||||
import { httpConfigSchema } from "../api/http/validation";
|
||||
import { Config } from "./types";
|
||||
import { vkConfigSchema } from "../service/vk/validation";
|
||||
import { telegramConfigSchema } from "../service/telegram/validation";
|
||||
import { loggerConfigSchema } from "../service/logger/config";
|
||||
|
||||
const configSchema = object<Config>().required().shape({
|
||||
http: httpConfigSchema,
|
||||
vk: vkConfigSchema,
|
||||
telegram: telegramConfigSchema,
|
||||
})
|
||||
logger: loggerConfigSchema,
|
||||
});
|
||||
|
||||
export const validateConfig = (config: Config) => configSchema.validateSync(config)
|
||||
export const validateConfig = (config: Config) =>
|
||||
configSchema.validateSync(config);
|
||||
|
|
30
src/index.ts
30
src/index.ts
|
@ -1,13 +1,23 @@
|
|||
import prepareConfig from './config';
|
||||
import { TelegramService } from './service/telegram';
|
||||
import logger from './service/logger';
|
||||
import { VkService } from './service/vk';
|
||||
import prepareConfig from "./config";
|
||||
import { TelegramService } from "./service/telegram";
|
||||
import logger from "./service/logger";
|
||||
import { VkService } from "./service/vk";
|
||||
import { TelegramApi } from "./api/telegram";
|
||||
import { HttpApi } from "./api/http";
|
||||
|
||||
try {
|
||||
const config = prepareConfig()
|
||||
const telegramService = new TelegramService(config.telegram).start()
|
||||
const vkService = new VkService(config.vk)
|
||||
async function main() {
|
||||
try {
|
||||
const config = prepareConfig();
|
||||
const telegram = new TelegramService(config.telegram);
|
||||
const vkService = new VkService(config.vk);
|
||||
|
||||
} catch (e) {
|
||||
logger.error(e.message)
|
||||
const telegramApi = new TelegramApi(telegram).listen();
|
||||
await telegram.start();
|
||||
|
||||
const httpApi = new HttpApi(config.http, telegram, vkService).listen();
|
||||
} catch (e) {
|
||||
logger.error(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
5
src/service/logger/config.ts
Normal file
5
src/service/logger/config.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { object, string } from "yup";
|
||||
|
||||
export const loggerConfigSchema = object().shape({
|
||||
level: string().optional().oneOf(["debug", "info", "warn", "error"]),
|
||||
});
|
19
src/service/logger/http.ts
Normal file
19
src/service/logger/http.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import morgan, { StreamOptions } from "morgan";
|
||||
import logger from "./index";
|
||||
|
||||
const stream: StreamOptions = {
|
||||
write: (message) => logger.http(message),
|
||||
};
|
||||
|
||||
const skip = () => {
|
||||
const env = process.env.NODE_ENV || "development";
|
||||
return env !== "development";
|
||||
};
|
||||
|
||||
// Build the morgan middleware
|
||||
const loggerHttpMiddleware = morgan(
|
||||
":method :url :status :res[content-length] - :response-time ms",
|
||||
{ stream, skip }
|
||||
);
|
||||
|
||||
export default loggerHttpMiddleware;
|
|
@ -1,7 +1,13 @@
|
|||
import { createLogger, format, transports } from 'winston';
|
||||
import { createLogger, format, transports } from "winston";
|
||||
import prepareConfig from "../../config";
|
||||
|
||||
const config = prepareConfig();
|
||||
|
||||
const logger = createLogger({
|
||||
transports: new transports.Console({ format: format.simple() })
|
||||
})
|
||||
transports: new transports.Console({
|
||||
format: format.simple(),
|
||||
level: config.logger.level || "info",
|
||||
}),
|
||||
});
|
||||
|
||||
export default logger
|
||||
export default logger;
|
||||
|
|
11
src/service/logger/tg.ts
Normal file
11
src/service/logger/tg.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { MiddlewareFn } from "telegraf";
|
||||
import logger from "./index";
|
||||
|
||||
const loggerTgMiddleware: MiddlewareFn<any> = async (ctx, next) => {
|
||||
logger.debug(
|
||||
`received tg message from @${ctx.message.from.username}: ${ctx.message.text}`
|
||||
);
|
||||
await next().catch(logger.warn);
|
||||
};
|
||||
|
||||
export default loggerTgMiddleware;
|
3
src/service/logger/types.ts
Normal file
3
src/service/logger/types.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export interface LoggerConfig {
|
||||
level?: "debug" | "info" | "warn" | "error";
|
||||
}
|
|
@ -1,17 +1,16 @@
|
|||
import { TelegramConfig } from './types';
|
||||
import { Telegraf } from 'telegraf';
|
||||
import logger from '../logger';
|
||||
import { TelegramConfig } from "./types";
|
||||
import { Telegraf } from "telegraf";
|
||||
import logger from "../logger";
|
||||
import { Response } from "express";
|
||||
import { Update } from "typegram";
|
||||
import loggerTgMiddleware from "../logger/tg";
|
||||
|
||||
// import SocksProxyAgent from 'socks-proxy-agent';
|
||||
|
||||
export class TelegramService {
|
||||
bot: Telegraf
|
||||
public readonly bot: Telegraf;
|
||||
|
||||
constructor(private props: TelegramConfig) {
|
||||
if (!props.key) {
|
||||
throw new Error('Telegram api key not found. Get it from bot father')
|
||||
}
|
||||
|
||||
// const agent = (CONFIG.PROXY && new SocksProxyAgent(CONFIG.PROXY)) || null;
|
||||
const options = {
|
||||
channelMode: true,
|
||||
|
@ -22,18 +21,28 @@ export class TelegramService {
|
|||
};
|
||||
|
||||
this.bot = new Telegraf(props.key, options);
|
||||
this.bot.use(loggerTgMiddleware);
|
||||
|
||||
process.once('SIGINT', () => this.bot.stop('SIGINT'))
|
||||
process.once('SIGTERM', () => this.bot.stop('SIGTERM'))
|
||||
|
||||
logger.info('Telegram service started')
|
||||
process.once("SIGINT", () => this.bot.stop("SIGINT"));
|
||||
process.once("SIGTERM", () => this.bot.stop("SIGTERM"));
|
||||
}
|
||||
|
||||
start() {
|
||||
if (!this.bot) {
|
||||
throw new Error('Not initialized')
|
||||
}
|
||||
/**
|
||||
* Connects to telegram
|
||||
*/
|
||||
public async start() {
|
||||
await this.bot.telegram.deleteWebhook().then(
|
||||
() => this.bot.launch(),
|
||||
() => this.bot.launch()
|
||||
);
|
||||
|
||||
return this.bot.launch()
|
||||
logger.info("telegram service started");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles webhook updates
|
||||
*/
|
||||
public async handleUpdate(req: Update, res: Response) {
|
||||
return this.bot.handleUpdate(req, res);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue