Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.vality.alerting.tg.bot.handler.alert;

import dev.vality.alerting.tg.bot.model.Webhook;

import java.util.List;

public interface AlertHandler {
boolean filter(String alertName);

void handle(Webhook webhook, List<Webhook.Alert> alerts);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dev.vality.alerting.tg.bot.handler.alert;

import dev.vality.alerting.tg.bot.config.properties.AlertBotProperties;
import dev.vality.alerting.tg.bot.model.Webhook;
import dev.vality.alerting.tg.bot.service.FailedMachinesAlertService;
import dev.vality.alerting.tg.bot.service.TelegramApiService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static dev.vality.alerting.tg.bot.constant.AlertThreadName.FAILED_MACHINES;
import static dev.vality.alerting.tg.bot.util.WebhookUtil.formatWebhook;

@Slf4j
@Component
@RequiredArgsConstructor
public class FailedMachinesAlertHandler implements AlertHandler {
private final AlertBotProperties properties;
private final TelegramApiService telegramApiService;
private final FailedMachinesAlertService service;

@Override
public boolean filter(String alertName) {
return FAILED_MACHINES.equals(alertName);
}

@Override
public void handle(Webhook webhook, List<Webhook.Alert> alerts) {
Map<Integer, List<Webhook.Alert>> threadIds = new HashMap<>();

for (Webhook.Alert alert : alerts) {
Integer threadId = service.getOrCreateTopicIdForFailedMachinesAlert(alert);
threadIds.computeIfAbsent(threadId, key -> new ArrayList<>()).add(alert);
}

threadIds.forEach((threadId, threadAlerts) -> {
telegramApiService.sendMessage(
properties.getChatId(),
threadId,
formatWebhook(webhook),
"MarkdownV2"
);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package dev.vality.alerting.tg.bot.handler.alert;

import dev.vality.alerting.tg.bot.config.properties.AlertBotProperties;
import dev.vality.alerting.tg.bot.model.Webhook;
import dev.vality.alerting.tg.bot.service.TelegramApiService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

import static dev.vality.alerting.tg.bot.constant.AlertThreadName.*;
import static dev.vality.alerting.tg.bot.constant.AlertThreadName.PENDING_PAYMENTS;
import static dev.vality.alerting.tg.bot.util.WebhookUtil.formatWebhook;

@Slf4j
@Component
@RequiredArgsConstructor
public class UnknownAlertHandler implements AlertHandler {
private final AlertBotProperties properties;
private final TelegramApiService telegramApiService;
private Map<String, Integer> alertThreads;

@PostConstruct
public void init() {
alertThreads = buildAlertThreadMap();
}

@Override
public boolean filter(String alertName) {
return false;
}

@Override
public void handle(Webhook webhook, List<Webhook.Alert> alerts) {
if (alerts == null || alerts.isEmpty()) {
return;
}

String alertName = alerts.get(0).getLabels() != null ? alerts.get(0).getLabels().getAlertname() : null;

Integer threadId = alertThreads.get(alertName);
if (threadId == null) {
log.error("Неизвестный тип алерта, alertName=" + alertName);
threadId = properties.getThreads().getCommands();
}

telegramApiService.sendMessage(
properties.getChatId(),
threadId,
formatWebhook(webhook),
"MarkdownV2"
);
}

private Map<String, Integer> buildAlertThreadMap() {
return Map.of(
API_ERROR_HTTP_CODE_INCREASE, properties.getThreads().getErrors5xx(),
ALT_PAY_CONVERSION, properties.getThreads().getAltpayConversion(),
FAILED_MACHINES, properties.getThreads().getFailedMachines(),
PENDING_PAYMENTS, properties.getThreads().getPendingPayments()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dev.vality.alerting.tg.bot.handler.command;

import dev.vality.alerting.tg.bot.config.properties.AlertBotProperties;
import dev.vality.alerting.tg.bot.service.CommandStateService;
import dev.vality.alerting.tg.bot.service.TelegramApiService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.objects.Update;

@Slf4j
@Component
@RequiredArgsConstructor
@Order(20)
public class CreateAlertThreadCommandHandler implements TelegramCommandHandler {

private static final String COMMAND = "/create_alert_topic";

private final AlertBotProperties properties;
private final CommandStateService commandStateService;
private final TelegramApiService telegramApiService;

@Override
public boolean filter(Update update) {
var message = update.getMessage();

Integer threadId = message.getMessageThreadId();
if (threadId == null || !threadId.equals(properties.getThreads().getCommands())) {
return false;
}

String text = message.getText();
if (text == null) {
return false;
}

return text.trim().startsWith(COMMAND);
}

@Override
public void handle(Update update) {
var message = update.getMessage();
Long chatId = message.getChatId();

commandStateService.markWaitingForNewThreadName(chatId);

telegramApiService.sendMessage(chatId, properties.getThreads().getCommands(),
"Введите название для нового треда:", null);

log.info("Create alert thread command accepted. chatId={}, user=@{}",
chatId,
message.getFrom() != null ? message.getFrom().getUserName() : null
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package dev.vality.alerting.tg.bot.handler.command;

import dev.vality.alerting.tg.bot.config.properties.AlertBotProperties;
import dev.vality.alerting.tg.bot.exception.TelegramThreadCreationException;
import dev.vality.alerting.tg.bot.service.CommandStateService;
import dev.vality.alerting.tg.bot.service.TelegramApiService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.forum.CreateForumTopic;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.generics.TelegramClient;

@Slf4j
@Component
@RequiredArgsConstructor
@Order(10)
public class EnterAlertThreadNameHandler implements TelegramCommandHandler {
private final AlertBotProperties properties;
private final CommandStateService commandStateService;
private final TelegramApiService telegramApiService;
private final TelegramClient telegramClient;

@Override
public boolean filter(Update update) {
var message = update.getMessage();

Integer threadId = message.getMessageThreadId();
if (threadId == null || !threadId.equals(properties.getThreads().getCommands())) {
return false;
}

Long chatId = message.getChatId();
if (chatId == null) {
return false;
}

return commandStateService.isWaitingForNewThreadName(chatId);
}

@Override
public void handle(Update update) {
var message = update.getMessage();
Long chatId = message.getChatId();

commandStateService.clearWaitingForNewThreadName(chatId);

String threadName = message.getText() != null ? message.getText().trim() : "";
if (threadName.isBlank()) {
telegramApiService.sendMessage(chatId, properties.getThreads().getCommands(),
"Название треда не может быть пустым. Повторите /create_alert_topic.", null);
return;
}

if (threadName.startsWith("/")) {
telegramApiService.sendMessage(chatId, properties.getThreads().getCommands(),
"Ожидалось название треда (обычный текст), а не команда. Повторите /create_alert_topic.", null);
return;
}

try {
CreateForumTopic createForumTopic = CreateForumTopic.builder()
.chatId(chatId.toString())
.name(threadName)
.build();

Integer messageThreadId = telegramClient.execute(createForumTopic).getMessageThreadId();
if (messageThreadId == null) {
throw new TelegramThreadCreationException("Telegram вернул null messageThreadId: threadName='" +
threadName + "'");
}

telegramApiService.sendMessage(chatId, properties.getThreads().getCommands(),
"✅ Тред '" + threadName + "' создан.", null);
} catch (TelegramApiException e) {
log.error("Ошибка при создании треда", e);
telegramApiService.sendMessage(chatId, properties.getThreads().getCommands(),
"❌ Ошибка при создании треда.", null);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dev.vality.alerting.tg.bot.handler.command;

import org.telegram.telegrambots.meta.api.objects.Update;

public interface TelegramCommandHandler {

boolean filter(final Update update);

void handle(Update update);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dev.vality.alerting.tg.bot.handler.command;

import dev.vality.alerting.tg.bot.config.properties.AlertBotProperties;
import dev.vality.alerting.tg.bot.service.TelegramApiService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.objects.Update;

@Slf4j
@Component
@RequiredArgsConstructor
@Order(1000)
public class UnknownCommandHandler implements TelegramCommandHandler {
private final AlertBotProperties properties;
private final TelegramApiService telegramApiService;


@Override
public boolean filter(Update update) {
var message = update.getMessage();
Integer threadId = message.getMessageThreadId();
if (threadId == null || !threadId.equals(properties.getThreads().getCommands())) {
return false;
}

String text = message.getText();
return text != null && text.trim().startsWith("/");
}

@Override
public void handle(Update update) {
var message = update.getMessage();
Long chatId = message.getChatId();

telegramApiService.sendMessage(chatId, properties.getThreads().getCommands(), "Неизвестная команда.", null);
log.info("Введена неизвестная команда message:" + message);
}
}
Loading
Loading