mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 07:40:56 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			133 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
						|
 | 
						|
package counters
 | 
						|
 | 
						|
import (
 | 
						|
	"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
 | 
						|
)
 | 
						|
 | 
						|
const spanMaxValue = 10_000_000
 | 
						|
const maxSpans = 10
 | 
						|
 | 
						|
type Item[T SupportedUIntType] struct {
 | 
						|
	spans          [maxSpans + 1]T
 | 
						|
	lastUpdateTime int64
 | 
						|
	lifeSeconds    int64
 | 
						|
	spanSeconds    int64
 | 
						|
}
 | 
						|
 | 
						|
func NewItem[T SupportedUIntType](lifeSeconds int) Item[T] {
 | 
						|
	if lifeSeconds <= 0 {
 | 
						|
		lifeSeconds = 60
 | 
						|
	}
 | 
						|
	var spanSeconds = lifeSeconds / maxSpans
 | 
						|
	if spanSeconds < 1 {
 | 
						|
		spanSeconds = 1
 | 
						|
	} else if lifeSeconds > maxSpans && lifeSeconds%maxSpans != 0 {
 | 
						|
		spanSeconds++
 | 
						|
	}
 | 
						|
 | 
						|
	return Item[T]{
 | 
						|
		lifeSeconds:    int64(lifeSeconds),
 | 
						|
		spanSeconds:    int64(spanSeconds),
 | 
						|
		lastUpdateTime: fasttime.Now().Unix(),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (this *Item[T]) Increase() (result T) {
 | 
						|
	var currentTime = fasttime.Now().Unix()
 | 
						|
	var currentSpanIndex = this.calculateSpanIndex(currentTime)
 | 
						|
 | 
						|
	// return quickly
 | 
						|
	if this.lastUpdateTime == currentTime {
 | 
						|
		if this.spans[currentSpanIndex] < spanMaxValue {
 | 
						|
			this.spans[currentSpanIndex]++
 | 
						|
		}
 | 
						|
		for _, count := range this.spans {
 | 
						|
			result += count
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if this.lastUpdateTime > 0 {
 | 
						|
		if currentTime-this.lastUpdateTime > this.lifeSeconds {
 | 
						|
			for index := range this.spans {
 | 
						|
				this.spans[index] = 0
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			var lastSpanIndex = this.calculateSpanIndex(this.lastUpdateTime)
 | 
						|
 | 
						|
			if lastSpanIndex != currentSpanIndex {
 | 
						|
				var countSpans = len(this.spans)
 | 
						|
 | 
						|
				// reset values between LAST and CURRENT
 | 
						|
				for index := lastSpanIndex + 1; ; index++ {
 | 
						|
					var realIndex = index % countSpans
 | 
						|
					this.spans[realIndex] = 0
 | 
						|
					if realIndex == currentSpanIndex {
 | 
						|
						break
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if this.spans[currentSpanIndex] < spanMaxValue {
 | 
						|
		this.spans[currentSpanIndex]++
 | 
						|
	}
 | 
						|
	this.lastUpdateTime = currentTime
 | 
						|
 | 
						|
	for _, count := range this.spans {
 | 
						|
		result += count
 | 
						|
	}
 | 
						|
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func (this *Item[T]) Sum() (result T) {
 | 
						|
	if this.lastUpdateTime == 0 {
 | 
						|
		return 0
 | 
						|
	}
 | 
						|
 | 
						|
	var currentTime = fasttime.Now().Unix()
 | 
						|
	var currentSpanIndex = this.calculateSpanIndex(currentTime)
 | 
						|
 | 
						|
	if currentTime-this.lastUpdateTime > this.lifeSeconds {
 | 
						|
		return 0
 | 
						|
	} else {
 | 
						|
		var lastSpanIndex = this.calculateSpanIndex(this.lastUpdateTime)
 | 
						|
		var countSpans = len(this.spans)
 | 
						|
		for index := currentSpanIndex + 1; ; index++ {
 | 
						|
			var realIndex = index % countSpans
 | 
						|
			result += this.spans[realIndex]
 | 
						|
			if realIndex == lastSpanIndex {
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return result
 | 
						|
}
 | 
						|
 | 
						|
func (this *Item[T]) Reset() {
 | 
						|
	for index := range this.spans {
 | 
						|
		this.spans[index] = 0
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (this *Item[T]) IsExpired(currentTime int64) bool {
 | 
						|
	return this.lastUpdateTime < currentTime-this.lifeSeconds-this.spanSeconds
 | 
						|
}
 | 
						|
 | 
						|
func (this *Item[T]) calculateSpanIndex(timestamp int64) int {
 | 
						|
	var index = int(timestamp % this.lifeSeconds / this.spanSeconds)
 | 
						|
	if index > maxSpans-1 {
 | 
						|
		return maxSpans - 1
 | 
						|
	}
 | 
						|
	return index
 | 
						|
}
 | 
						|
 | 
						|
func (this *Item[T]) IsOk() bool {
 | 
						|
	return this.lifeSeconds > 0
 | 
						|
}
 |