package upstreamapi import ( "context" "database/sql" "strings" "sync" "time" "git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/consts" "git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/dao" "git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/model" "git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/model/entity" "git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/service" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" ) type sUpstreamAPI struct { tempMap map[string]model.SimCardTempI modelMap map[string]model.SimCardModelFactory chanMap map[string]*model.SimCardChannelCache channelGuards sync.Map sync.RWMutex running bool } func NewUpstreamAPI() *sUpstreamAPI { return &sUpstreamAPI{ chanMap: make(map[string]*model.SimCardChannelCache), tempMap: make(map[string]model.SimCardTempI), modelMap: make(map[string]model.SimCardModelFactory), } } func init() { service.RegisterUpstreamAPI(NewUpstreamAPI()) } func (u *sUpstreamAPI) Start(ctx context.Context) error { u.running = true lastReloadTime := int64(0) go func() { for u.running { now := time.Now().Unix() reloadInterval := g.Cfg().MustGet(ctx, "upstreamapi.reload_interval", 60).Int64() if now-lastReloadTime >= reloadInterval { lastReloadTime = now err := u.loop(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamAPI loop err %+v", err) } } time.Sleep(1 * time.Second) } }() g.Log().Infof(ctx, "sUpstreamAPI Start success") return nil } func (u *sUpstreamAPI) Stop(ctx context.Context) error { u.running = false return nil } // RefreshChannel reloads the persisted channel configuration and atomically // replaces the cached upstream implementation for that channel. func (u *sUpstreamAPI) RefreshChannel(ctx context.Context, chanKey string) error { chanKey = strings.TrimSpace(chanKey) if chanKey == "" { return gerror.New("chanKey is required") } return u.withChannelGuard(chanKey, func() error { if err := service.ChannelConfig().RefreshChannel(ctx, chanKey); err != nil { return err } channelConf, ok := service.ChannelConfig().GetChannel(chanKey) if !ok || channelConf == nil { return gerror.Newf("channel config not found: %s", chanKey) } if !channelConf.CanCreateInstance() { u.UnregisterChan(chanKey) g.Log().Infof(ctx, "channel instance removed because channel is abnormal, chanKey: %s", chanKey) return nil } instance, err := u.newRuntimeChannelInstance(ctx, channelConf) if err != nil { return err } u.RegisterChan(chanKey, channelConf.Version, &model.SimCardChannelCache{Instance: instance, Version: channelConf.Version}) g.Log().Infof(ctx, "channel refreshed, chanKey: %s, version: %s", chanKey, channelConf.Version) return nil }) } // RemoveChannel drops the cached configuration and runtime instance for a // channel. Deleting an already absent key is a successful no-op. func (u *sUpstreamAPI) RemoveChannel(ctx context.Context, chanKey string) error { chanKey = strings.TrimSpace(chanKey) if chanKey == "" { return gerror.New("chanKey is required") } return u.withChannelGuard(chanKey, func() error { if err := service.ChannelConfig().RemoveChannel(ctx, chanKey); err != nil { return err } u.UnregisterChan(chanKey) g.Log().Infof(ctx, "channel removed, chanKey: %s", chanKey) return nil }) } func (u *sUpstreamAPI) loop(ctx context.Context) error { channelConfigs, err := service.ChannelConfig().GetAllChannel(ctx) if err != nil { return err } for _, channelConf := range channelConfigs { if channelConf == nil || channelConf.Channel == nil { continue } chanKey := strings.TrimSpace(channelConf.Channel.ChanKey) if chanKey == "" { continue } if err := u.withChannelGuard(chanKey, func() error { latest, ok := service.ChannelConfig().GetChannel(chanKey) if !ok || latest == nil || latest.Channel == nil { u.UnregisterChan(chanKey) return nil } if !latest.CanCreateInstance() { u.UnregisterChan(chanKey) return nil } tempKey := "" if latest.Template != nil { tempKey = latest.Template.TempKey } channelCache, ok := u.GetChan(chanKey) if ok && channelCache != nil && channelCache.Version == latest.Version { return nil } isNew := !ok || channelCache == nil g.Log().Infof(ctx, "Create channel instance begin, chanKey: %s, isNew: %v", chanKey, isNew) instance, instanceErr := u.newRuntimeChannelInstance(ctx, latest) if instanceErr != nil { return gerror.Wrapf(instanceErr, "create channel instance failed, tempKey: %s", tempKey) } u.RegisterChan(chanKey, latest.Version, &model.SimCardChannelCache{ Instance: instance, Version: latest.Version, }) g.Log().Infof(ctx, "Create channel instance success, chanKey: %s, version: %s", chanKey, latest.Version) return nil }); err != nil { g.Log().Errorf(ctx, "Create channel instance failed, chanKey: %s, err: %v", chanKey, err) } } return nil } func (u *sUpstreamAPI) RegisterChan(chanKey string, version string, channel *model.SimCardChannelCache) { u.Lock() defer u.Unlock() u.chanMap[chanKey] = channel } // UnregisterChan atomically removes a runtime channel. Missing keys are a // successful no-op so refresh and rename retries remain idempotent. func (u *sUpstreamAPI) UnregisterChan(chanKey string) { u.Lock() delete(u.chanMap, strings.TrimSpace(chanKey)) u.Unlock() } func (u *sUpstreamAPI) withChannelGuard(chanKey string, fn func() error) error { guard, _ := u.channelGuards.LoadOrStore(chanKey, &sync.Mutex{}) mu := guard.(*sync.Mutex) mu.Lock() defer mu.Unlock() return fn() } func (u *sUpstreamAPI) RegisterTemp(tempKey string, channel model.SimCardTempI) { u.Lock() defer u.Unlock() u.tempMap[tempKey] = channel } // RegisterModel registers a fallback implementation keyed by template model. // Concrete temp_key registrations always take precedence over model factories. func (u *sUpstreamAPI) RegisterModel(modelKey string, factory model.SimCardModelFactory) { modelKey = strings.TrimSpace(modelKey) if modelKey == "" || factory == nil { return } u.Lock() defer u.Unlock() u.modelMap[modelKey] = factory } func (u *sUpstreamAPI) GetTemp(tempKey string) (model.SimCardTempI, bool) { u.RLock() defer u.RUnlock() temp, ok := u.tempMap[tempKey] return temp, ok } func (u *sUpstreamAPI) GetModel(modelKey string) (model.SimCardModelFactory, bool) { u.RLock() defer u.RUnlock() factory, ok := u.modelMap[strings.TrimSpace(modelKey)] return factory, ok } func (u *sUpstreamAPI) newRuntimeChannelInstance(ctx context.Context, channelConf *model.SimChannelConfigItemCache) (model.SimCardChannelI, error) { if !channelConf.CanCreateInstance() { return nil, gerror.New("channel is_normal must be 0 to create a runtime instance") } return u.buildChannelInstance(ctx, channelConf) } func (u *sUpstreamAPI) newTestChannelInstance(ctx context.Context, channelConf *model.SimChannelConfigItemCache) (model.SimCardChannelI, error) { return u.buildChannelInstance(ctx, channelConf) } func (u *sUpstreamAPI) buildChannelInstance(ctx context.Context, channelConf *model.SimChannelConfigItemCache) (model.SimCardChannelI, error) { if channelConf == nil || channelConf.Channel == nil { return nil, gerror.New("channel config is required") } if strings.TrimSpace(channelConf.Channel.ChanKey) == "" { return nil, gerror.New("channel key is required") } if channelConf.Template == nil { return nil, gerror.New("channel template config is required") } if strings.TrimSpace(channelConf.Template.TempKey) == "" { return nil, gerror.New("channel template key is required") } if temp, ok := u.GetTemp(channelConf.Template.TempKey); ok && temp != nil { instance := temp.NewTemp(ctx, channelConf) if instance == nil { return nil, gerror.Newf("create channel instance failed: %s", channelConf.Template.TempKey) } return instance, nil } modelKey := strings.TrimSpace(channelConf.Template.TempModel) if modelKey == "" { return nil, gerror.Newf("channel template model is required: tempKey=%s", channelConf.Template.TempKey) } if modelKey == "direct" { return nil, gerror.Newf("direct channel template requires exact temp_key registration: tempKey=%s", channelConf.Template.TempKey) } factory, ok := u.GetModel(modelKey) if !ok || factory == nil { return nil, gerror.Newf("unsupported channel template model: tempKey=%s tempModel=%s", channelConf.Template.TempKey, modelKey) } instance := factory(ctx, channelConf) if instance == nil { return nil, gerror.Newf("create channel instance failed: tempKey=%s tempModel=%s", channelConf.Template.TempKey, modelKey) } return instance, nil } func (u *sUpstreamAPI) GetChan(chanKey string) (*model.SimCardChannelCache, bool) { u.RLock() defer u.RUnlock() channel, ok := u.chanMap[chanKey] return channel, ok } func iccidFromChannelCacheKey(key string) string { const prefix = "sim:chan:iccid:" if !strings.HasPrefix(key, prefix) { return "" } return strings.TrimPrefix(key, prefix) } func (u *sUpstreamAPI) packChanKey(ctx context.Context, simKeys []*model.SimKey) (map[string][]*model.SimKey, error) { redisKey := "sim:chan:iccid:" unknownChanKeyIccids := make([]string, 0) queryRedisIccids := make([]string, 0) queryDbIccids := make([]string, 0) chanKeyMap := make(map[string][]*model.SimKey) simKeyMap := make(map[string][]*model.SimKey, len(simKeys)) // 检查通道id是都携带 for _, simKey := range simKeys { if simKey.ChanKey == "" { simKeyMap[simKey.ICCID] = append(simKeyMap[simKey.ICCID], simKey) unknownChanKeyIccids = append(unknownChanKeyIccids, simKey.ICCID) queryRedisIccids = append(queryRedisIccids, redisKey+simKey.ICCID) } else { chanKeyMap[simKey.ChanKey] = append(chanKeyMap[simKey.ChanKey], simKey) } } if len(unknownChanKeyIccids) == 0 { return chanKeyMap, nil } allIccid := make(map[string]bool) for _, iccid := range unknownChanKeyIccids { allIccid[iccid] = false } // TODO: 临时数据库查询,后面添加内存缓存和Redis缓存 // 从Redis中查询通道id redisChanKeys, err := g.Redis().MGet(ctx, queryRedisIccids...) if err != nil { return nil, err } for iccidKey, chanKey := range redisChanKeys { iccid := iccidFromChannelCacheKey(iccidKey) if _, expected := allIccid[iccid]; !expected { continue } chanKeyStr := chanKey.String() if chanKeyStr == "" { g.Log().Debug(ctx, "查询redis为空, iccid:"+iccid) continue } allIccid[iccid] = true for _, original := range simKeyMap[iccid] { key := *original key.ChanKey = chanKeyStr chanKeyMap[chanKeyStr] = append(chanKeyMap[chanKeyStr], &key) } } for iccid, found := range allIccid { if !found { queryDbIccids = append(queryDbIccids, iccid) } } if len(queryDbIccids) == 0 { return chanKeyMap, nil } var simCardInfos []*entity.TSimCardInfo err = dao.TSimCardInfo.Ctx(ctx). Fields( dao.TSimCardInfo.Columns().ChanKey, dao.TSimCardInfo.Columns().Iccid, ). WhereIn(dao.TSimCardInfo.Columns().Iccid, queryDbIccids). Scan(&simCardInfos) if err != nil && err != sql.ErrNoRows { return nil, err } for _, simCardInfo := range simCardInfos { allIccid[simCardInfo.Iccid] = true for _, original := range simKeyMap[simCardInfo.Iccid] { key := *original key.ChanKey = simCardInfo.ChanKey chanKeyMap[simCardInfo.ChanKey] = append(chanKeyMap[simCardInfo.ChanKey], &key) } g.Redis().Set(ctx, redisKey+simCardInfo.Iccid, simCardInfo.ChanKey) } for iccid, found := range allIccid { if !found { for _, original := range simKeyMap[iccid] { key := *original key.ChanKey = "" chanKeyMap[""] = append(chanKeyMap[""], &key) } } } return chanKeyMap, nil } // 物联网卡基本信息查询 func (u *sUpstreamAPI) QuerySimBasicInfo(ctx context.Context, input *model.SimBasicInfoInput) (model.SimBasicInfoOutput, error) { output := make([]*model.SimBaseRes[model.SimBasicInfoItem], 0) inputMap := make(map[string]*model.SimBasicInfoInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimBasicInfoInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimBasicInfoItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", ResData: model.SimBasicInfoItem{ ActiveDate: "", OpenDate: "", Remark: "", }, }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimBasicInfoItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", ResData: model.SimBasicInfoItem{ ActiveDate: "", OpenDate: "", Remark: "", }, }) } continue } out, err := channel.Instance.QuerySimBasicInfo(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimBasicInfoItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), ResData: model.SimBasicInfoItem{ ActiveDate: "", OpenDate: "", Remark: "", }, }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡在线信息实时查询 func (u *sUpstreamAPI) QuerySimSession(ctx context.Context, input *model.SimSessionInput) (model.SimSessionOutput, error) { output := make([]*model.SimBaseRes[model.SimSessionItem], 0) inputMap := make(map[string]*model.SimSessionInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimSessionInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimSessionItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", ResData: model.SimSessionItem{ Status: "-2", }, }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimSessionItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", ResData: model.SimSessionItem{ Status: "-2", }, }) } continue } out, err := channel.Instance.QuerySimSession(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimSessionItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), ResData: model.SimSessionItem{ Status: "-2", }, }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡卡状态查询 func (u *sUpstreamAPI) QuerySimCardStatus(ctx context.Context, input *model.SimCardStatusInput) (output model.SimCardStatusOutput, err error) { output = make([]*model.SimBaseRes[model.SimCardStatusItem], 0) inputMap := make(map[string]*model.SimCardStatusInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimCardStatusInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } out, err := channel.Instance.QuerySimCardStatus(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡机卡绑定状态查询 func (u *sUpstreamAPI) QuerySimStopReason(ctx context.Context, input *model.SimStopReasonInput) (output model.SimStopReasonOutput, err error) { output = make([]*model.SimBaseRes[model.SimStopReasonItem], 0) inputMap := make(map[string]*model.SimStopReasonInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimStopReasonInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimStopReasonItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", ResData: model.SimStopReasonItem{}, }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimStopReasonItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", ResData: model.SimStopReasonItem{}, }) } continue } out, err := channel.Instance.QuerySimStopReason(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimStopReasonItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), ResData: model.SimStopReasonItem{}, }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } func (u *sUpstreamAPI) QuerySimFrozenState(ctx context.Context, input *model.SimFrozenStateInput) (output model.SimFrozenStateOutput, err error) { output = make([]*model.SimBaseRes[model.SimFrozenStateItem], 0) inputMap := make(map[string]*model.SimFrozenStateInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimFrozenStateInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimFrozenStateItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", ResData: model.SimFrozenStateItem{}, }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimFrozenStateItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", ResData: model.SimFrozenStateItem{}, }) } continue } out, err := channel.Instance.QuerySimFrozenState(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimFrozenStateItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), ResData: model.SimFrozenStateItem{}, }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } func (u *sUpstreamAPI) QuerySimCardBindStatus(ctx context.Context, input *model.SimCardBindStatusInput) (output model.SimCardBindStatusOutput, err error) { output = make([]*model.SimBaseRes[model.SimCardBindStatusItem], 0) inputMap := make(map[string]*model.SimCardBindStatusInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimCardBindStatusInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardBindStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", ResData: model.SimCardBindStatusItem{ BindStatus: "", }, }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardBindStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", ResData: model.SimCardBindStatusItem{ BindStatus: "", }, }) } continue } out, err := channel.Instance.QuerySimCardBindStatus(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardBindStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), ResData: model.SimCardBindStatusItem{ BindStatus: "", }, }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡设备状态查询 func (u *sUpstreamAPI) QuerySimDeviceStatus(ctx context.Context, input *model.SimDeviceStatusInput) (output model.SimDeviceStatusOutput, err error) { output = make([]*model.SimBaseRes[model.SimDeviceStatusItem], 0) inputMap := make(map[string]*model.SimDeviceStatusInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimDeviceStatusInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDeviceStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", ResData: model.SimDeviceStatusItem{ DeviceStatus: "-2", }, }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDeviceStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", ResData: model.SimDeviceStatusItem{ DeviceStatus: "-2", }, }) } continue } out, err := channel.Instance.QuerySimDeviceStatus(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDeviceStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), ResData: model.SimDeviceStatusItem{ DeviceStatus: "-2", }, }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡地域限制状态查询 func (u *sUpstreamAPI) QuerySimRegionLimitStatus(ctx context.Context, input *model.SimRegionLimitStatusInput) (output model.SimRegionLimitStatusOutput, err error) { output = make([]*model.SimBaseRes[model.SimRegionLimitStatusItem], 0) inputMap := make(map[string]*model.SimRegionLimitStatusInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimRegionLimitStatusInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimRegionLimitStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", ResData: model.SimRegionLimitStatusItem{ RegionLimitStatus: "", }, }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimRegionLimitStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", ResData: model.SimRegionLimitStatusItem{ RegionLimitStatus: "", }, }) } continue } out, err := channel.Instance.QuerySimRegionLimitStatus(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimRegionLimitStatusItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), ResData: model.SimRegionLimitStatusItem{ RegionLimitStatus: "", }, }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡IMEI查询 func (u *sUpstreamAPI) QuerySimImei(ctx context.Context, input *model.SimImeiInput) (output model.SimImeiOutput, err error) { output = make([]*model.SimBaseRes[model.SimImeiItem], 0) inputMap := make(map[string]*model.SimImeiInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimImeiInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimImeiItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimImeiItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } out, err := channel.Instance.QuerySimImei(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimImeiItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 单卡本月流量累计使用量查询 func (u *sUpstreamAPI) QuerySimDataUsage(ctx context.Context, input *model.SimDataUsageInput) (output model.SimDataUsageOutput, err error) { output = make([]*model.SimBaseRes[model.SimDataUsageItem], 0) if input == nil || len(input.SimKeys) == 0 { return output, nil } inputMap := make(map[string]*model.SimDataUsageInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimDataUsageInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } out, err := channel.Instance.QuerySimDataUsage(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联卡达量限速档位查询 func (u *sUpstreamAPI) QuerySimDataDiagnosis(ctx context.Context, input *model.SimDataDiagnosisInput) (output model.SimDataDiagnosisOutput, err error) { output = make([]*model.SimBaseRes[any], 0) if input == nil || len(input.SimKeys) == 0 { return output, nil } inputMap := make(map[string]*model.SimDataDiagnosisInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimDataDiagnosisInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[any]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[any]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } out, err := channel.Instance.QuerySimDataDiagnosis(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[any]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联卡单月 GPRS流量使用量批量查询 func (u *sUpstreamAPI) QuerySimDataUsageMonthly(ctx context.Context, input *model.SimDataUsageMonthlyInput) (output model.SimDataUsageMonthlyOutput, err error) { output = make(model.SimDataUsageMonthlyOutput, 0) if input == nil || len(input.SimKeys) == 0 { return output, nil } if message := validateHistoricalMonth(input.ReqData.QueryDate, time.Now()); message != "" { return appendBatchMonthlyFailures(output, input.SimKeys, message), nil } inputMap := make(map[string]*model.SimDataUsageMonthlyInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimDataUsageMonthlyInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageMonthlyOutputItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageMonthlyOutputItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } out, err := channel.Instance.QuerySimDataUsageMonthly(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageMonthlyOutputItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡数据流量查询 日查询 func (u *sUpstreamAPI) QuerySimDataUsageDaily(ctx context.Context, input *model.SimDataUsageDailyInput) (output model.SimDataUsageDailyOutput, err error) { output = make(model.SimDataUsageDailyOutput, 0) if input == nil || len(input.SimKeys) == 0 { return output, nil } if message := validateHistoricalDay(input.ReqData.QueryDate, time.Now()); message != "" { return appendBatchDailyFailures(output, input.SimKeys, message), nil } inputMap := make(map[string]*model.SimDataUsageDailyInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimDataUsageDailyInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageDailyOutputItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageDailyOutputItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } out, err := channel.Instance.QuerySimDataUsageDaily(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimDataUsageDailyOutputItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡已开通APN信息查询 func (u *sUpstreamAPI) QuerySimApnInfo(ctx context.Context, input *model.SimApnInfoInput) (output model.SimApnInfoOutput, err error) { output = make(model.SimApnInfoOutput, 0) inputMap := make(map[string]*model.SimApnInfoInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimApnInfoInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimApnInfoItemList]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimApnInfoItemList]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } out, err := channel.Instance.QuerySimApnInfo(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimApnInfoItemList]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } // 物联网卡状态变更 func (u *sUpstreamAPI) ChangeSimStatus(ctx context.Context, input *model.SimCardStatusChangeInput) (output model.SimCardStatusChangeOutput, err error) { output = make([]*model.SimBaseRes[model.SimCardStatusChangeItem], 0) inputMap := make(map[string]*model.SimCardStatusChangeInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimCardStatusChangeInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if chanKey == "" { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardStatusChangeItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardStatusChangeItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } out, err := channel.Instance.ChangeSimStatus(ctx, inputNew) if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardStatusChangeItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil } func (u *sUpstreamAPI) ChangeSimCardOperateApn(ctx context.Context, input *model.SimCardOperateChangeApnInput) (output model.SimCardOperateChangeApnOutput, err error) { output = make([]*model.SimBaseRes[model.SimCardOperateChangeApnItem], 0) inputMap := make(map[string]*model.SimCardOperateChangeApnInput) chanKeyMap, err := u.packChanKey(ctx, input.SimKeys) if err != nil { return nil, err } for chanKey, simKeys := range chanKeyMap { inputMap[chanKey] = &model.SimCardOperateChangeApnInput{ SimKeys: simKeys, ReqData: input.ReqData, } } for chanKey, inputNew := range inputMap { if inputNew.ReqData.RecoverOnly && inputNew.ReqData.QueryJobID == "" { recovered, recoverErr := durableApnOperation(ctx, sqlApnOperationStore{}, chanKey, inputNew, nil) if recoverErr != nil { recovered = unknownApnOperation(inputNew, recoverErr.Error()) } output = append(output, recovered...) continue } if chanKey == "" { if inputNew.ReqData.SubmitOnly || inputNew.ReqData.QueryJobID != "" { output = append(output, unknownApnOperation(inputNew, "通道未配置,异步结果未确认")...) continue } for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardOperateChangeApnItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未配置", }) } continue } channel, ok := u.GetChan(chanKey) if !ok || channel.Instance == nil { if inputNew.ReqData.SubmitOnly || inputNew.ReqData.QueryJobID != "" { output = append(output, unknownApnOperation(inputNew, "通道未实例化,异步结果未确认")...) continue } for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardOperateChangeApnItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: "通道未实例化", }) } continue } var out model.SimCardOperateChangeApnOutput var err error if inputNew.ReqData.QueryJobID == "" && (inputNew.ReqData.RecoverOnly || inputNew.ReqData.SubmitOnly) { out, err = durableApnOperation(ctx, sqlApnOperationStore{}, chanKey, inputNew, func(submitCtx context.Context) (model.SimCardOperateChangeApnOutput, error) { return channel.Instance.ChangeSimApnFunction(submitCtx, inputNew) }) } else if inputNew.ReqData.QueryJobID != "" { querier, supported := channel.Instance.(interface { QuerySimApnFunctionResult(context.Context, *model.SimCardOperateChangeApnInput) (model.SimCardOperateChangeApnOutput, error) }) if !supported { for _, key := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardOperateChangeApnItem]{SimKey: key, Code: consts.ApiStatusError, Message: "该通道不支持异步APN任务查询", ResData: model.SimCardOperateChangeApnItem{OrderNum: inputNew.ReqData.QueryJobID, Uncertain: true}}) } continue } out, err = querier.QuerySimApnFunctionResult(ctx, inputNew) } else { out, err = channel.Instance.ChangeSimApnFunction(ctx, inputNew) } if err != nil { for _, simKey := range inputNew.SimKeys { output = append(output, &model.SimBaseRes[model.SimCardOperateChangeApnItem]{ SimKey: simKey, Code: consts.ApiStatusError, Message: err.Error(), ResData: model.SimCardOperateChangeApnItem{OrderNum: inputNew.ReqData.QueryJobID, Uncertain: inputNew.ReqData.SubmitOnly || inputNew.ReqData.RecoverOnly || inputNew.ReqData.QueryJobID != ""}, }) } } else { for _, item := range out { output = append(output, item) } } } return output, nil }