Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions model/ability.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ type AbilityWithChannel struct {
ChannelType int `json:"channel_type"`
}

func ensureAbilityColumnsInitialized() {
if commonGroupCol == "" {
initCol()
}
}

func GetAllEnableAbilityWithChannels() ([]AbilityWithChannel, error) {
var abilities []AbilityWithChannel
err := DB.Table("abilities").
Expand All @@ -39,6 +45,7 @@ func GetAllEnableAbilityWithChannels() ([]AbilityWithChannel, error) {
}

func GetGroupEnabledModels(group string) []string {
ensureAbilityColumnsInitialized()
var models []string
// Find distinct models
DB.Table("abilities").Where(commonGroupCol+" = ? and enabled = ?", group, true).Distinct("model").Pluck("model", &models)
Expand All @@ -59,6 +66,7 @@ func GetAllEnableAbilities() []Ability {
}

func getPriority(group string, model string, retry int) (int, error) {
ensureAbilityColumnsInitialized()

var priorities []int
err := DB.Model(&Ability{}).
Expand Down Expand Up @@ -89,6 +97,7 @@ func getPriority(group string, model string, retry int) (int, error) {
}

func getChannelQuery(group string, model string, retry int) (*gorm.DB, error) {
ensureAbilityColumnsInitialized()
maxPrioritySubQuery := DB.Model(&Ability{}).Select("MAX(priority)").Where(commonGroupCol+" = ? and model = ? and enabled = ?", group, model, true)
channelQuery := DB.Where(commonGroupCol+" = ? and model = ? and enabled = ? and priority = (?)", group, model, true, maxPrioritySubQuery)
if retry != 0 {
Expand Down
79 changes: 44 additions & 35 deletions model/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,25 @@ func (c ChannelInfo) Value() (driver.Value, error) {

// Scan implements sql.Scanner interface
func (c *ChannelInfo) Scan(value interface{}) error {
bytesValue, _ := value.([]byte)
return common.Unmarshal(bytesValue, c)
switch typedValue := value.(type) {
case nil:
*c = ChannelInfo{}
return nil
case []byte:
if len(typedValue) == 0 {
*c = ChannelInfo{}
return nil
}
return common.Unmarshal(typedValue, c)
case string:
if typedValue == "" {
*c = ChannelInfo{}
return nil
}
return common.Unmarshal([]byte(typedValue), c)
default:
return fmt.Errorf("unsupported channel info type: %T", value)
}
}

func (channel *Channel) GetKeys() []string {
Expand Down Expand Up @@ -608,42 +625,13 @@ func handlerMultiKeyUpdate(channel *Channel, usingKey string, status int, reason
}
}

// UpdateChannelStatus updates channel state and its ability visibility atomically.
func UpdateChannelStatus(channelId int, usingKey string, status int, reason string) bool {
if common.MemoryCacheEnabled {
channelStatusLock.Lock()
defer channelStatusLock.Unlock()

channelCache, _ := CacheGetChannel(channelId)
if channelCache == nil {
return false
}
if channelCache.ChannelInfo.IsMultiKey {
// Use per-channel lock to prevent concurrent map read/write with GetNextEnabledKey
pollingLock := GetChannelPollingLock(channelId)
pollingLock.Lock()
// 如果是多Key模式,更新缓存中的状态
handlerMultiKeyUpdate(channelCache, usingKey, status, reason)
pollingLock.Unlock()
//CacheUpdateChannel(channelCache)
//return true
} else {
// 如果缓存渠道存在,且状态已是目标状态,直接返回
if channelCache.Status == status {
return false
}
CacheUpdateChannelStatus(channelId, status)
}
}

shouldUpdateAbilities := false
defer func() {
if shouldUpdateAbilities {
err := UpdateAbilityStatus(channelId, status == common.ChannelStatusEnabled)
if err != nil {
common.SysLog(fmt.Sprintf("failed to update ability status: channel_id=%d, error=%v", channelId, err))
}
}
}()
channel, err := GetChannelById(channelId, true)
if err != nil {
return false
Expand All @@ -670,11 +658,32 @@ func UpdateChannelStatus(channelId int, usingKey string, status int, reason stri
channel.Status = status
shouldUpdateAbilities = true
}
err = channel.SaveWithoutKey()
if err != nil {
}
err = DB.Transaction(func(tx *gorm.DB) error {
if err := tx.Omit("key").Save(channel).Error; err != nil {
return err
}
if shouldUpdateAbilities {
err := tx.Model(&Ability{}).
Where("channel_id = ?", channelId).
Select("enabled").
Update("enabled", status == common.ChannelStatusEnabled).Error
if err != nil {
return err
}
}
return nil
})
if err != nil {
if shouldUpdateAbilities {
common.SysLog(fmt.Sprintf("failed to update channel or ability status atomically: channel_id=%d, status=%d, error=%v", channelId, status, err))
} else {
common.SysLog(fmt.Sprintf("failed to update channel status: channel_id=%d, status=%d, error=%v", channel.Id, status, err))
return false
}
return false
}
if common.MemoryCacheEnabled {
InitChannelCache()
}
return true
}
Expand Down
Loading