Merge branch 'develop'
This commit is contained in:
commit
d0b3f197c5
|
@ -0,0 +1,142 @@
|
|||
package task
|
||||
|
||||
import "time"
|
||||
|
||||
// Cond 创建任务条件
|
||||
func Cond(k, v any) Condition {
|
||||
return map[any]any{k: v}
|
||||
}
|
||||
|
||||
// Condition 任务条件
|
||||
type Condition map[any]any
|
||||
|
||||
// Cond 创建任务条件
|
||||
func (slf Condition) Cond(k, v any) Condition {
|
||||
slf[k] = v
|
||||
return slf
|
||||
}
|
||||
|
||||
// GetString 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetString(key any) string {
|
||||
v, _ := slf[key].(string)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetInt 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetInt(key any) int {
|
||||
v, _ := slf[key].(int)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetInt8 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetInt8(key any) int8 {
|
||||
v, _ := slf[key].(int8)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetInt16 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetInt16(key any) int16 {
|
||||
v, _ := slf[key].(int16)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetInt32 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetInt32(key any) int32 {
|
||||
v, _ := slf[key].(int32)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetInt64 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetInt64(key any) int64 {
|
||||
v, _ := slf[key].(int64)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetUint 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetUint(key any) uint {
|
||||
v, _ := slf[key].(uint)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetUint8 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetUint8(key any) uint8 {
|
||||
v, _ := slf[key].(uint8)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetUint16 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetUint16(key any) uint16 {
|
||||
v, _ := slf[key].(uint16)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetUint32 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetUint32(key any) uint32 {
|
||||
v, _ := slf[key].(uint32)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetUint64 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetUint64(key any) uint64 {
|
||||
v, _ := slf[key].(uint64)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetFloat32 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetFloat32(key any) float32 {
|
||||
v, _ := slf[key].(float32)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetFloat64 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetFloat64(key any) float64 {
|
||||
v, _ := slf[key].(float64)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetBool 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetBool(key any) bool {
|
||||
v, _ := slf[key].(bool)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetTime 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetTime(key any) time.Time {
|
||||
v, _ := slf[key].(time.Time)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetDuration 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetDuration(key any) time.Duration {
|
||||
v, _ := slf[key].(time.Duration)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetByte 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetByte(key any) byte {
|
||||
v, _ := slf[key].(byte)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetBytes 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetBytes(key any) []byte {
|
||||
v, _ := slf[key].([]byte)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetRune 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetRune(key any) rune {
|
||||
v, _ := slf[key].(rune)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetRunes 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetRunes(key any) []rune {
|
||||
v, _ := slf[key].([]rune)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetAny 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
func (slf Condition) GetAny(key any) any {
|
||||
return slf[key]
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package task
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrTaskNotFinish 任务未完成
|
||||
ErrTaskNotFinish = errors.New("task not finish")
|
||||
// ErrTaskRewardReceived 任务奖励已领取
|
||||
ErrTaskRewardReceived = errors.New("task reward received")
|
||||
// ErrTaskNotStart 任务未开始
|
||||
ErrTaskNotStart = errors.New("task not start")
|
||||
// ErrTaskFail 任务失败
|
||||
ErrTaskFail = errors.New("task fail")
|
||||
)
|
|
@ -1,35 +1,77 @@
|
|||
package task
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type (
|
||||
RefreshTaskCountEvent func(taskType int, increase int64)
|
||||
RefreshTaskChildCountEvent func(taskType int, key any, increase int64)
|
||||
RefreshTaskCounterEventHandler[Trigger any] func(taskType string, trigger Trigger, count int64) // 刷新任务计数器事件处理函数
|
||||
RefreshTaskConditionEventHandler[Trigger any] func(taskType string, trigger Trigger, condition Condition) // 刷新任务条件事件处理函数
|
||||
)
|
||||
|
||||
var (
|
||||
refreshTaskCountEventHandles = make(map[int]RefreshTaskCountEvent)
|
||||
refreshTaskChildCountEventHandles = make(map[int]RefreshTaskChildCountEvent)
|
||||
refreshTaskCounterEventHandlers = make(map[string][]struct {
|
||||
t reflect.Type
|
||||
h func(taskType string, trigger any, count int64)
|
||||
})
|
||||
refreshTaskConditionEventHandlers = make(map[string][]struct {
|
||||
t reflect.Type
|
||||
h func(taskType string, trigger any, condition Condition)
|
||||
})
|
||||
)
|
||||
|
||||
// RegRefreshTaskCount 注册任务计数刷新事件
|
||||
func RegRefreshTaskCount(taskType int, handler RefreshTaskCountEvent) {
|
||||
refreshTaskCountEventHandles[taskType] = handler
|
||||
// RegisterRefreshTaskCounterEvent 注册特定任务类型的刷新任务计数器事件处理函数
|
||||
func RegisterRefreshTaskCounterEvent[Trigger any](taskType string, handler RefreshTaskCounterEventHandler[Trigger]) {
|
||||
if refreshTaskCounterEventHandlers == nil {
|
||||
refreshTaskCounterEventHandlers = make(map[string][]struct {
|
||||
t reflect.Type
|
||||
h func(taskType string, trigger any, count int64)
|
||||
})
|
||||
}
|
||||
refreshTaskCounterEventHandlers[taskType] = append(refreshTaskCounterEventHandlers[taskType], struct {
|
||||
t reflect.Type
|
||||
h func(taskType string, trigger any, count int64)
|
||||
}{reflect.TypeOf(handler).In(1), func(taskType string, trigger any, count int64) {
|
||||
handler(taskType, trigger.(Trigger), count)
|
||||
}})
|
||||
}
|
||||
|
||||
// OnRefreshTaskCount 触发任务计数刷新事件
|
||||
func OnRefreshTaskCount(taskType int, increase int64) {
|
||||
if handler, ok := refreshTaskCountEventHandles[taskType]; ok {
|
||||
handler(taskType, increase)
|
||||
// OnRefreshTaskCounterEvent 触发特定任务类型的刷新任务计数器事件
|
||||
func OnRefreshTaskCounterEvent(taskType string, trigger any, count int64) {
|
||||
if handlers, exist := refreshTaskCounterEventHandlers[taskType]; exist {
|
||||
for _, handler := range handlers {
|
||||
if !reflect.TypeOf(trigger).AssignableTo(handler.t) {
|
||||
continue
|
||||
}
|
||||
handler.h(taskType, trigger, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RegRefreshTaskChildCount 注册任务子计数刷新事件
|
||||
func RegRefreshTaskChildCount(taskType int, handler RefreshTaskChildCountEvent) {
|
||||
refreshTaskChildCountEventHandles[taskType] = handler
|
||||
// RegisterRefreshTaskConditionEvent 注册特定任务类型的刷新任务条件事件处理函数
|
||||
func RegisterRefreshTaskConditionEvent[Trigger any](taskType string, handler RefreshTaskConditionEventHandler[Trigger]) {
|
||||
if refreshTaskConditionEventHandlers == nil {
|
||||
refreshTaskConditionEventHandlers = make(map[string][]struct {
|
||||
t reflect.Type
|
||||
h func(taskType string, trigger any, condition Condition)
|
||||
})
|
||||
}
|
||||
refreshTaskConditionEventHandlers[taskType] = append(refreshTaskConditionEventHandlers[taskType], struct {
|
||||
t reflect.Type
|
||||
h func(taskType string, trigger any, condition Condition)
|
||||
}{reflect.TypeOf(handler).In(1), func(taskType string, trigger any, condition Condition) {
|
||||
handler(taskType, trigger.(Trigger), condition)
|
||||
}})
|
||||
}
|
||||
|
||||
// OnRefreshTaskChildCount 触发任务子计数刷新事件
|
||||
func OnRefreshTaskChildCount(taskType int, key any, increase int64) {
|
||||
if handler, ok := refreshTaskChildCountEventHandles[taskType]; ok {
|
||||
handler(taskType, key, increase)
|
||||
// OnRefreshTaskConditionEvent 触发特定任务类型的刷新任务条件事件
|
||||
func OnRefreshTaskConditionEvent(taskType string, trigger any, condition Condition) {
|
||||
if handlers, exist := refreshTaskConditionEventHandlers[taskType]; exist {
|
||||
for _, handler := range handlers {
|
||||
if !reflect.TypeOf(trigger).AssignableTo(handler.t) {
|
||||
continue
|
||||
}
|
||||
handler.h(taskType, trigger, condition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,85 +1,82 @@
|
|||
package task
|
||||
|
||||
import (
|
||||
"github.com/kercylan98/minotaur/utils/offset"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Option 任务选项
|
||||
type Option func(task *Task)
|
||||
|
||||
// WithChildCount 通过初始化子计数的方式创建任务
|
||||
func WithChildCount(key any, childCount int64) Option {
|
||||
// WithType 设置任务类型
|
||||
func WithType(taskType string) Option {
|
||||
return func(task *Task) {
|
||||
if task.childCount == nil {
|
||||
task.childCount = make(map[any]int64)
|
||||
task.Type = taskType
|
||||
}
|
||||
}
|
||||
|
||||
// WithCondition 设置任务完成条件,当满足条件时,任务状态为完成
|
||||
// - 任务条件值需要变更时可通过 Task.AssignConditionValueAndRefresh 方法变更
|
||||
// - 当多次设置该选项时,后面的设置会覆盖之前的设置
|
||||
func WithCondition(condition Condition) Option {
|
||||
return func(task *Task) {
|
||||
if condition == nil {
|
||||
return
|
||||
}
|
||||
if task.childCondition == nil {
|
||||
task.childCondition = make(map[any]int64)
|
||||
if task.Cond == nil {
|
||||
task.Cond = condition
|
||||
return
|
||||
}
|
||||
task.childCount[key] = childCount
|
||||
}
|
||||
}
|
||||
|
||||
// WithChild 通过指定子计数的方式创建任务
|
||||
// - 只有当子计数与主计数均达到条件时,任务才会完成
|
||||
// - 通常用于多条件的任务
|
||||
func WithChild(key any, childCondition int64) Option {
|
||||
return func(task *Task) {
|
||||
if task.childCount == nil {
|
||||
task.childCount = make(map[any]int64)
|
||||
}
|
||||
if task.childCondition == nil {
|
||||
task.childCondition = make(map[any]int64)
|
||||
}
|
||||
task.childCondition[key] = childCondition
|
||||
}
|
||||
}
|
||||
|
||||
// WithDisableNotStartGetReward 禁止未开始的任务领取奖励
|
||||
func WithDisableNotStartGetReward() Option {
|
||||
return func(task *Task) {
|
||||
task.disableNotStartGetReward = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCount 通过初始化计数的方式创建任务
|
||||
func WithCount(count int64) Option {
|
||||
return func(task *Task) {
|
||||
task.SetCount(count)
|
||||
}
|
||||
}
|
||||
|
||||
// WithStartTime 通过指定开始时间的方式创建任务
|
||||
// - 只有当时间在开始时间之后,任务才会开始计数
|
||||
func WithStartTime(startTime time.Time) Option {
|
||||
return func(task *Task) {
|
||||
task.start = startTime
|
||||
}
|
||||
}
|
||||
|
||||
// WithOffsetTime 通过指定偏移时间的方式创建任务
|
||||
func WithOffsetTime(offset *offset.Time) Option {
|
||||
return func(task *Task) {
|
||||
task.offset = offset
|
||||
}
|
||||
}
|
||||
|
||||
// WithLimitedTime 通过限时的方式创建任务
|
||||
func WithLimitedTime(limitTime time.Duration) Option {
|
||||
return func(task *Task) {
|
||||
task.limitTime = limitTime
|
||||
}
|
||||
}
|
||||
|
||||
// WithFront 通过指定任务前置任务的方式创建任务
|
||||
// - 当前置任务未完成时,当前任务不会开始计数
|
||||
func WithFront(fronts ...*Task) Option {
|
||||
return func(task *Task) {
|
||||
if task.fronts == nil {
|
||||
task.fronts = make(map[int64]*Task)
|
||||
}
|
||||
for _, front := range fronts {
|
||||
task.fronts[front.GetID()] = front
|
||||
for k, v := range condition {
|
||||
task.Cond[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithCounter 设置任务计数器,当计数器达到要求时,任务状态为完成
|
||||
// - 一些场景下,任务计数器可能会溢出,此时可通过 WithOverflowCounter 设置可溢出的任务计数器
|
||||
// - 当多次设置该选项时,后面的设置会覆盖之前的设置
|
||||
// - 如果需要初始化计数器的值,可通过 initCount 参数设置
|
||||
func WithCounter(counter int64, initCount ...int64) Option {
|
||||
return func(task *Task) {
|
||||
task.Counter = counter
|
||||
if len(initCount) > 0 {
|
||||
task.CurrCount = initCount[0]
|
||||
if task.CurrCount < 0 {
|
||||
task.CurrCount = 0
|
||||
} else if task.CurrCount > task.Counter {
|
||||
task.CurrCount = task.Counter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithOverflowCounter 设置可溢出的任务计数器,当计数器达到要求时,任务状态为完成
|
||||
// - 当多次设置该选项时,后面的设置会覆盖之前的设置
|
||||
// - 如果需要初始化计数器的值,可通过 initCount 参数设置
|
||||
func WithOverflowCounter(counter int64, initCount ...int64) Option {
|
||||
return func(task *Task) {
|
||||
task.Counter = counter
|
||||
task.CurrOverflow = true
|
||||
if len(initCount) > 0 {
|
||||
task.CurrCount = initCount[0]
|
||||
if task.CurrCount < 0 {
|
||||
task.CurrCount = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithDeadline 设置任务截止时间,超过截至时间并且任务未完成时,任务状态为失败
|
||||
func WithDeadline(deadline time.Time) Option {
|
||||
return func(task *Task) {
|
||||
task.Deadline = deadline
|
||||
}
|
||||
}
|
||||
|
||||
// WithLimitedDuration 设置任务限时,超过限时时间并且任务未完成时,任务状态为失败
|
||||
func WithLimitedDuration(start time.Time, duration time.Duration) Option {
|
||||
return func(task *Task) {
|
||||
task.StartTime = start
|
||||
task.LimitedDuration = duration
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package task
|
||||
|
||||
const (
|
||||
StateAccept State = iota + 1 // 已接受
|
||||
StateFinish // 已完成
|
||||
StateReward // 已领取
|
||||
StateFail // 已失败
|
||||
)
|
||||
|
||||
type State uint16
|
|
@ -0,0 +1,23 @@
|
|||
package task
|
||||
|
||||
const (
|
||||
StatusAccept Status = iota + 1 // 已接受
|
||||
StatusFailed // 已失败
|
||||
StatusComplete // 已完成
|
||||
StatusReward // 已领取奖励
|
||||
)
|
||||
|
||||
var (
|
||||
statusFormat = map[Status]string{
|
||||
StatusAccept: "Accept",
|
||||
StatusComplete: "Complete",
|
||||
StatusReward: "Reward",
|
||||
StatusFailed: "Failed",
|
||||
}
|
||||
)
|
||||
|
||||
type Status byte
|
||||
|
||||
func (slf Status) String() string {
|
||||
return statusFormat[slf]
|
||||
}
|
|
@ -1,207 +1,152 @@
|
|||
package task
|
||||
|
||||
import (
|
||||
"github.com/kercylan98/minotaur/utils/hash"
|
||||
"github.com/kercylan98/minotaur/utils/offset"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewTask 创建任务
|
||||
func NewTask(id int64, taskType int, condition int64, options ...Option) *Task {
|
||||
task := &Task{
|
||||
id: id,
|
||||
taskType: taskType,
|
||||
condition: condition,
|
||||
state: StateAccept,
|
||||
}
|
||||
// NewTask 生成任务
|
||||
func NewTask(options ...Option) *Task {
|
||||
task := new(Task)
|
||||
for _, option := range options {
|
||||
option(task)
|
||||
}
|
||||
if task.start.IsZero() {
|
||||
if task.offset != nil {
|
||||
task.start = task.offset.Now()
|
||||
} else {
|
||||
task.start = time.Now()
|
||||
}
|
||||
}
|
||||
for key := range task.childCount {
|
||||
if !hash.Exist(task.childCondition, key) {
|
||||
delete(task.childCount, key)
|
||||
}
|
||||
}
|
||||
if task.count == task.condition {
|
||||
task.state = StateFinish
|
||||
}
|
||||
return task
|
||||
return task.refreshTaskStatus()
|
||||
}
|
||||
|
||||
// Task 通用任务数据结构
|
||||
// Task 是对任务信息进行描述和处理的结构体
|
||||
type Task struct {
|
||||
id int64 // 任务ID
|
||||
taskType int // 任务类型
|
||||
count int64 // 任务主计数
|
||||
condition int64 // 任务完成需要的计数条件
|
||||
childCount map[any]int64 // 任务子计数
|
||||
childCondition map[any]int64 // 任务子计数条件
|
||||
state State // 任务状态
|
||||
start time.Time // 任务开始时间
|
||||
limitTime time.Duration // 任务限时
|
||||
fronts map[int64]*Task // 任务前置任务
|
||||
disableNotStartGetReward bool // 禁止未开始的任务领取奖励
|
||||
|
||||
offset *offset.Time // 任务偏移时间
|
||||
Type string `json:"type,omitempty"` // 任务类型
|
||||
Status Status `json:"status,omitempty"` // 任务状态
|
||||
Cond Condition `json:"cond,omitempty"` // 任务条件
|
||||
CondValue map[any]any `json:"cond_value,omitempty"` // 任务条件值
|
||||
Counter int64 `json:"counter,omitempty"` // 任务要求计数器
|
||||
CurrCount int64 `json:"curr_count,omitempty"` // 任务当前计数
|
||||
CurrOverflow bool `json:"curr_overflow,omitempty"` // 任务当前计数是否允许溢出
|
||||
Deadline time.Time `json:"deadline,omitempty"` // 任务截止时间
|
||||
StartTime time.Time `json:"start_time,omitempty"` // 任务开始时间
|
||||
LimitedDuration time.Duration `json:"limited_duration,omitempty"` // 任务限时
|
||||
}
|
||||
|
||||
// GetID 获取任务ID
|
||||
func (slf *Task) GetID() int64 {
|
||||
return slf.id
|
||||
// IsComplete 判断任务是否已完成
|
||||
func (slf *Task) IsComplete() bool {
|
||||
return slf.Status == StatusComplete
|
||||
}
|
||||
|
||||
// GetType 获取任务类型
|
||||
func (slf *Task) GetType() int {
|
||||
return slf.taskType
|
||||
// IsFailed 判断任务是否已失败
|
||||
func (slf *Task) IsFailed() bool {
|
||||
return slf.Status == StatusFailed
|
||||
}
|
||||
|
||||
// Reset 重置任务
|
||||
func (slf *Task) Reset() {
|
||||
slf.count = 0
|
||||
slf.state = StateAccept
|
||||
for key := range slf.childCount {
|
||||
delete(slf.childCount, key)
|
||||
}
|
||||
}
|
||||
|
||||
// GetFronts 获取前置任务
|
||||
func (slf *Task) GetFronts() map[int64]*Task {
|
||||
return slf.fronts
|
||||
}
|
||||
|
||||
// GetFrontsWithState 获取特定状态的前置任务
|
||||
func (slf *Task) GetFrontsWithState(state State) map[int64]*Task {
|
||||
fronts := make(map[int64]*Task)
|
||||
for id, front := range slf.fronts {
|
||||
if front.GetState() == state {
|
||||
fronts[id] = front
|
||||
}
|
||||
}
|
||||
return fronts
|
||||
}
|
||||
|
||||
// FrontsIsFinish 判断前置任务是否完成
|
||||
func (slf *Task) FrontsIsFinish() bool {
|
||||
for _, front := range slf.fronts {
|
||||
state := front.GetState()
|
||||
if state == StateAccept || state == StateFail {
|
||||
return false
|
||||
}
|
||||
// IsReward 判断任务是否已领取奖励
|
||||
func (slf *Task) IsReward() bool {
|
||||
return slf.Status == StatusReward
|
||||
}
|
||||
|
||||
// ReceiveReward 领取任务奖励,当任务状态为已完成时,才能领取奖励,此时返回 true,并且任务状态变更为已领取奖励
|
||||
func (slf *Task) ReceiveReward() bool {
|
||||
if slf.Status != StatusComplete {
|
||||
return false
|
||||
}
|
||||
slf.Status = StatusReward
|
||||
return true
|
||||
}
|
||||
|
||||
// GetReward 获取任务奖励
|
||||
// - 当任务状态为 StateFinish 时,调用 rewardHandle 函数
|
||||
// - 当任务状态不为 StateFinish 或奖励函数发生错误时,返回错误
|
||||
func (slf *Task) GetReward(rewardHandle func() error) error {
|
||||
if !slf.IsStart() {
|
||||
return ErrTaskNotStart
|
||||
// IncrementCounter 增加计数器的值,当 incr 为负数时,计数器的值不会发生变化
|
||||
// - 如果需要溢出计数器,可通过 WithOverflowCounter 设置可溢出的任务计数器
|
||||
func (slf *Task) IncrementCounter(incr int64) *Task {
|
||||
if incr < 0 {
|
||||
return slf
|
||||
}
|
||||
switch slf.GetState() {
|
||||
case StateAccept:
|
||||
return ErrTaskNotFinish
|
||||
case StateReward:
|
||||
return ErrTaskRewardReceived
|
||||
case StateFail:
|
||||
return ErrTaskFail
|
||||
slf.CurrCount += incr
|
||||
if !slf.CurrOverflow && slf.CurrCount > slf.Counter {
|
||||
slf.CurrCount = slf.Counter
|
||||
}
|
||||
if err := rewardHandle(); err != nil {
|
||||
return err
|
||||
}
|
||||
slf.state = StateReward
|
||||
return nil
|
||||
return slf.refreshTaskStatus()
|
||||
}
|
||||
|
||||
// GetState 获取任务状态
|
||||
func (slf *Task) GetState() State {
|
||||
return slf.state
|
||||
}
|
||||
|
||||
// IsStart 判断任务是否开始
|
||||
func (slf *Task) IsStart() bool {
|
||||
var current time.Time
|
||||
if slf.offset != nil {
|
||||
current = slf.offset.Now()
|
||||
} else {
|
||||
current = time.Now()
|
||||
// DecrementCounter 减少计数器的值,当 decr 为负数时,计数器的值不会发生变化
|
||||
func (slf *Task) DecrementCounter(decr int64) *Task {
|
||||
if decr < 0 {
|
||||
return slf
|
||||
}
|
||||
if current.Before(slf.start) {
|
||||
return false
|
||||
} else if slf.limitTime > 0 && current.Sub(slf.start) >= slf.limitTime {
|
||||
return false
|
||||
slf.CurrCount -= decr
|
||||
if slf.CurrCount < 0 {
|
||||
slf.CurrCount = 0
|
||||
}
|
||||
return true
|
||||
return slf.refreshTaskStatus()
|
||||
}
|
||||
|
||||
// SetCount 设置计数
|
||||
func (slf *Task) SetCount(count int64) {
|
||||
if !slf.IsStart() || !slf.FrontsIsFinish() {
|
||||
return
|
||||
// AssignConditionValueAndRefresh 分配条件值并刷新任务状态
|
||||
func (slf *Task) AssignConditionValueAndRefresh(key, value any) *Task {
|
||||
if slf.Cond == nil {
|
||||
return slf
|
||||
}
|
||||
slf.count = count
|
||||
if slf.count >= slf.condition {
|
||||
slf.count = slf.condition
|
||||
} else if slf.count < 0 {
|
||||
slf.count = 0
|
||||
if _, exist := slf.Cond[key]; !exist {
|
||||
return slf
|
||||
}
|
||||
slf.refreshState()
|
||||
}
|
||||
|
||||
// AddCount 增加计数
|
||||
func (slf *Task) AddCount(count int64) {
|
||||
slf.SetCount(slf.count + count)
|
||||
}
|
||||
|
||||
// GetCount 获取计数
|
||||
func (slf *Task) GetCount() int64 {
|
||||
return slf.count
|
||||
}
|
||||
|
||||
// GetCondition 获取计数条件
|
||||
func (slf *Task) GetCondition() int64 {
|
||||
return slf.condition
|
||||
}
|
||||
|
||||
// SetChildCount 设置子计数
|
||||
func (slf *Task) SetChildCount(key any, count int64) {
|
||||
if !slf.IsStart() || !slf.FrontsIsFinish() || !hash.Exist(slf.childCondition, key) {
|
||||
return
|
||||
if slf.CondValue == nil {
|
||||
slf.CondValue = make(map[any]any)
|
||||
}
|
||||
if condition := slf.childCondition[key]; count > condition {
|
||||
count = condition
|
||||
} else if count < 0 {
|
||||
count = 0
|
||||
}
|
||||
slf.childCount[key] = count
|
||||
slf.refreshState()
|
||||
OnRefreshTaskCount(slf.taskType, count)
|
||||
slf.CondValue[key] = value
|
||||
return slf.refreshTaskStatus()
|
||||
}
|
||||
|
||||
// AddChildCount 增加子计数
|
||||
func (slf *Task) AddChildCount(key any, count int64) {
|
||||
slf.SetChildCount(key, slf.childCount[key]+count)
|
||||
OnRefreshTaskChildCount(slf.taskType, key, count)
|
||||
// AssignConditionValueAndRefreshByCondition 分配条件值并刷新任务状态
|
||||
func (slf *Task) AssignConditionValueAndRefreshByCondition(condition Condition) *Task {
|
||||
if slf.Cond == nil {
|
||||
return slf
|
||||
}
|
||||
if slf.CondValue == nil {
|
||||
slf.CondValue = make(map[any]any)
|
||||
}
|
||||
for k, v := range condition {
|
||||
if _, exist := slf.Cond[k]; !exist {
|
||||
continue
|
||||
}
|
||||
slf.CondValue[k] = v
|
||||
}
|
||||
return slf.refreshTaskStatus()
|
||||
}
|
||||
|
||||
// refreshState 刷新任务状态
|
||||
func (slf *Task) refreshState() {
|
||||
slf.state = StateFinish
|
||||
if slf.count != slf.condition {
|
||||
slf.state = StateAccept
|
||||
return
|
||||
// ResetStatus 重置任务状态
|
||||
// - 该函数会将任务状态重置为已接受状态后,再刷新任务状态
|
||||
// - 当任务条件变更,例如任务计数要求为 10,已经完成的情况下,将任务计数要求变更为 5 或 20,此时任务状态由于是已完成或已领取状态,不会自动刷新,需要调用该函数刷新任务状态
|
||||
func (slf *Task) ResetStatus() *Task {
|
||||
slf.Status = StatusAccept
|
||||
return slf.refreshTaskStatus()
|
||||
}
|
||||
|
||||
// refreshTaskStatus 刷新任务状态
|
||||
func (slf *Task) refreshTaskStatus() *Task {
|
||||
curr := time.Now()
|
||||
if (!slf.StartTime.IsZero() && curr.Before(slf.StartTime)) || (!slf.Deadline.IsZero() && curr.After(slf.Deadline)) || slf.Status >= StatusComplete {
|
||||
return slf
|
||||
}
|
||||
for key, condition := range slf.childCondition {
|
||||
if slf.childCount[key] != condition {
|
||||
slf.state = StateAccept
|
||||
return
|
||||
slf.Status = StatusComplete
|
||||
|
||||
if slf.Counter > 0 && slf.CurrCount < slf.Counter {
|
||||
slf.Status = StatusAccept
|
||||
return slf
|
||||
}
|
||||
if slf.Cond != nil {
|
||||
for k, v := range slf.Cond {
|
||||
if v != slf.CondValue[k] {
|
||||
slf.Status = StatusAccept
|
||||
return slf
|
||||
}
|
||||
}
|
||||
}
|
||||
if !slf.Deadline.IsZero() && slf.Status == StatusAccept {
|
||||
if slf.Deadline.After(curr) {
|
||||
slf.Status = StatusFailed
|
||||
return slf
|
||||
}
|
||||
}
|
||||
if slf.LimitedDuration > 0 && slf.Status == StatusAccept {
|
||||
if curr.Sub(slf.StartTime) > slf.LimitedDuration {
|
||||
slf.Status = StatusFailed
|
||||
return slf
|
||||
}
|
||||
}
|
||||
return slf
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package task
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type Player struct {
|
||||
tasks map[string][]*Task
|
||||
}
|
||||
|
||||
type Monster struct {
|
||||
}
|
||||
|
||||
func TestCond(t *testing.T) {
|
||||
task := NewTask(WithType("T"), WithCounter(5), WithCondition(Cond("N", 5).Cond("M", 10)))
|
||||
task.AssignConditionValueAndRefresh("N", 5)
|
||||
task.AssignConditionValueAndRefresh("M", 10)
|
||||
|
||||
RegisterRefreshTaskCounterEvent[*Player](task.Type, func(taskType string, trigger *Player, count int64) {
|
||||
fmt.Println("Player", count)
|
||||
for _, t := range trigger.tasks[taskType] {
|
||||
fmt.Println(t.CurrCount, t.IncrementCounter(count).Status)
|
||||
}
|
||||
})
|
||||
|
||||
RegisterRefreshTaskConditionEvent[*Player](task.Type, func(taskType string, trigger *Player, condition Condition) {
|
||||
fmt.Println("Player", condition)
|
||||
for _, t := range trigger.tasks[taskType] {
|
||||
fmt.Println(t.CurrCount, t.AssignConditionValueAndRefresh("N", 5).Status)
|
||||
}
|
||||
})
|
||||
|
||||
RegisterRefreshTaskCounterEvent[*Monster](task.Type, func(taskType string, trigger *Monster, count int64) {
|
||||
fmt.Println("Monster", count)
|
||||
})
|
||||
|
||||
player := &Player{
|
||||
tasks: map[string][]*Task{
|
||||
task.Type: []*Task{task},
|
||||
},
|
||||
}
|
||||
OnRefreshTaskCounterEvent(task.Type, player, 1)
|
||||
OnRefreshTaskCounterEvent(task.Type, player, 2)
|
||||
OnRefreshTaskCounterEvent(task.Type, player, 3)
|
||||
OnRefreshTaskCounterEvent(task.Type, new(Monster), 3)
|
||||
|
||||
}
|
10
go.mod
10
go.mod
|
@ -11,7 +11,7 @@ require (
|
|||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||
github.com/nats-io/nats.go v1.30.2
|
||||
github.com/nats-io/nats.go v1.31.0
|
||||
github.com/panjf2000/ants/v2 v2.8.1
|
||||
github.com/panjf2000/gnet v1.6.7
|
||||
github.com/smartystreets/goconvey v1.8.1
|
||||
|
@ -21,7 +21,7 @@ require (
|
|||
github.com/xtaci/kcp-go/v5 v5.6.3
|
||||
go.uber.org/atomic v1.10.0
|
||||
go.uber.org/zap v1.25.0
|
||||
golang.org/x/time v0.3.0
|
||||
golang.org/x/time v0.4.0
|
||||
google.golang.org/grpc v1.59.0
|
||||
)
|
||||
|
||||
|
@ -49,8 +49,8 @@ require (
|
|||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.5.2 // indirect
|
||||
github.com/nats-io/nats-server/v2 v2.10.3 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.5.3 // indirect
|
||||
github.com/nats-io/nats-server/v2 v2.10.4 // indirect
|
||||
github.com/nats-io/nkeys v0.4.6 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
|
@ -72,7 +72,7 @@ require (
|
|||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||
|
|
9
go.sum
9
go.sum
|
@ -125,13 +125,18 @@ github.com/nats-io/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4=
|
|||
github.com/nats-io/jwt/v2 v2.4.1/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
|
||||
github.com/nats-io/jwt/v2 v2.5.2 h1:DhGH+nKt+wIkDxM6qnVSKjokq5t59AZV5HRcFW0zJwU=
|
||||
github.com/nats-io/jwt/v2 v2.5.2/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
|
||||
github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo=
|
||||
github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4=
|
||||
github.com/nats-io/nats-server/v2 v2.9.16 h1:SuNe6AyCcVy0g5326wtyU8TdqYmcPqzTjhkHojAjprc=
|
||||
github.com/nats-io/nats-server/v2 v2.9.16/go.mod h1:z1cc5Q+kqJkz9mLUdlcSsdYnId4pyImHjNgoh6zxSC0=
|
||||
github.com/nats-io/nats-server/v2 v2.10.3 h1:nk2QVLpJUh3/AhZCJlQdTfj2oeLDvWnn1Z6XzGlNFm0=
|
||||
github.com/nats-io/nats-server/v2 v2.10.3/go.mod h1:lzrskZ/4gyMAh+/66cCd+q74c6v7muBypzfWhP/MAaM=
|
||||
github.com/nats-io/nats-server/v2 v2.10.4 h1:uB9xcwon3tPXWAdmTJqqqC6cie3yuPWHJjjTBgaPNus=
|
||||
github.com/nats-io/nats-server/v2 v2.10.4/go.mod h1:eWm2JmHP9Lqm2oemB6/XGi0/GwsZwtWf8HIPUsh+9ns=
|
||||
github.com/nats-io/nats.go v1.28.0 h1:Th4G6zdsz2d0OqXdfzKLClo6bOfoI/b1kInhRtFIy5c=
|
||||
github.com/nats-io/nats.go v1.28.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
|
||||
github.com/nats-io/nats.go v1.30.2/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzDHrVBd5qM=
|
||||
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
|
||||
github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
|
||||
github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
|
||||
github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
|
||||
|
@ -289,6 +294,8 @@ golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
|||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
|
@ -303,6 +310,8 @@ golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
|
||||
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package server
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
// NewHttpHandleWrapper 创建一个新的 http 处理程序包装器
|
||||
// - 默认使用 server.HttpContext 作为上下文,如果需要依赖其作为新的上下文,可以通过 NewHttpContext 创建
|
||||
func NewHttpHandleWrapper[Context any](srv *Server, packer ContextPacker[Context]) *Http[Context] {
|
||||
return &Http[Context]{
|
||||
gin: srv.ginServer,
|
||||
HttpRouter: &HttpRouter[Context]{
|
||||
srv: srv,
|
||||
group: srv.ginServer,
|
||||
|
@ -15,5 +18,10 @@ func NewHttpHandleWrapper[Context any](srv *Server, packer ContextPacker[Context
|
|||
// Http 基于 gin.Engine 包装的 http 服务器
|
||||
type Http[Context any] struct {
|
||||
srv *Server
|
||||
gin *gin.Engine
|
||||
*HttpRouter[Context]
|
||||
}
|
||||
|
||||
func (slf *Http[Context]) Gin() *gin.Engine {
|
||||
return slf.gin
|
||||
}
|
||||
|
|
|
@ -87,6 +87,13 @@ func (slf *Lockstep[ClientID, Command]) JoinClientWithFrame(client Client[Client
|
|||
|
||||
}
|
||||
|
||||
// GetClientCount 获取客户端数量
|
||||
func (slf *Lockstep[ClientID, Command]) GetClientCount() int {
|
||||
slf.clientLock.RLock()
|
||||
defer slf.clientLock.RUnlock()
|
||||
return len(slf.clients)
|
||||
}
|
||||
|
||||
// DropCache 丢弃特定帧的缓存,当 handler 返回 true 时将丢弃缓存
|
||||
func (slf *Lockstep[ClientID, Command]) DropCache(handler func(frame int64) bool) {
|
||||
slf.frameCacheLock.Lock()
|
||||
|
|
|
@ -748,3 +748,8 @@ func (slf *Server) dispatchMessage(msg *Message) {
|
|||
log.Warn("Server", log.String("not support message type", msg.t.String()))
|
||||
}
|
||||
}
|
||||
|
||||
// PushAsyncMessage 是 PushAsyncMessage 的快捷方式
|
||||
func (slf *Server) PushAsyncMessage(caller func() error, callback func(err error), mark ...any) {
|
||||
PushAsyncMessage(slf, caller, callback, mark...)
|
||||
}
|
||||
|
|
|
@ -34,3 +34,8 @@ type Unsigned interface {
|
|||
type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
|
||||
// Basic 基本类型
|
||||
type Basic interface {
|
||||
Signed | Unsigned | Float | ~string | ~bool | ~byte
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"github.com/tidwall/gjson"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Analyzer 分析器
|
||||
type Analyzer struct {
|
||||
v map[string]float64 // 记录了每个 key 的当前值
|
||||
v map[string]any // 记录了每个 key 的当前值
|
||||
vc map[string]int64 // 记录了每个 key 生效的计数数量
|
||||
repeat map[string]struct{} // 去重信息
|
||||
subs map[string]*Analyzer
|
||||
|
@ -29,7 +30,106 @@ func (slf *Analyzer) Sub(key string) *Analyzer {
|
|||
return sub
|
||||
}
|
||||
|
||||
// SetValueIfGreaterThan 设置指定 key 的值,当新值大于旧值时
|
||||
// - 当已有值不为 float64 时,将会被忽略
|
||||
func (slf *Analyzer) SetValueIfGreaterThan(key string, value float64) {
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
if slf.v == nil {
|
||||
slf.v = make(map[string]any)
|
||||
slf.vc = make(map[string]int64)
|
||||
}
|
||||
v, exist := slf.v[key]
|
||||
if !exist {
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
return
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case float64:
|
||||
if v < value {
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetValueIfLessThan 设置指定 key 的值,当新值小于旧值时
|
||||
// - 当已有值不为 float64 时,将会被忽略
|
||||
func (slf *Analyzer) SetValueIfLessThan(key string, value float64) {
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
if slf.v == nil {
|
||||
slf.v = make(map[string]any)
|
||||
slf.vc = make(map[string]int64)
|
||||
}
|
||||
v, exist := slf.v[key]
|
||||
if !exist {
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
return
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case float64:
|
||||
if v > value {
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetValueIf 当表达式满足的时候将设置指定 key 的值为 value
|
||||
func (slf *Analyzer) SetValueIf(key string, expression bool, value float64) {
|
||||
if !expression {
|
||||
return
|
||||
}
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
}
|
||||
|
||||
// SetValueStringIf 当表达式满足的时候将设置指定 key 的值为 value
|
||||
func (slf *Analyzer) SetValueStringIf(key string, expression bool, value string) {
|
||||
if !expression {
|
||||
return
|
||||
}
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
}
|
||||
|
||||
// SetValue 设置指定 key 的值
|
||||
func (slf *Analyzer) SetValue(key string, value float64) {
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
if slf.v == nil {
|
||||
slf.v = make(map[string]any)
|
||||
slf.vc = make(map[string]int64)
|
||||
}
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
}
|
||||
|
||||
// SetValueString 设置指定 key 的值
|
||||
func (slf *Analyzer) SetValueString(key string, value string) {
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
if slf.v == nil {
|
||||
slf.v = make(map[string]any)
|
||||
slf.vc = make(map[string]int64)
|
||||
}
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
}
|
||||
|
||||
// Increase 在指定 key 现有值的基础上增加 recordKey 的值
|
||||
// - 当分析器已经记录过相同 key 的值时,会根据已有的值类型进行不同处理
|
||||
//
|
||||
// 处理方式:
|
||||
// - 当已有值类型为 string 时,将会使用新的值的 string 类型进行覆盖
|
||||
// - 当已有值类型为 float64 时,当新的值类型不为 float64 时,将会被忽略
|
||||
func (slf *Analyzer) Increase(key string, record R, recordKey string) {
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
|
@ -37,10 +137,31 @@ func (slf *Analyzer) Increase(key string, record R, recordKey string) {
|
|||
return
|
||||
}
|
||||
if slf.v == nil {
|
||||
slf.v = make(map[string]float64)
|
||||
slf.v = make(map[string]any)
|
||||
slf.vc = make(map[string]int64)
|
||||
}
|
||||
slf.v[key] += record.GetFloat64(recordKey)
|
||||
value, exist := slf.v[key]
|
||||
if !exist {
|
||||
result := gjson.Get(string(record), recordKey)
|
||||
switch result.Type {
|
||||
case gjson.String:
|
||||
slf.v[key] = result.String()
|
||||
case gjson.Number:
|
||||
slf.v[key] = result.Float()
|
||||
default:
|
||||
return
|
||||
}
|
||||
slf.vc[key]++
|
||||
return
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
slf.v[key] = record.GetString(recordKey)
|
||||
case float64:
|
||||
slf.v[key] = v + record.GetFloat64(recordKey)
|
||||
default:
|
||||
return
|
||||
}
|
||||
slf.vc[key]++
|
||||
}
|
||||
|
||||
|
@ -49,11 +170,20 @@ func (slf *Analyzer) IncreaseValue(key string, value float64) {
|
|||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
if slf.v == nil {
|
||||
slf.v = make(map[string]float64)
|
||||
slf.v = make(map[string]any)
|
||||
slf.vc = make(map[string]int64)
|
||||
}
|
||||
slf.v[key] += value
|
||||
slf.vc[key]++
|
||||
v, exist := slf.v[key]
|
||||
if !exist {
|
||||
slf.v[key] = value
|
||||
slf.vc[key]++
|
||||
return
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case float64:
|
||||
slf.v[key] = v + value
|
||||
slf.vc[key]++
|
||||
}
|
||||
}
|
||||
|
||||
// IncreaseNonRepeat 在指定 key 现有值的基础上增加 recordKey 的值,但是当去重维度 dimension 相同时,不会增加
|
||||
|
@ -99,3 +229,33 @@ func (slf *Analyzer) IncreaseValueNonRepeat(key string, record R, value float64,
|
|||
slf.m.Unlock()
|
||||
slf.IncreaseValue(key, value)
|
||||
}
|
||||
|
||||
// GetValue 获取当前记录的值
|
||||
func (slf *Analyzer) GetValue(key string) float64 {
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
value, exist := slf.v[key]
|
||||
if !exist {
|
||||
return 0
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case float64:
|
||||
return v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetValueString 获取当前记录的值
|
||||
func (slf *Analyzer) GetValueString(key string) string {
|
||||
slf.m.Lock()
|
||||
defer slf.m.Unlock()
|
||||
value, exist := slf.v[key]
|
||||
if !exist {
|
||||
return ""
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package survey
|
|||
|
||||
import (
|
||||
"github.com/kercylan98/minotaur/utils/super"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newReport(analyzer *Analyzer) *Report {
|
||||
|
@ -23,15 +24,23 @@ func newReport(analyzer *Analyzer) *Report {
|
|||
// Report 分析报告
|
||||
type Report struct {
|
||||
analyzer *Analyzer
|
||||
Name string // 报告名称(默认为 ROOT)
|
||||
Values map[string]float64 `json:"Values,omitempty"`
|
||||
Counter map[string]int64 `json:"Count,omitempty"`
|
||||
Subs []*Report `json:"Reports,omitempty"`
|
||||
Name string // 报告名称(默认为 ROOT)
|
||||
Values map[string]any `json:"Values,omitempty"`
|
||||
Counter map[string]int64 `json:"Count,omitempty"`
|
||||
Subs []*Report `json:"Reports,omitempty"`
|
||||
}
|
||||
|
||||
// Avg 计算平均值
|
||||
func (slf *Report) Avg(key string) float64 {
|
||||
return slf.Values[key] / float64(slf.Counter[key])
|
||||
value, exist := slf.Values[key]
|
||||
if !exist {
|
||||
return 0
|
||||
}
|
||||
valF, ok := value.(float64)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
return valF / float64(slf.Counter[key])
|
||||
}
|
||||
|
||||
// Count 获取特定 key 的计数次数
|
||||
|
@ -43,7 +52,15 @@ func (slf *Report) Count(key string) int64 {
|
|||
func (slf *Report) Sum(keys ...string) float64 {
|
||||
var sum float64
|
||||
for _, key := range keys {
|
||||
sum += slf.Values[key]
|
||||
value, exist := slf.Values[key]
|
||||
if !exist {
|
||||
continue
|
||||
}
|
||||
valF, ok := value.(float64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
sum += valF
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
@ -58,6 +75,19 @@ func (slf *Report) Sub(name string) *Report {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ReserveSubByPrefix 仅保留特定前缀的子报告
|
||||
func (slf *Report) ReserveSubByPrefix(prefix string) *Report {
|
||||
report := newReport(slf.analyzer)
|
||||
var newSub []*Report
|
||||
for _, sub := range slf.Subs {
|
||||
if strings.HasPrefix(sub.Name, prefix) {
|
||||
newSub = append(newSub, sub)
|
||||
}
|
||||
}
|
||||
report.Subs = newSub
|
||||
return report
|
||||
}
|
||||
|
||||
// ReserveSub 仅保留特定名称子报告
|
||||
func (slf *Report) ReserveSub(names ...string) *Report {
|
||||
report := newReport(slf.analyzer)
|
||||
|
@ -78,7 +108,7 @@ func (slf *Report) ReserveSub(names ...string) *Report {
|
|||
return report
|
||||
}
|
||||
|
||||
// FilterSub 过滤特定名称的子报告
|
||||
// FilterSub 将特定名称的子报告过滤掉
|
||||
func (slf *Report) FilterSub(names ...string) *Report {
|
||||
report := newReport(slf.analyzer)
|
||||
var newSub []*Report
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package super
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Retry 根据提供的 count 次数尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功或者达到 count 次数
|
||||
func Retry(count int, interval time.Duration, f func() error) error {
|
||||
|
@ -14,6 +19,58 @@ func Retry(count int, interval time.Duration, f func() error) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// RetryByRule 根据提供的规则尝试执行 f 函数,如果 f 函数返回错误,则根据 rule 的返回值进行重试
|
||||
// - rule 将包含一个入参,表示第几次重试,返回值表示下一次重试的时间间隔,当返回值为 0 时,表示不再重试
|
||||
// - rule 的 count 将在 f 首次失败后变为 1,因此 rule 的入参将从 1 开始
|
||||
func RetryByRule(f func() error, rule func(count int) time.Duration) error {
|
||||
var count int
|
||||
var err error
|
||||
for {
|
||||
if err = f(); err != nil {
|
||||
count++
|
||||
next := rule(count)
|
||||
if next <= 0 {
|
||||
break
|
||||
}
|
||||
time.Sleep(next)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// RetryByExponentialBackoff 根据指数退避算法尝试执行 f 函数
|
||||
// - maxRetries:最大重试次数
|
||||
// - baseDelay:基础延迟
|
||||
// - maxDelay:最大延迟
|
||||
// - multiplier:延迟时间的乘数,通常为 2
|
||||
// - randomization:延迟时间的随机化因子,通常为 0.5
|
||||
func RetryByExponentialBackoff(f func() error, maxRetries int, baseDelay, maxDelay time.Duration, multiplier, randomization float64) error {
|
||||
retry := 0
|
||||
for {
|
||||
err := f()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if retry >= maxRetries {
|
||||
return fmt.Errorf("max retries reached: %v", err)
|
||||
}
|
||||
|
||||
delay := float64(baseDelay) * math.Pow(multiplier, float64(retry))
|
||||
jitter := (rand.Float64() - 0.5) * randomization * float64(baseDelay)
|
||||
sleepDuration := time.Duration(delay + jitter)
|
||||
|
||||
if sleepDuration > maxDelay {
|
||||
sleepDuration = maxDelay
|
||||
}
|
||||
|
||||
time.Sleep(sleepDuration)
|
||||
retry++
|
||||
}
|
||||
}
|
||||
|
||||
// RetryAsync 与 Retry 类似,但是是异步执行
|
||||
// - 传入的 callback 函数会在执行完毕后被调用,如果执行成功,则 err 为 nil,否则为错误信息
|
||||
// - 如果 callback 为 nil,则不会在执行完毕后被调用
|
||||
|
|
Loading…
Reference in New Issue