mcstatus/monitor.go

155 lines
3.1 KiB
Go

package main
import (
"fmt"
"log"
"strings"
"sync"
"time"
"github.com/bwmarrin/discordgo"
)
type StatusMonitor struct {
mu sync.Mutex
session *discordgo.Session
channelID string
host string
port int
interval time.Duration
messageID string
onlineSince time.Time
}
func NewStatusMonitor(s *discordgo.Session, cfg *Config) *StatusMonitor {
return &StatusMonitor{
session: s,
channelID: cfg.ChannelID,
host: cfg.ServerHost,
port: cfg.ServerPort,
interval: time.Duration(cfg.UpdateInterval) * time.Second,
}
}
func (m *StatusMonitor) Start() {
m.findExistingMessage()
m.updateStatus()
ticker := time.NewTicker(m.interval)
go func() {
for range ticker.C {
m.updateStatus()
}
}()
}
func (m *StatusMonitor) findExistingMessage() {
msgs, err := m.session.ChannelMessages(m.channelID, 50, "", "", "")
if err != nil {
log.Printf("Error fetching messages: %v", err)
return
}
for _, msg := range msgs {
if msg.Author.ID == m.session.State.User.ID {
m.mu.Lock()
m.messageID = msg.ID
m.mu.Unlock()
return
}
}
}
func (m *StatusMonitor) buildEmbed(status *ServerStatus) *discordgo.MessageEmbed {
embed := &discordgo.MessageEmbed{
Color: 0x808080,
Title: "NikoCraft",
URL: "https://mc.n1ko.dev",
}
if !status.Online {
embed.Description = "**Сервер оффлайн** 🔴"
embed.Color = 0xFF0000
return embed
}
var b strings.Builder
b.WriteString("**Игроки:**\n```\n")
if len(status.Players) == 0 {
b.WriteString("Никого нет")
} else {
for i, name := range status.Players {
if i > 0 {
b.WriteString("\n")
}
b.WriteString(name)
}
}
b.WriteString("```")
embed.Description = b.String()
uptime := time.Since(m.onlineSince)
var uptimeStr string
hours := uptime.Hours()
if hours < 1 {
uptimeStr = fmt.Sprintf("%.0f мин.", uptime.Minutes())
} else {
uptimeStr = fmt.Sprintf("%.1f ч.", hours)
}
embed.Fields = []*discordgo.MessageEmbedField{
{
Name: ":busts_in_silhouette: Игроков",
Value: fmt.Sprintf("%d/%d", status.OnlineCount, status.MaxPlayers),
Inline: true,
},
{
Name: ":repeat: Аптайм",
Value: uptimeStr,
Inline: true,
},
}
return embed
}
func (m *StatusMonitor) updateStatus() {
status, err := queryServer(m.host, m.port)
m.mu.Lock()
defer m.mu.Unlock()
if err != nil {
log.Printf("Server query failed: %v", err)
m.onlineSince = time.Time{}
status = &ServerStatus{Online: false}
} else {
if m.onlineSince.IsZero() {
m.onlineSince = time.Now()
}
}
embed := m.buildEmbed(status)
if m.messageID != "" {
_, err := m.session.ChannelMessageEditComplex(&discordgo.MessageEdit{
Channel: m.channelID,
ID: m.messageID,
Embeds: &[]*discordgo.MessageEmbed{embed},
})
if err != nil {
log.Printf("Error editing embed (will create new): %v", err)
m.messageID = ""
}
}
if m.messageID == "" {
msg, err := m.session.ChannelMessageSendEmbed(m.channelID, embed)
if err != nil {
log.Printf("Error sending embed: %v", err)
return
}
m.messageID = msg.ID
}
}