181 lines
3.5 KiB
Go
181 lines
3.5 KiB
Go
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
|
||
}
|