mirror of
https://github.com/muerwre/vk-tg-bot.git
synced 2025-04-25 06:56:40 +07:00
added vk events handler stub
This commit is contained in:
parent
dfae42c197
commit
3f908da91e
11 changed files with 125 additions and 67 deletions
|
@ -1,13 +1,17 @@
|
||||||
http:
|
http:
|
||||||
port: 3002
|
port: 3002
|
||||||
telegram:
|
telegram:
|
||||||
|
# Get it from bot father
|
||||||
key: ''
|
key: ''
|
||||||
webhook:
|
webhook:
|
||||||
url: https://something.org:65534/webhook
|
url: https://something.org:3002/webhook
|
||||||
enabled: false
|
enabled: false
|
||||||
logger:
|
logger:
|
||||||
level: info
|
level: info
|
||||||
#vk:
|
vk:
|
||||||
|
# Default path for POST requests from VK api
|
||||||
|
endpoint: /
|
||||||
|
groups: []
|
||||||
# groups:
|
# groups:
|
||||||
# - id: 0
|
# - id: 0
|
||||||
# name: 'Group name'
|
# name: 'Group name'
|
||||||
|
|
|
@ -6,19 +6,21 @@ import loggerHttpMiddleware from "../../service/logger/http";
|
||||||
import logger from "../../service/logger";
|
import logger from "../../service/logger";
|
||||||
import { TelegramService } from "../../service/telegram";
|
import { TelegramService } from "../../service/telegram";
|
||||||
import http from "http";
|
import http from "http";
|
||||||
import { WebhookConfig } from "../../config/types";
|
|
||||||
import { URL } from "url";
|
import { URL } from "url";
|
||||||
import { corsMiddleware, errorMiddleware } from "./middleware";
|
import { corsMiddleware, errorMiddleware } from "./middleware";
|
||||||
|
import { WebhookConfig } from "../../service/telegram/types";
|
||||||
|
|
||||||
export class HttpApi {
|
export class HttpApi {
|
||||||
app: Express;
|
app: Express;
|
||||||
|
webhook: WebhookConfig;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private props: HttpConfig,
|
private props: HttpConfig,
|
||||||
private telegram: TelegramService,
|
private telegram: TelegramService,
|
||||||
private vk: VkService,
|
private vk: VkService
|
||||||
private webhook?: WebhookConfig
|
|
||||||
) {
|
) {
|
||||||
|
this.webhook = this.telegram.webhook;
|
||||||
|
|
||||||
this.app = express();
|
this.app = express();
|
||||||
this.app.use(corsMiddleware);
|
this.app.use(corsMiddleware);
|
||||||
this.app.use(express.json());
|
this.app.use(express.json());
|
||||||
|
@ -28,11 +30,7 @@ export class HttpApi {
|
||||||
this.app.use(bodyParser.json());
|
this.app.use(bodyParser.json());
|
||||||
this.app.use(express.json());
|
this.app.use(express.json());
|
||||||
|
|
||||||
if (this?.webhook?.enabled && this?.webhook?.url) {
|
this.setupHandlers();
|
||||||
const url = new URL(this.webhook.url);
|
|
||||||
logger.info(`using webhook at ${url.pathname}`);
|
|
||||||
this.app.post(url.pathname, this.handleWebhook);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.app.use(errorMiddleware);
|
this.app.use(errorMiddleware);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +44,21 @@ export class HttpApi {
|
||||||
logger.info(`http api listening at ${this.props.port}`);
|
logger.info(`http api listening at ${this.props.port}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds webhandlers
|
||||||
|
*/
|
||||||
|
private setupHandlers() {
|
||||||
|
// Webhooks (if available)
|
||||||
|
if (this?.webhook?.enabled && this?.webhook?.url) {
|
||||||
|
const url = new URL(this.webhook.url);
|
||||||
|
logger.info(`using webhook at ${url.pathname}`);
|
||||||
|
this.app.post(url.pathname, this.handleWebhook);
|
||||||
|
this.app.get(url.pathname, this.testWebhook);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.app.post(this.vk.endpoint, this.handleVkEvent);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles telegram webhooks
|
* Handles telegram webhooks
|
||||||
*/
|
*/
|
||||||
|
@ -53,4 +66,19 @@ export class HttpApi {
|
||||||
logger.debug("got message via webhook", req.body);
|
logger.debug("got message via webhook", req.body);
|
||||||
await this.telegram.handleUpdate(req.body, res);
|
await this.telegram.handleUpdate(req.body, res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just returns 200
|
||||||
|
*/
|
||||||
|
private testWebhook = async (req: Request, res: Response) => {
|
||||||
|
res.sendStatus(200);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles VK events
|
||||||
|
*/
|
||||||
|
private handleVkEvent = async (req: Request, res: Response) => {
|
||||||
|
await this.vk.handle(req.body);
|
||||||
|
res.sendStatus(200);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,9 @@ import { VkConfig } from "../service/vk/types";
|
||||||
import { HttpConfig } from "../api/http/types";
|
import { HttpConfig } from "../api/http/types";
|
||||||
import { LoggerConfig } from "../service/logger/types";
|
import { LoggerConfig } from "../service/logger/types";
|
||||||
|
|
||||||
export interface WebhookConfig {
|
|
||||||
url?: string;
|
|
||||||
enabled?: boolean;
|
|
||||||
}
|
|
||||||
export interface Config extends Record<string, any> {
|
export interface Config extends Record<string, any> {
|
||||||
http: HttpConfig;
|
http: HttpConfig;
|
||||||
telegram: TelegramConfig;
|
telegram: TelegramConfig;
|
||||||
vk: VkConfig;
|
vk: VkConfig;
|
||||||
logger?: LoggerConfig;
|
logger?: LoggerConfig;
|
||||||
webhook?: WebhookConfig;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,11 @@ import { vkConfigSchema } from "../service/vk/validation";
|
||||||
import { telegramConfigSchema } from "../service/telegram/validation";
|
import { telegramConfigSchema } from "../service/telegram/validation";
|
||||||
import { loggerConfigSchema } from "../service/logger/config";
|
import { loggerConfigSchema } from "../service/logger/config";
|
||||||
|
|
||||||
const webhookValidationSchema = object().optional().shape({
|
|
||||||
url: string(),
|
|
||||||
enabled: boolean(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const configSchema = object<Config>().required().shape({
|
const configSchema = object<Config>().required().shape({
|
||||||
http: httpConfigSchema,
|
http: httpConfigSchema,
|
||||||
vk: vkConfigSchema,
|
vk: vkConfigSchema,
|
||||||
telegram: telegramConfigSchema,
|
telegram: telegramConfigSchema,
|
||||||
logger: loggerConfigSchema,
|
logger: loggerConfigSchema,
|
||||||
webhook: webhookValidationSchema,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const validateConfig = (config: Config) =>
|
export const validateConfig = (config: Config) =>
|
||||||
|
|
|
@ -8,18 +8,13 @@ import { HttpApi } from "./api/http";
|
||||||
async function main() {
|
async function main() {
|
||||||
try {
|
try {
|
||||||
const config = prepareConfig();
|
const config = prepareConfig();
|
||||||
const telegram = new TelegramService(config.telegram, config.webhook);
|
const telegram = new TelegramService(config.telegram);
|
||||||
const vkService = new VkService(config.vk);
|
const vkService = new VkService(config.vk);
|
||||||
|
|
||||||
const telegramApi = new TelegramApi(telegram).listen();
|
const telegramApi = new TelegramApi(telegram).listen();
|
||||||
await telegram.start();
|
await telegram.start();
|
||||||
|
|
||||||
const httpApi = new HttpApi(
|
const httpApi = new HttpApi(config.http, telegram, vkService).listen();
|
||||||
config.http,
|
|
||||||
telegram,
|
|
||||||
vkService,
|
|
||||||
config.webhook
|
|
||||||
).listen();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e.message);
|
logger.error(e.message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { TelegramConfig } from "./types";
|
import { TelegramConfig, WebhookConfig } from "./types";
|
||||||
import { Telegraf } from "telegraf";
|
import { Telegraf } from "telegraf";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
import { Response } from "express";
|
import { Response } from "express";
|
||||||
import { Update } from "typegram";
|
import { Update } from "typegram";
|
||||||
import loggerTgMiddleware from "../logger/tg";
|
import loggerTgMiddleware from "../logger/tg";
|
||||||
import { WebhookConfig } from "../../config/types";
|
|
||||||
|
|
||||||
// import SocksProxyAgent from 'socks-proxy-agent';
|
// import SocksProxyAgent from 'socks-proxy-agent';
|
||||||
|
|
||||||
export class TelegramService {
|
export class TelegramService {
|
||||||
public readonly bot: Telegraf;
|
public readonly bot: Telegraf;
|
||||||
|
public readonly webhook: WebhookConfig = {};
|
||||||
|
|
||||||
constructor(private props: TelegramConfig, private webhook: WebhookConfig) {
|
constructor(private props: TelegramConfig) {
|
||||||
// const agent = (CONFIG.PROXY && new SocksProxyAgent(CONFIG.PROXY)) || null;
|
// const agent = (CONFIG.PROXY && new SocksProxyAgent(CONFIG.PROXY)) || null;
|
||||||
const options: Partial<Telegraf.Options<any>> = {
|
const options: Partial<Telegraf.Options<any>> = {
|
||||||
telegram: {
|
telegram: {
|
||||||
|
@ -21,6 +21,8 @@ export class TelegramService {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.webhook = props.webhook;
|
||||||
|
|
||||||
this.bot = new Telegraf(props.key, options);
|
this.bot = new Telegraf(props.key, options);
|
||||||
this.bot.use(loggerTgMiddleware);
|
this.bot.use(loggerTgMiddleware);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
export interface WebhookConfig {
|
||||||
|
url?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TelegramConfig {
|
export interface TelegramConfig {
|
||||||
key: string;
|
key: string;
|
||||||
|
webhook: WebhookConfig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
|
import { boolean, object, string } from "yup";
|
||||||
|
|
||||||
|
const webhookValidationSchema = object().optional().shape({
|
||||||
|
url: string(),
|
||||||
|
enabled: boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
export const telegramConfigSchema = yup.object().required().shape({
|
export const telegramConfigSchema = yup.object().required().shape({
|
||||||
key: yup.string().required(),
|
key: yup.string().required(),
|
||||||
|
webhook: webhookValidationSchema,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
import { VkConfig } from './types';
|
import { VkConfig } from "./types";
|
||||||
|
|
||||||
export class VkService {
|
export class VkService {
|
||||||
|
public endpoint: string = "/";
|
||||||
|
|
||||||
constructor(private config: VkConfig) {
|
constructor(private config: VkConfig) {
|
||||||
if (!config.groups.length) {
|
if (!config.groups.length) {
|
||||||
throw new Error('No vk groups to handle. Specify them in config')
|
throw new Error("No vk groups to handle. Specify them in config");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.endpoint = config.endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles incoming VK events
|
||||||
|
*/
|
||||||
|
public handle = async (event: any) => {
|
||||||
|
// TODO: handle events
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
export interface VkConfig extends Record<string, any> {
|
export interface VkConfig extends Record<string, any> {
|
||||||
groups: ConfigGroup[]
|
groups: ConfigGroup[];
|
||||||
|
endpoint?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConfigGroup {
|
interface ConfigGroup {
|
||||||
id: number
|
id: number;
|
||||||
name: string
|
name: string;
|
||||||
testResponse: string
|
testResponse: string;
|
||||||
secretKey: string
|
secretKey: string;
|
||||||
apiKey: string
|
apiKey: string;
|
||||||
channels: GroupChannel[]
|
channels: GroupChannel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GroupChannel {
|
interface GroupChannel {
|
||||||
id: string,
|
id: string;
|
||||||
events: VkEvent[]
|
events: VkEvent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum VkEvent {
|
export enum VkEvent {
|
||||||
Confirmation = 'confirmation',
|
Confirmation = "confirmation",
|
||||||
WallPostNew = 'wall_post_new',
|
WallPostNew = "wall_post_new",
|
||||||
PostSuggestion = 'post_suggestion',
|
PostSuggestion = "post_suggestion",
|
||||||
GroupJoin = 'group_join',
|
GroupJoin = "group_join",
|
||||||
GroupLeave = 'group_leave',
|
GroupLeave = "group_leave",
|
||||||
MessageNew = 'message_new',
|
MessageNew = "message_new",
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,35 @@
|
||||||
import * as yup from 'yup'
|
import * as yup from "yup";
|
||||||
import { VkConfig, VkEvent } from './types';
|
import { VkConfig, VkEvent } from "./types";
|
||||||
|
|
||||||
const vkChannelEventSchema = yup.string().oneOf(Object.values(VkEvent))
|
const vkChannelEventSchema = yup.string().oneOf(Object.values(VkEvent));
|
||||||
|
|
||||||
const vkChannelSchema = yup.object().required().shape({
|
const vkChannelSchema = yup
|
||||||
id: yup.string().required().matches(/^@/, ({ path }) => `${path} should start with "@"`),
|
.object()
|
||||||
events: yup.array().of(vkChannelEventSchema)
|
.required()
|
||||||
})
|
.shape({
|
||||||
|
id: yup
|
||||||
|
.string()
|
||||||
|
.required()
|
||||||
|
.matches(/^@/, ({ path }) => `${path} should start with "@"`),
|
||||||
|
events: yup.array().of(vkChannelEventSchema),
|
||||||
|
});
|
||||||
|
|
||||||
export const vkConfigSchema = yup.object<VkConfig>().required().shape({
|
export const vkConfigSchema = yup
|
||||||
groups: yup.array().required().of(yup.object().shape({
|
.object<VkConfig>()
|
||||||
id: yup.number().positive(),
|
.required()
|
||||||
name: yup.string().required(),
|
.shape({
|
||||||
testResponse: yup.string().required(),
|
endpoint: yup.string().optional(),
|
||||||
secretKey: yup.string().required(),
|
groups: yup
|
||||||
apiKey: yup.string().required(),
|
.array()
|
||||||
channels: yup.array().of(vkChannelSchema),
|
.required()
|
||||||
}))
|
.of(
|
||||||
})
|
yup.object().shape({
|
||||||
|
id: yup.number().positive(),
|
||||||
|
name: yup.string().required(),
|
||||||
|
testResponse: yup.string().required(),
|
||||||
|
secretKey: yup.string().required(),
|
||||||
|
apiKey: yup.string().required(),
|
||||||
|
channels: yup.array().of(vkChannelSchema),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue