Files
iotlcm/upstream-chan/internal/logic/upstreamapi/upstreamapi.go
T

1355 lines
40 KiB
Go

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
}