package state_machine import ( "context" "sync" "github.com/gogf/gf/v2/os/glog" "server/internal/consts" "server/utility/ecode" ) // AdStateMachine 广告状态机 type AdStateMachine struct { mu sync.RWMutex // 读写锁,保证并发安全 // 状态流转规则 transitions map[consts.AdState][]consts.AdState // 终止状态 terminalStates map[consts.AdState]bool } // NewAdStateMachine 创建新的广告状态机 func NewAdStateMachine() *AdStateMachine { sm := &AdStateMachine{ transitions: make(map[consts.AdState][]consts.AdState), terminalStates: make(map[consts.AdState]bool), } // 初始化状态流转规则 sm.initTransitions() return sm } // initTransitions 初始化状态流转规则 func (sm *AdStateMachine) initTransitions() { // 定义状态流转规则 sm.transitions = map[consts.AdState][]consts.AdState{ consts.StateFetchSuccess: {consts.StateDisplayFailed, consts.StateDisplaySuccess}, consts.StateDisplaySuccess: {consts.StateNotWatched, consts.StateWatched}, consts.StateWatched: {consts.StateNotClicked, consts.StateClicked}, consts.StateClicked: {consts.StateNotDownloaded, consts.StateDownloaded}, consts.StateNotDownloaded: {consts.StateDownloaded}, } // 定义终止状态 sm.terminalStates = map[consts.AdState]bool{ consts.StateFetchFailed: true, consts.StateDisplayFailed: true, consts.StateNotWatched: true, consts.StateNotClicked: true, consts.StateDownloaded: true, } } // CanTransition 检查是否可以转换到目标状态 func (sm *AdStateMachine) CanTransition(fromState, toState consts.AdState) bool { sm.mu.RLock() defer sm.mu.RUnlock() // 检查是否为终止状态 if sm.terminalStates[fromState] { return false } // 检查允许的转换 allowedStates, exists := sm.transitions[fromState] if !exists { return false } for _, allowed := range allowedStates { if allowed == toState { return true } } return false } // Transition 执行状态转换 func (sm *AdStateMachine) Transition(ctx context.Context, flowID string, userID int64, fromState, toState consts.AdState, reason string) error { sm.mu.Lock() defer sm.mu.Unlock() // 验证状态转换 if !sm.CanTransition(fromState, toState) { glog.Warningf(ctx, "Invalid state transition: %s -> %s, FlowID: %s, UserID: %d, Reason: %s", consts.GetStateDescription(fromState), consts.GetStateDescription(toState), flowID, userID, reason) return ecode.Params.Sub("invalid_state_transition") } // 记录状态转换日志 glog.Infof(ctx, "State transition: %s -> %s, FlowID: %s, UserID: %d, Reason: %s", consts.GetStateDescription(fromState), consts.GetStateDescription(toState), flowID, userID, reason) return nil } // IsTerminalState 检查是否为终止状态 func (sm *AdStateMachine) IsTerminalState(state consts.AdState) bool { sm.mu.RLock() defer sm.mu.RUnlock() return sm.terminalStates[state] } // GetAvailableTransitions 获取当前状态可用的转换 func (sm *AdStateMachine) GetAvailableTransitions(currentState consts.AdState) []consts.AdState { sm.mu.RLock() defer sm.mu.RUnlock() if transitions, exists := sm.transitions[currentState]; exists { return transitions } return []consts.AdState{} }