<commit_before>package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	bt "github.com/ikool-cn/gobeanstalk-connection-pool"
	"strconv"
	"strings"
	"time"
	// "regexp"
)

var (
	qqBot *QQBot
)

// QQFace ...
type QQFace int

// QQAt ...
type QQAt struct {
	qq string
}

// QQImage ...
type QQImage struct {
	file string
}

// QQBot ...
type QQBot struct {
	ID     string
	Config *QQConfig
	Client *bt.Pool
	RecvQ  string
	SendQ  string
}

// NewQQBot ...
func NewQQBot(cfg *Config) *QQBot {
	q := &QQBot{ID: cfg.QQ.BotID, Config: cfg.QQ}
	q.Client = &bt.Pool{
		Dial: func() (*bt.Conn, error) {
			return bt.Dial(cfg.BeanstalkAddr)
		},
		MaxIdle:     10,
		MaxActive:   100,
		IdleTimeout: 60 * time.Second,
		MaxLifetime: 180 * time.Second,
		Wait:        true,
	}

	q.RecvQ = q.ID + "(o)"
	q.SendQ = q.ID + "(i)"
	return q
}

// String generate code string for qq face
func (q QQFace) String() string {
	return fmt.Sprintf("[CQ:face,id=%d]", q)
}

// String generate code string for qq image
func (q QQImage) String() string {
	return fmt.Sprintf("[CQ:image,file=%s]", q.file)
}

// String generate code string for qq qt msg
func (q QQAt) String() string {
	return fmt.Sprintf("[CQ:at,qq=%s]", q.qq)
}

func (q *QQBot) send(msg []byte) {
	// wait longer with more errors
	var (
		conn *bt.Conn
		err  error
	)
	for i := 1; ; i++ {
		conn, err = q.Client.Get()
		if err == nil {
			break
		}
		time.Sleep(time.Duration(i) * time.Second)
		if i > q.Config.SendMaxRetry {
			logger.Error("Send failed:", string(msg))
			return
		}
	}
	conn.Use(q.SendQ)
	_, err = conn.Put(msg, 1, 0, time.Minute)
	if err != nil {
		logger.Error(err)
		return
	}

	q.Client.Release(conn, false)
	return
}

// SendGroupMsg ...
func (q *QQBot) SendGroupMsg(msg string) {
	logger.Infof(strconv.Quote(msg))
	fullMsg, err := formMsg("sendGroupMsg", q.Config.GroupID, msg)
	if err != nil {
		logger.Error(err)
		return
	}
	go q.send(fullMsg)
}

// SendPics ...
func (q *QQBot) SendPics(fn func(string), url string) {
	fileName, err := downloadFile(url, q.Config.ImgPath)
	if err != nil {
		return
	}
	fn(QQImage{fileName}.String())
}

// SendPrivateMsg ...
func (q *QQBot) SendPrivateMsg(qq string, msg string) {
	logger.Infof("TO:" + qq + ":" + strconv.Quote(msg))
	fullMsg, err := formMsg("sendPrivateMsg", qq, msg)
	if err != nil {
		logger.Error(err)
	} else {
		go q.send(fullMsg)
	}
}

//SendSelfMsg ...
func (q *QQBot) SendSelfMsg(msg string) {
	q.SendPrivateMsg(q.Config.SelfID, msg)
}

// CheckMention ...
func (q *QQBot) CheckMention(msg string) bool {
	for _, s := range q.Config.SelfNames {
		if strings.Contains(msg, s) {
			return true
		}
	}
	return false
}

// NoticeMention ...
func (q *QQBot) NoticeMention(msg string, group string) {
	if !q.CheckMention(msg) {
		return
	}
	key := q.Config.SelfID + "_mention"
	exists, err := redisClient.Expire(key, 10*time.Minute).Result()
	if err != nil {
		logger.Error(err)
		return
	}
	if exists {
		logger.Notice("Called in last 10min")
	} else {
		_, err := redisClient.Set(key, 0, 10*time.Minute).Result()
		if err != nil {
			logger.Error(err)
			return
		}
		q.SendGroupMsg("呀呀呀，召唤一号机" + QQAt{q.Config.SelfID}.String())
	}
}

// CheckRepeat ...
func (q *QQBot) CheckRepeat(msg string, group string) {
	key := group + "_last"
	flattendMsg := strings.TrimSpace(msg)
	defer redisClient.LPush(key, flattendMsg)
	lastMsgs, err := redisClient.LRange(key, 0, 5).Result()<commit_msg>ltrim last msgs to 10<commit_after>package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	bt "github.com/ikool-cn/gobeanstalk-connection-pool"
	"strconv"
	"strings"
	"time"
	// "regexp"
)

var (
	qqBot *QQBot
)

// QQFace ...
type QQFace int

// QQAt ...
type QQAt struct {
	qq string
}

// QQImage ...
type QQImage struct {
	file string
}

// QQBot ...
type QQBot struct {
	ID     string
	Config *QQConfig
	Client *bt.Pool
	RecvQ  string
	SendQ  string
}

// NewQQBot ...
func NewQQBot(cfg *Config) *QQBot {
	q := &QQBot{ID: cfg.QQ.BotID, Config: cfg.QQ}
	q.Client = &bt.Pool{
		Dial: func() (*bt.Conn, error) {
			return bt.Dial(cfg.BeanstalkAddr)
		},
		MaxIdle:     10,
		MaxActive:   100,
		IdleTimeout: 60 * time.Second,
		MaxLifetime: 180 * time.Second,
		Wait:        true,
	}

	q.RecvQ = q.ID + "(o)"
	q.SendQ = q.ID + "(i)"
	return q
}

// String generate code string for qq face
func (q QQFace) String() string {
	return fmt.Sprintf("[CQ:face,id=%d]", q)
}

// String generate code string for qq image
func (q QQImage) String() string {
	return fmt.Sprintf("[CQ:image,file=%s]", q.file)
}

// String generate code string for qq qt msg
func (q QQAt) String() string {
	return fmt.Sprintf("[CQ:at,qq=%s]", q.qq)
}

func (q *QQBot) send(msg []byte) {
	// wait longer with more errors
	var (
		conn *bt.Conn
		err  error
	)
	for i := 1; ; i++ {
		conn, err = q.Client.Get()
		if err == nil {
			break
		}
		time.Sleep(time.Duration(i) * time.Second)
		if i > q.Config.SendMaxRetry {
			logger.Error("Send failed:", string(msg))
			return
		}
	}
	conn.Use(q.SendQ)
	_, err = conn.Put(msg, 1, 0, time.Minute)
	if err != nil {
		logger.Error(err)
		return
	}

	q.Client.Release(conn, false)
	return
}

// SendGroupMsg ...
func (q *QQBot) SendGroupMsg(msg string) {
	logger.Infof(strconv.Quote(msg))
	fullMsg, err := formMsg("sendGroupMsg", q.Config.GroupID, msg)
	if err != nil {
		logger.Error(err)
		return
	}
	go q.send(fullMsg)
}

// SendPics ...
func (q *QQBot) SendPics(fn func(string), url string) {
	fileName, err := downloadFile(url, q.Config.ImgPath)
	if err != nil {
		return
	}
	fn(QQImage{fileName}.String())
}

// SendPrivateMsg ...
func (q *QQBot) SendPrivateMsg(qq string, msg string) {
	logger.Infof("TO:" + qq + ":" + strconv.Quote(msg))
	fullMsg, err := formMsg("sendPrivateMsg", qq, msg)
	if err != nil {
		logger.Error(err)
	} else {
		go q.send(fullMsg)
	}
}

//SendSelfMsg ...
func (q *QQBot) SendSelfMsg(msg string) {
	q.SendPrivateMsg(q.Config.SelfID, msg)
}

// CheckMention ...
func (q *QQBot) CheckMention(msg string) bool {
	for _, s := range q.Config.SelfNames {
		if strings.Contains(msg, s) {
			return true
		}
	}
	return false
}

// NoticeMention ...
func (q *QQBot) NoticeMention(msg string, group string) {
	if !q.CheckMention(msg) {
		return
	}
	key := q.Config.SelfID + "_mention"
	exists, err := redisClient.Expire(key, 10*time.Minute).Result()
	if err != nil {
		logger.Error(err)
		return
	}
	if exists {
		logger.Notice("Called in last 10min")
	} else {
		_, err := redisClient.Set(key, 0, 10*time.Minute).Result()
		if err != nil {
			logger.Error(err)
			return
		}
		q.SendGroupMsg("呀呀呀，召唤一号机" + QQAt{q.Config.SelfID}.String())
	}
}

// CheckRepeat ...
func (q *QQBot) CheckRepeat(msg string, group string) {
	key := group + "_last"
	flattendMsg := strings.TrimSpace(msg)
	defer redisClient.LTrim(key, 0, 10)
	defer redisClient.LPush(key, flattendMsg)
	lastMsgs, err := redisClient.LRange(key, 0, 5).Result()
{'fraction_non_alphanumeric': 0.1656245455867384, 'fraction_numerical': 0.007706848916678785, 'mean_word_length': 3.243059839605182, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1701583', 'n_tokens_mistral': 2981, 'n_tokens_neox': 2796, 'n_words': 657}