ZeroBot-Plugin/plugin/minecraftobserver/model.go
github-actions[bot] 6c6699a5d6
chore(lint): 改进代码样式 (#1143)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-25 12:33:02 +09:00

254 lines
7.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 minecraftobserver
import (
"crypto/md5"
"encoding/hex"
"fmt"
"strings"
"time"
"github.com/Tnze/go-mc/chat"
"github.com/google/uuid"
"github.com/wdvxdr1123/ZeroBot/utils/helper"
)
// ====================
// DB Schema
// serverStatus 服务器状态
type serverStatus struct {
// ID 主键
ID int64 `json:"id" gorm:"column:id;primary_key:pk_id;auto_increment;default:0"`
// 服务器地址
ServerAddr string `json:"server_addr" gorm:"column:server_addr;default:'';unique_index:udx_server_addr"`
// 服务器描述
Description string `json:"description" gorm:"column:description;default:null;type:CLOB"`
// 在线玩家
Players string `json:"players" gorm:"column:players;default:''"`
// 版本
Version string `json:"version" gorm:"column:version;default:''"`
// FaviconMD5 Favicon MD5
FaviconMD5 string `json:"favicon_md5" gorm:"column:favicon_md5;default:''"`
// FaviconRaw 原始数据
FaviconRaw icon `json:"favicon_raw" gorm:"column:favicon_raw;default:null;type:CLOB"`
// 延迟,不可达时为-1
PingDelay int64 `json:"ping_delay" gorm:"column:ping_delay;default:-1"`
// 更新时间
LastUpdate int64 `json:"last_update" gorm:"column:last_update;default:0"`
}
// serverSubscribe 订阅信息
type serverSubscribe struct {
// ID 主键
ID int64 `json:"id" gorm:"column:id;primary_key:pk_id;auto_increment;default:0"`
// 服务器地址
ServerAddr string `json:"server_addr" gorm:"column:server_addr;default:'';unique_index:udx_ait"`
// 推送目标id
TargetID int64 `json:"target_id" gorm:"column:target_id;default:0;unique_index:udx_ait"`
// 类型 1群组 2个人
TargetType int64 `json:"target_type" gorm:"column:target_type;default:0;unique_index:udx_ait"`
// 更新时间
LastUpdate int64 `json:"last_update" gorm:"column:last_update;default:0"`
}
const (
// pingDelayUnreachable 不可达
pingDelayUnreachable = -1
)
// isServerStatusSpecChanged 检查是否有状态变化
func (ss *serverStatus) isServerStatusSpecChanged(newStatus *serverStatus) (res bool) {
res = false
if ss == nil || newStatus == nil {
res = false
return
}
// 描述变化、版本变化、Favicon变化
if ss.Description != newStatus.Description || ss.Version != newStatus.Version || ss.FaviconMD5 != newStatus.FaviconMD5 {
res = true
return
}
// 状态由不可达变为可达 or 反之
if (ss.PingDelay == pingDelayUnreachable && newStatus.PingDelay != pingDelayUnreachable) ||
(ss.PingDelay != pingDelayUnreachable && newStatus.PingDelay == pingDelayUnreachable) {
res = true
return
}
return
}
// deepCopy 深拷贝
func (ss *serverStatus) deepCopy() (dst *serverStatus) {
if ss == nil {
return
}
dst = &serverStatus{}
*dst = *ss
return
}
// generateServerStatusMsg 生成服务器状态消息
func (ss *serverStatus) generateServerStatusMsg() (msg string, iconBase64 string) {
var msgBuilder strings.Builder
if ss == nil {
return
}
msgBuilder.WriteString(ss.Description)
msgBuilder.WriteString("\n")
msgBuilder.WriteString("服务器地址:")
msgBuilder.WriteString(ss.ServerAddr)
msgBuilder.WriteString("\n")
// 版本
msgBuilder.WriteString("版本:")
msgBuilder.WriteString(ss.Version)
msgBuilder.WriteString("\n")
// Ping
if ss.PingDelay < 0 {
msgBuilder.WriteString("Ping延迟超时\n")
} else {
msgBuilder.WriteString("Ping延迟")
msgBuilder.WriteString(fmt.Sprintf("%d 毫秒\n", ss.PingDelay))
msgBuilder.WriteString("在线人数:")
msgBuilder.WriteString(ss.Players)
}
// 图标
if ss.FaviconRaw != "" && ss.FaviconRaw.checkPNG() {
iconBase64 = ss.FaviconRaw.toBase64String()
}
msg = msgBuilder.String()
return
}
// DB Schema End
// ====================
// Ping & List Response DTO
// serverPingAndListResp 服务器状态数据传输对象 From mc server response
type serverPingAndListResp struct {
Description chat.Message
Players struct {
Max int
Online int
Sample []struct {
ID uuid.UUID
Name string
}
}
Version struct {
Name string
Protocol int
}
Favicon icon
Delay time.Duration
}
// icon should be a PNG image that is Base64 encoded
// (without newlines: \n, new lines no longer work since 1.13)
// and prepended with "data:image/png;base64,".
type icon string
// func (i icon) toImage() (icon image.Image, err error) {
// const prefix = "data:image/png;base64,"
// if !strings.HasPrefix(string(i), prefix) {
// return nil, errors.Errorf("server icon should prepended with %s", prefix)
// }
// base64png := strings.TrimPrefix(string(i), prefix)
// r := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64png))
// icon, err = png.Decode(r)
// return
//}
// checkPNG 检查是否为PNG
func (i icon) checkPNG() bool {
const prefix = "data:image/png;base64,"
return strings.HasPrefix(string(i), prefix)
}
// toBase64String 转换为base64字符串
func (i icon) toBase64String() string {
return "base64://" + strings.TrimPrefix(string(i), "data:image/png;base64,")
}
// genServerSubscribeSchema 将DTO转换为DB Schema
func (dto *serverPingAndListResp) genServerSubscribeSchema(addr string, id int64) *serverStatus {
if dto == nil {
return nil
}
faviconMD5 := md5.Sum(helper.StringToBytes(string(dto.Favicon)))
return &serverStatus{
ID: id,
ServerAddr: addr,
Description: dto.Description.ClearString(),
Version: dto.Version.Name,
Players: fmt.Sprintf("%d/%d", dto.Players.Online, dto.Players.Max),
FaviconMD5: hex.EncodeToString(faviconMD5[:]),
FaviconRaw: dto.Favicon,
PingDelay: dto.Delay.Milliseconds(),
LastUpdate: time.Now().Unix(),
}
}
// Ping & List Response DTO End
// ====================
// ====================
// Biz Model
const (
logPrefix = "[minecraft observer] "
)
// warpTargetIDAndType 转换消息信息到订阅的目标ID和类型
func warpTargetIDAndType(groupID, userID int64) (int64, int64) {
// 订阅
var targetID int64
var targetType int64
if groupID == 0 {
targetType = targetTypeUser
targetID = userID
} else {
targetType = targetTypeGroup
targetID = groupID
}
return targetID, targetType
}
// formatSubStatusChangeText 格式化状态变更文本
func formatSubStatusChangeText(oldStatus, newStatus *serverStatus) string {
var msgBuilder strings.Builder
if oldStatus == nil || newStatus == nil {
return ""
}
// 变更通知
msgBuilder.WriteString("[Minecraft服务器状态变更通知]\n")
// 地址
msgBuilder.WriteString(fmt.Sprintf("服务器地址: %v\n", oldStatus.ServerAddr))
// 描述
if oldStatus.Description != newStatus.Description {
msgBuilder.WriteString("\n-----[描述变更]-----\n")
msgBuilder.WriteString(fmt.Sprintf("[旧]\n%v\n", oldStatus.Description))
msgBuilder.WriteString(fmt.Sprintf("[新]\n%v\n", newStatus.Description))
}
// 版本
if oldStatus.Version != newStatus.Version {
msgBuilder.WriteString("\n-----[版本变更]-----\n")
msgBuilder.WriteString(fmt.Sprintf("[旧]\n%v\n", oldStatus.Version))
msgBuilder.WriteString(fmt.Sprintf("[新]\n%v\n", newStatus.Version))
}
// 状态由不可达变为可达,反之
if oldStatus.PingDelay == pingDelayUnreachable && newStatus.PingDelay != pingDelayUnreachable {
msgBuilder.WriteString("\n-----[Ping延迟]-----\n")
msgBuilder.WriteString("[旧]\n超时\n")
msgBuilder.WriteString(fmt.Sprintf("[新]\n%v毫秒\n", newStatus.PingDelay))
}
if oldStatus.PingDelay != pingDelayUnreachable && newStatus.PingDelay == pingDelayUnreachable {
msgBuilder.WriteString("\n-----[Ping延迟]-----\n")
msgBuilder.WriteString(fmt.Sprintf("[旧]\n%v毫秒\n", oldStatus.PingDelay))
msgBuilder.WriteString("[新]\n超时\n")
}
return msgBuilder.String()
}
// Biz Model End
// ====================