TTW_Bot_GO/internal/events/processor.go

170 lines
6.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package events
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"strings"
"stream-bot/internal/audio"
"stream-bot/internal/db"
"stream-bot/internal/hotkey"
"stream-bot/internal/logger"
"stream-bot/internal/webservices"
)
type Processor struct {
sendMessageFunc func(platform, text string) error
webSrvMgr *webservices.Manager
}
// NewProcessor создаёт обработчик событий с функцией отправки сообщений и менеджером веб-сервисов
func NewProcessor(sendMessageFunc func(platform, text string) error, webSrvMgr *webservices.Manager) *Processor {
return &Processor{
sendMessageFunc: sendMessageFunc,
webSrvMgr: webSrvMgr,
}
}
func (p *Processor) ProcessEvent(platform, eventName string, params map[string]string) {
// 1. Выполняем действия, сохранённые в БД (send_message, play_sound, press_hotkey)
actions, err := db.GetEventActions(platform, eventName)
if err != nil {
logger.Error("Failed to get event actions: %v", err)
} else {
for _, action := range actions {
switch action.Type {
case "send_message":
if p.sendMessageFunc == nil {
logger.Error("sendMessageFunc is nil, cannot send message")
continue
}
text := action.Text
for k, v := range params {
placeholder := "{{" + k + "}}"
text = strings.ReplaceAll(text, placeholder, v)
}
if err := p.sendMessageFunc(platform, text); err != nil {
logger.Error("Send message error: %v", err)
}
case "play_sound":
if err := audio.PlaySound(action.SoundFile); err != nil {
logger.Error("Play sound error: %v", err)
}
case "press_hotkey":
if err := hotkey.PressCombination(action.Keys); err != nil {
logger.Error("Hotkey error: %v", err)
}
case "http_request":
logger.Info("[Event] HTTP request to %s", action.URL)
}
}
}
// 2. Отправляем уведомление во все запущенные alert-сервисы (если есть)
if p.webSrvMgr == nil {
return
}
// Формируем заголовок и текст уведомления на основе типа события
title, text := p.formatEventNotification(eventName, params)
if title == "" && text == "" {
// Если событие не требует уведомления, не отправляем
return
}
// Получаем звук для события (можно настроить позже, пока используем стандартные)
soundFile := p.getSoundForEvent(eventName)
payload := map[string]interface{}{
"title": title,
"text": text,
"duration": 5,
"image": "",
"sound": soundFile,
}
// Отправляем во все alert-сервисы
services := p.webSrvMgr.GetAllServices()
for _, srv := range services {
if srv.GetType() != "alert" {
continue
}
port := srv.GetPort()
url := fmt.Sprintf("http://localhost:%d/notify", port)
body, _ := json.Marshal(payload)
go func(url string, body []byte) {
resp, err := http.Post(url, "application/json", bytes.NewReader(body))
if err != nil {
logger.Error("Failed to send alert to service %s: %v", url, err)
} else {
resp.Body.Close()
}
}(url, body)
}
}
// formatEventNotification формирует заголовок и текст уведомления для события
func (p *Processor) formatEventNotification(eventName string, params map[string]string) (title, text string) {
switch eventName {
case "follow":
username := params["username"]
title = "Новый фолловер!"
text = username + " теперь с нами"
case "subscribe":
username := params["username"]
tier := params["tier"]
tierName := ""
switch tier {
case "1000":
tierName = "1 уровень"
case "2000":
tierName = "2 уровень"
case "3000":
tierName = "3 уровень"
default:
tierName = tier
}
title = "Спасибо за подписку!"
text = username + " подписался на " + tierName
case "gift_sub":
gifter := params["gifter"]
recipient := params["recipient"]
total := params["cumulative_total"]
title = "Подарочная подписка!"
if recipient != "" {
text = gifter + " подарил подписку для " + recipient
} else {
text = gifter + " подарил " + total + " подписок"
}
case "raid":
from := params["from"]
viewers := params["viewers"]
title = "Рейд!"
text = from + " привёл " + viewers + " зрителей"
case "reward_redemption":
username := params["username"]
reward := params["reward_title"]
title = "Активирована награда!"
text = username + " активировал " + reward
default:
return "", ""
}
return title, text
}
// getSoundForEvent возвращает путь к звуковому файлу для события (можно вынести в настройки)
func (p *Processor) getSoundForEvent(eventName string) string {
// Здесь можно читать настройки из БД, пока используем заглушку
sounds := map[string]string{
"follow": "/sounds/follow.mp3",
"subscribe": "/sounds/sub.mp3",
"gift_sub": "/sounds/gift.mp3",
"raid": "/sounds/raid.mp3",
"reward_redemption": "/sounds/reward.mp3",
}
if s, ok := sounds[eventName]; ok {
return s
}
return "/sounds/default.mp3"
}