TTW_Bot_GO/internal/webservices/manager.go

181 lines
3.5 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 webservices
import (
"fmt"
"stream-bot/internal/db"
"stream-bot/internal/logger"
"sync"
)
type Manager struct {
services map[int]Service
mu sync.RWMutex
globalMessageChan chan ChatMessage
globalEventChan chan AlertEvent
}
func NewManager() *Manager {
m := &Manager{
services: make(map[int]Service),
globalMessageChan: make(chan ChatMessage, 1000),
globalEventChan: make(chan AlertEvent, 1000),
}
m.startDispatchers()
return m
}
func (m *Manager) startDispatchers() {
go func() {
for msg := range m.globalMessageChan {
m.mu.RLock()
for _, srv := range m.services {
if chatSrv, ok := srv.(*ChatService); ok {
chatSrv.SendToClients(msg)
}
}
m.mu.RUnlock()
}
}()
go func() {
for ev := range m.globalEventChan {
m.mu.RLock()
for _, srv := range m.services {
if alertSrv, ok := srv.(*AlertService); ok {
alertSrv.SendToClients(ev)
}
}
m.mu.RUnlock()
}
}()
}
func (m *Manager) StartAll() error {
list, err := db.GetAllWebServices()
if err != nil {
return err
}
for _, ws := range list {
if !ws.Enabled {
continue
}
if err := m.startServiceFromDB(ws); err != nil {
logger.Error("Failed to start service %d: %v", ws.ID, err)
}
}
return nil
}
func (m *Manager) startServiceFromDB(ws db.WebService) error {
var srv Service
switch ws.Type {
case "chat":
cfg, err := ws.GetChatConfig()
if err != nil {
return err
}
srv = NewChatService(ws.Port, cfg)
case "alert":
cfg, err := ws.GetAlertConfig()
if err != nil {
return err
}
srv = NewAlertService(ws.Port, cfg)
default:
return fmt.Errorf("unknown service type: %s", ws.Type)
}
if err := srv.Start(); err != nil {
return err
}
m.mu.Lock()
m.services[ws.ID] = srv
m.mu.Unlock()
_ = db.SetWebServiceRunning(ws.ID, true)
return nil
}
func (m *Manager) AddService(serviceType string, port int, config interface{}) (int, error) {
id, err := db.CreateWebService(serviceType, port, config)
if err != nil {
return 0, err
}
return id, nil
}
func (m *Manager) StartService(id int) error {
ws, err := db.GetWebService(id)
if err != nil {
return err
}
return m.startServiceFromDB(*ws)
}
func (m *Manager) StopService(id int) error {
m.mu.Lock()
srv, ok := m.services[id]
delete(m.services, id)
m.mu.Unlock()
if !ok {
return nil
}
if err := srv.Stop(); err != nil {
return err
}
_ = db.SetWebServiceRunning(id, false)
return nil
}
func (m *Manager) UpdateConfig(id int, config interface{}) error {
ws, err := db.GetWebService(id)
if err != nil {
return err
}
if err := db.UpdateWebService(id, ws.Port, config, ws.Enabled); err != nil {
return err
}
m.mu.RLock()
srv, ok := m.services[id]
m.mu.RUnlock()
if ok {
return srv.ReloadConfig(config)
}
return nil
}
func (m *Manager) DeleteService(id int) error {
_ = m.StopService(id)
return db.DeleteWebService(id)
}
// Эти два метода должны быть ТОЛЬКО ОДИН РАЗ!
func (m *Manager) SendChatMessage(msg ChatMessage) {
select {
case m.globalMessageChan <- msg:
default:
logger.Warn("Chat message buffer full")
}
}
func (m *Manager) SendAlertEvent(event AlertEvent) {
select {
case m.globalEventChan <- event:
default:
logger.Warn("Alert event buffer full")
}
}
func (m *Manager) GetService(id int) Service {
m.mu.RLock()
defer m.mu.RUnlock()
return m.services[id]
}
func (m *Manager) GetAllServices() map[int]Service {
m.mu.RLock()
defer m.mu.RUnlock()
out := make(map[int]Service)
for k, v := range m.services {
out[k] = v
}
return out
}