package task import ( "context" "sync" "time" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // realnameControlCacheTTL 是运营商账户实名管控在进程内的缓存时长;账户配置修改最迟在该时长后生效。 const realnameControlCacheTTL = time.Minute type realnameControlEntry struct { controlled bool loadedAt time.Time } var realnameControlCache = struct { sync.Mutex values map[uint]realnameControlEntry }{values: map[uint]realnameControlEntry{}} // realnameQuerySkippable 判断本次实名轮询能否跳过查询:卡所属运营商账户未开启实名管控时实名结果不影响停复机,跳过; // 但卡未实名且所在资产(绑定设备时按设备)有等待实名激活的套餐时照常查询,避免囤货套餐因发现不了实名而无法激活。 // 账户或套餐查询失败返回错误,调用方按可恢复失败处理。 func (b *PollingBase) realnameQuerySkippable(ctx context.Context, card *model.IotCard) (bool, error) { controlled, err := b.carrierRealnameControlled(ctx, card.CarrierID) if err != nil { return false, err } if controlled { return false, nil } if card.RealNameStatus == constants.RealNameStatusVerified { return true, nil } pending, err := b.hasPendingRealnameActivation(ctx, card) if err != nil { return false, err } return !pending, nil } func (b *PollingBase) carrierRealnameControlled(ctx context.Context, carrierID uint) (bool, error) { realnameControlCache.Lock() entry, ok := realnameControlCache.values[carrierID] realnameControlCache.Unlock() if ok && time.Since(entry.loadedAt) < realnameControlCacheTTL { return entry.controlled, nil } if b.db == nil { return false, errors.New(errors.CodeInternalError, "实名轮询数据库未配置") } var values []int if err := b.db.WithContext(ctx).Model(&model.Carrier{}).Where("id = ?", carrierID).Limit(1). Pluck("realname_control_enabled", &values).Error; err != nil { return false, errors.Wrap(errors.CodeDatabaseError, err, "查询运营商账户实名管控失败") } if len(values) == 0 { return false, errors.New(errors.CodeNotFound, "卡所属运营商账户不存在,无法判断实名管控") } controlled := values[0] == 1 realnameControlCache.Lock() realnameControlCache.values[carrierID] = realnameControlEntry{controlled: controlled, loadedAt: time.Now()} realnameControlCache.Unlock() return controlled, nil } // hasPendingRealnameActivation 判断卡所在资产是否有等待实名激活的待生效套餐。 func (b *PollingBase) hasPendingRealnameActivation(ctx context.Context, card *model.IotCard) (bool, error) { query := b.db.WithContext(ctx).Model(&model.PackageUsage{}). Where("pending_realname_activation = ? AND status = ?", true, constants.PackageUsageStatusPending) var deviceIDs []uint if !card.IsStandalone { if err := b.db.WithContext(ctx).Model(&model.DeviceSimBinding{}). Where("iot_card_id = ? AND bind_status = ?", card.ID, constants.BindStatusBound). Limit(1).Pluck("device_id", &deviceIDs).Error; err != nil { return false, errors.Wrap(errors.CodeDatabaseError, err, "查询卡绑定设备失败") } } if len(deviceIDs) > 0 { query = query.Where("device_id = ?", deviceIDs[0]) } else { query = query.Where("iot_card_id = ?", card.ID) } var count int64 if err := query.Limit(1).Count(&count).Error; err != nil { return false, errors.Wrap(errors.CodeDatabaseError, err, "查询待实名激活套餐失败") } return count > 0, nil }