mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 11:07:40 +08:00
fix ttl.
This commit is contained in:
parent
bf8fa81a5d
commit
e1e00ed068
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
||||||
"github.com/Mrs4s/MiraiGo/utils"
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@ -235,12 +236,13 @@ func decodeMessageSvcPacket(c *QQClient, _ uint16, payload []byte) (interface{},
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if friend.msgSeqList == nil {
|
if friend.msgSeqList == nil {
|
||||||
friend.msgSeqList = utils.NewTTList(60)
|
friend.msgSeqList = utils.NewCache(time.Second * 5)
|
||||||
}
|
}
|
||||||
if friend.msgSeqList.Any(func(i interface{}) bool { return i.(int32) == message.Head.MsgSeq }) {
|
strSeq := strconv.FormatInt(int64(message.Head.MsgSeq), 10)
|
||||||
|
if _, ok := friend.msgSeqList.Get(strSeq); ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
friend.msgSeqList.Add(message.Head.MsgSeq)
|
friend.msgSeqList.Add(strSeq, 0, time.Second*15)
|
||||||
c.dispatchFriendMessage(c.parsePrivateMessage(message))
|
c.dispatchFriendMessage(c.parsePrivateMessage(message))
|
||||||
case 187:
|
case 187:
|
||||||
_, pkt := c.buildSystemMsgNewFriendPacket()
|
_, pkt := c.buildSystemMsgNewFriendPacket()
|
||||||
|
@ -37,7 +37,7 @@ type (
|
|||||||
Remark string
|
Remark string
|
||||||
FaceId int16
|
FaceId int16
|
||||||
|
|
||||||
msgSeqList *utils.TTList
|
msgSeqList *utils.Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
FriendListResponse struct {
|
FriendListResponse struct {
|
||||||
|
114
utils/ttl.go
114
utils/ttl.go
@ -5,54 +5,96 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TTList struct {
|
// https://github.com/Konstantin8105/SimpleTTL
|
||||||
list []*item
|
// entry - typical element of cache
|
||||||
lock sync.Mutex
|
type entry struct {
|
||||||
|
value interface{}
|
||||||
|
expiry *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type item struct {
|
// Cache - simple implementation of cache
|
||||||
i interface{}
|
// More information: https://en.wikipedia.org/wiki/Time_to_live
|
||||||
lastAccess int64
|
type Cache struct {
|
||||||
|
timeTTL time.Duration
|
||||||
|
cache map[string]*entry
|
||||||
|
lock *sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTTList(ttl int64) *TTList {
|
// NewCache - initialization of new cache.
|
||||||
l := &TTList{}
|
// For avoid mistake - minimal time to live is 1 minute.
|
||||||
|
// For simplification, - key is string and cache haven`t stop method
|
||||||
|
func NewCache(interval time.Duration) *Cache {
|
||||||
|
if interval < time.Second {
|
||||||
|
interval = time.Second
|
||||||
|
}
|
||||||
|
cache := &Cache{
|
||||||
|
timeTTL: interval,
|
||||||
|
cache: make(map[string]*entry),
|
||||||
|
lock: &sync.RWMutex{},
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for now := range time.Tick(time.Second * 5) {
|
ticker := time.NewTicker(cache.timeTTL)
|
||||||
l.lock.Lock()
|
for {
|
||||||
pos := 0
|
// wait of ticker
|
||||||
for _, i := range l.list {
|
now := <-ticker.C
|
||||||
if now.Unix()-i.lastAccess > ttl {
|
|
||||||
l.list = append(l.list[:pos], l.list[pos+1:]...)
|
// remove entry outside TTL
|
||||||
if pos > 0 {
|
cache.lock.Lock()
|
||||||
pos++
|
for id, entry := range cache.cache {
|
||||||
}
|
if entry.expiry != nil && entry.expiry.Before(now) {
|
||||||
|
delete(cache.cache, id)
|
||||||
}
|
}
|
||||||
pos++
|
|
||||||
}
|
}
|
||||||
l.lock.Unlock()
|
cache.lock.Unlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return l
|
return cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *TTList) Add(i interface{}) {
|
// Count - return amount element of TTL map.
|
||||||
l.lock.Lock()
|
func (cache *Cache) Count() int {
|
||||||
defer l.lock.Unlock()
|
cache.lock.RLock()
|
||||||
l.list = append(l.list, &item{
|
defer cache.lock.RUnlock()
|
||||||
i: i,
|
|
||||||
lastAccess: time.Now().Unix(),
|
return len(cache.cache)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *TTList) Any(filter func(i interface{}) bool) bool {
|
// Get - return value from cache
|
||||||
l.lock.Lock()
|
func (cache *Cache) Get(key string) (interface{}, bool) {
|
||||||
defer l.lock.Unlock()
|
cache.lock.RLock()
|
||||||
for _, it := range l.list {
|
defer cache.lock.RUnlock()
|
||||||
if filter(it.i) {
|
|
||||||
it.lastAccess = time.Now().Unix()
|
e, ok := cache.cache[key]
|
||||||
return true
|
|
||||||
}
|
if ok && e.expiry != nil && e.expiry.After(time.Now()) {
|
||||||
|
return e.value, true
|
||||||
}
|
}
|
||||||
return false
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add - add key/value in cache
|
||||||
|
func (cache *Cache) Add(key string, value interface{}, ttl time.Duration) {
|
||||||
|
cache.lock.Lock()
|
||||||
|
defer cache.lock.Unlock()
|
||||||
|
|
||||||
|
expiry := time.Now().Add(ttl)
|
||||||
|
|
||||||
|
cache.cache[key] = &entry{
|
||||||
|
value: value,
|
||||||
|
expiry: &expiry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeys - return all keys of cache map
|
||||||
|
func (cache *Cache) GetKeys() []interface{} {
|
||||||
|
cache.lock.RLock()
|
||||||
|
defer cache.lock.RUnlock()
|
||||||
|
|
||||||
|
keys := make([]interface{}, len(cache.cache))
|
||||||
|
var i int
|
||||||
|
for k := range cache.cache {
|
||||||
|
keys[i] = k
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return keys
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user