TTW_Bot_GO/internal/platforms/manager.go

216 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 platforms
import (
"strings"
"sync"
"time"
"fmt"
"stream-bot/internal/commands"
"stream-bot/internal/events"
"stream-bot/internal/logger"
"stream-bot/internal/userstats"
"stream-bot/internal/db"
"stream-bot/internal/notifications"
"stream-bot/internal/webservices"
)
type Platform interface {
Connect() error
Disconnect()
SendMessage(text string) error
GetName() string
}
type Manager struct {
platforms map[string]Platform
cmdProc *commands.Processor
eventProc *events.Processor
mu sync.RWMutex
userStats *userstats.Store
notifMgr *notifications.Manager
webServices *webservices.Manager
}
func NewManager(cmdProc *commands.Processor, eventProc *events.Processor, notifMgr *notifications.Manager, webSrv *webservices.Manager) *Manager {
m := &Manager{
platforms: make(map[string]Platform),
cmdProc: cmdProc,
eventProc: eventProc,
userStats: userstats.NewStore(),
notifMgr: notifMgr,
webServices: webSrv,
}
m.platforms["twitch"] = NewTwitchPlatform(m)
return m
}
func (m *Manager) ConnectAll() {
for name, p := range m.platforms {
if err := p.Connect(); err != nil {
logger.Error("Failed to connect %s: %v", name, err)
}
}
}
func (m *Manager) StopAll() {
for _, p := range m.platforms {
p.Disconnect()
}
}
func (m *Manager) GetPlatform(name string) Platform {
m.mu.RLock()
defer m.mu.RUnlock()
return m.platforms[name]
}
func (m *Manager) OnChatMessage(platform, channel, username, message string, isMod, isBroadcaster, isVip, isSubscriber bool) {
// Обновляем статистику пользователя
m.userStats.Update(username, func(u *userstats.UserStats) {
u.MessageCount++
u.LastActive = time.Now()
u.IsMod = isMod
u.IsVip = isVip
u.IsSubscriber = isSubscriber
})
if m.notifMgr != nil {
m.notifMgr.PlayEvent("new_message")
}
m.webServices.SendChatMessage(webservices.ChatMessage{
Username: username,
Message: message,
IsMod: isMod,
IsVip: isVip,
IsSub: isSubscriber,
Timestamp: time.Now().Unix(),
})
// Обработка команды
if len(message) == 0 || message[0] != '!' {
// Проверка на отметку: если пользователь отмечен и это его первое сообщение за стрим (сегодня)
m.checkAndSendMarkNotification(username, platform, channel)
return
}
parts := strings.SplitN(message, " ", 2)
trigger := strings.TrimPrefix(parts[0], "!")
args := ""
if len(parts) > 1 {
args = parts[1]
}
resp, _, err := m.cmdProc.ProcessCommand(trigger, username, platform, isMod, isBroadcaster, args)
if err != nil {
logger.Error("Command error: %v", err)
return
}
if resp != "" {
if p := m.GetPlatform(platform); p != nil {
p.SendMessage(resp)
}
}
// После команды тоже проверяем отметку (можно вынести в общее место)
m.checkAndSendMarkNotification(username, platform, channel)
}
// checkAndSendMarkNotification отправляет сообщение, если пользователь отмечен и сегодня ещё не отмечали
func (m *Manager) checkAndSendMarkNotification(username, platform, channel string) {
marked, lastDate, err := db.IsUserMarked(username, platform)
if err != nil {
logger.Error("Failed to check marked user: %v", err)
return
}
if !marked {
return
}
today := time.Now().Format("2006-01-02")
if lastDate == today {
return
}
// Отправляем сообщение с упоминанием пользователя, а не канала
msg := fmt.Sprintf("Время кое-кого отметить! Отмечен @%s", username)
if p := m.GetPlatform(platform); p != nil {
p.SendMessage(msg)
}
db.UpdateMarkedUserDate(username, platform, time.Now())
}
func (m *Manager) OnEvent(platform, eventName string, params map[string]string) {
m.eventProc.ProcessEvent(platform, eventName, params)
if m.webServices != nil {
// Преобразуем map[string]string в map[string]interface{}
data := make(map[string]interface{})
for k, v := range params {
data[k] = v
}
// Исправленный вызов:
m.webServices.SendAlertEvent(webservices.AlertEvent{
Type: eventName,
Data: data,
})
}
}
func (m *Manager) IsConnected(platform string) bool {
m.mu.RLock()
defer m.mu.RUnlock()
if p, ok := m.platforms[platform]; ok {
if tw, ok := p.(*TwitchPlatform); ok {
return tw.IsConnected()
}
// для других платформ можно добавить аналогично
}
return false
}
func (m *Manager) GetAllUsers() []*userstats.UserStats {
return m.userStats.GetAll()
}
func (m *Manager) UpdateUserFlags(username string, isVip, isMod, isSubscriber bool) {
m.userStats.Update(username, func(u *userstats.UserStats) {
if isVip {
u.IsVip = isVip
}
if isMod {
u.IsMod = isMod
}
if isSubscriber {
u.IsSubscriber = isSubscriber
}
})
}
func (m *Manager) UpdateUserMarked(username string, marked bool) {
m.userStats.Update(username, func(u *userstats.UserStats) {
u.IsMarked = marked
})
}
func (m *Manager) SetVip(username string, isVip bool) {
m.userStats.Update(username, func(u *userstats.UserStats) {
u.IsVip = isVip
})
}
func (m *Manager) SetMod(username string, isMod bool) {
m.userStats.Update(username, func(u *userstats.UserStats) {
u.IsMod = isMod
})
}
func (m *Manager) SetMarked(username string, isMarked bool) {
m.userStats.Update(username, func(u *userstats.UserStats) {
u.IsMarked = isMarked
})
}
func (m *Manager) GetTwitchEventSubStatus() (connected bool, subscriptions []string, err error) {
tw, ok := m.platforms["twitch"].(*TwitchPlatform)
if !ok {
return false, nil, fmt.Errorf("twitch platform not available")
}
connected, subscriptions = tw.EventSubStatus()
return connected, subscriptions, nil
}