2026-06-12 01:21:33 +08:00

102 lines
2.8 KiB
Go

package gamemanagement
import (
"context"
"database/sql"
"fmt"
"net/url"
"strings"
"unicode/utf8"
)
type RobotProfile struct {
Nickname string
Avatar string
}
type RobotProfileSource interface {
RandomRobotProfiles(ctx context.Context, count int) ([]RobotProfile, error)
}
type likeiRobotProfileSource struct {
db *sql.DB
}
func NewLikeiRobotProfileSource(db *sql.DB) RobotProfileSource {
if db == nil {
return nil
}
return &likeiRobotProfileSource{db: db}
}
// WithRobotProfileSource 注入机器人资料池;创建机器人时只消费这里返回的线上 likei 用户昵称和头像。
func WithRobotProfileSource(source RobotProfileSource) Option {
return func(h *Handler) {
h.robotProfiles = source
}
}
func (s *likeiRobotProfileSource) RandomRobotProfiles(ctx context.Context, count int) ([]RobotProfile, error) {
if s == nil || s.db == nil {
return nil, fmt.Errorf("likei robot profile source is not configured")
}
if count <= 0 {
return nil, nil
}
rows, err := s.db.QueryContext(ctx, `
SELECT TRIM(user_nickname), TRIM(user_avatar)
FROM user_base_info
WHERE account_status = 'NORMAL'
AND is_del = 0
AND origin_sys = 'LIKEI'
AND user_avatar IS NOT NULL AND TRIM(user_avatar) <> ''
AND user_nickname IS NOT NULL AND TRIM(user_nickname) <> ''
AND CHAR_LENGTH(TRIM(user_nickname)) <= 64
AND CHAR_LENGTH(TRIM(user_avatar)) <= 512
AND (TRIM(user_avatar) LIKE 'http://%' OR TRIM(user_avatar) LIKE 'https://%')
ORDER BY RAND()
LIMIT ?
`, count)
if err != nil {
return nil, fmt.Errorf("query likei robot profiles: %w", err)
}
defer rows.Close()
profiles := make([]RobotProfile, 0, count)
for rows.Next() {
var profile RobotProfile
if err := rows.Scan(&profile.Nickname, &profile.Avatar); err != nil {
return nil, fmt.Errorf("scan likei robot profile: %w", err)
}
if normalized, ok := normalizeRobotProfile(profile); ok {
profiles = append(profiles, normalized)
}
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate likei robot profiles: %w", err)
}
if len(profiles) < count {
return nil, fmt.Errorf("likei robot profile pool returned %d profiles, need %d", len(profiles), count)
}
return profiles, nil
}
func normalizeRobotProfile(profile RobotProfile) (RobotProfile, bool) {
profile.Nickname = strings.TrimSpace(profile.Nickname)
profile.Avatar = strings.TrimSpace(profile.Avatar)
if profile.Nickname == "" || profile.Avatar == "" {
return RobotProfile{}, false
}
if utf8.RuneCountInString(profile.Nickname) > 64 || utf8.RuneCountInString(profile.Avatar) > 512 {
return RobotProfile{}, false
}
parsed, err := url.Parse(profile.Avatar)
if err != nil || parsed.Host == "" || (parsed.Scheme != "http" && parsed.Scheme != "https") {
return RobotProfile{}, false
}
if strings.ContainsAny(profile.Avatar, " \t\r\n") {
return RobotProfile{}, false
}
return profile, true
}