96b1edff45
iotlcm-upstream-chan:运营商上游通道适配服务(统一 /sim/* 协议)。 - 内联原私有依赖:yunze-public → internal/pub/(10 包 18 文件), yunze-pb/pb → internal/pb/(9 文件);Consul 注册改用官方 gogf/gf/contrib/registry/consul/v2(API 兼容) - Go module:yz-svr → git.5iot.com/iotlcm-public/iotlcm-upstream-chan - 修复 mingqian 包测试:实现重构后 `adapter.operations` 字段已移除, 测试断言按当前实现语义重写(不改产品行为) - 凭据与内部标识脱敏:MySQL/Redis/Consul 凭据、私网与生产 IP、 内网域名、真实手机号、注释里的真实 token/transid - 移除内部资产:CI 触发器、生产通道种子 SQL、真实凭据测试资源文档 - Dockerfile 改用公共基础镜像,移除写死的 registry 凭据 - 补 Apache-2.0 LICENSE,重写 README,LF 行尾 + .gitattributes
496 lines
19 KiB
Go
496 lines
19 KiB
Go
package upstreamimpl
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/consts"
|
|
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/logic/upstreamimpl/yunda"
|
|
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/model"
|
|
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/service"
|
|
)
|
|
|
|
const yundaTemplateKey = "sim_yunda_v1"
|
|
|
|
type sSimYunda struct {
|
|
channelConfig *model.SimChannelConfigItemCache
|
|
client *yunda.Client
|
|
}
|
|
|
|
type yundaFloat float64
|
|
|
|
func (f *yundaFloat) UnmarshalJSON(data []byte) error {
|
|
var number float64
|
|
if err := json.Unmarshal(data, &number); err == nil {
|
|
*f = yundaFloat(number)
|
|
return nil
|
|
}
|
|
var text string
|
|
if err := json.Unmarshal(data, &text); err != nil {
|
|
return err
|
|
}
|
|
if text == "" {
|
|
*f = 0
|
|
return nil
|
|
}
|
|
value, err := strconv.ParseFloat(text, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*f = yundaFloat(value)
|
|
return nil
|
|
}
|
|
|
|
type yundaCards []yundaCard
|
|
|
|
func (cards *yundaCards) UnmarshalJSON(data []byte) error {
|
|
data = bytes.TrimSpace(data)
|
|
if len(data) == 0 || bytes.Equal(data, []byte("null")) {
|
|
*cards = nil
|
|
return nil
|
|
}
|
|
if data[0] == '[' {
|
|
return json.Unmarshal(data, (*[]yundaCard)(cards))
|
|
}
|
|
var card yundaCard
|
|
if err := json.Unmarshal(data, &card); err != nil {
|
|
return err
|
|
}
|
|
*cards = []yundaCard{card}
|
|
return nil
|
|
}
|
|
|
|
type yundaCard struct {
|
|
MSISDN string `json:"msisdn"`
|
|
ICCID string `json:"iccid"`
|
|
IMEI string `json:"imei"`
|
|
IMSI string `json:"imsi"`
|
|
Code string `json:"code"`
|
|
Error string `json:"error"`
|
|
Status string `json:"status"`
|
|
GPRSStatus string `json:"gprsStatus"`
|
|
GPRSStatusLower string `json:"gprsstatus"`
|
|
IP string `json:"ip"`
|
|
RAT string `json:"rat"`
|
|
StatTimestamp string `json:"statustimestamp"`
|
|
OpenTime string `json:"opentime"`
|
|
PackageID string `json:"packageid"`
|
|
PackageName string `json:"packagename"`
|
|
LifecycleStatus string `json:"lifecycleStatus"`
|
|
LifecycleStatusLower string `json:"lifecyclestatus"`
|
|
APNList []yundaAPN `json:"apnlist"`
|
|
APN string `json:"apn"`
|
|
}
|
|
|
|
type yundaAPN struct {
|
|
APNName string `json:"apnname"`
|
|
UsedFlow yundaFloat `json:"usedflow"`
|
|
DailyList []yundaDailyUse `json:"dailylist"`
|
|
}
|
|
|
|
type yundaDailyUse struct {
|
|
UsedFlow yundaFloat `json:"usedflow"`
|
|
Date string `json:"date"`
|
|
}
|
|
|
|
type yundaConfig struct {
|
|
BaseURL string `json:"baseUrl"`
|
|
Timeout string `json:"timeout"`
|
|
}
|
|
|
|
type yundaConfigEnvelope struct {
|
|
API yundaConfig `json:"api"`
|
|
BaseURL string `json:"baseUrl"`
|
|
Timeout string `json:"timeout"`
|
|
}
|
|
|
|
func NewSimYunda() *sSimYunda { return &sSimYunda{} }
|
|
|
|
func init() {
|
|
service.UpstreamAPI().RegisterTemp(yundaTemplateKey, NewSimYunda())
|
|
}
|
|
|
|
func (s *sSimYunda) NewTemp(ctx context.Context, channelConfig *model.SimChannelConfigItemCache) model.SimCardChannelI {
|
|
cfg := yundaConfigEnvelope{}
|
|
if channelConfig != nil && channelConfig.Template != nil {
|
|
_ = json.Unmarshal([]byte(channelConfig.Template.TempConfig), &cfg)
|
|
}
|
|
if channelConfig != nil && channelConfig.Channel != nil && strings.TrimSpace(channelConfig.Channel.ChanConfig) != "" {
|
|
var channelCfg yundaConfigEnvelope
|
|
if json.Unmarshal([]byte(channelConfig.Channel.ChanConfig), &channelCfg) == nil {
|
|
if channelCfg.API.BaseURL != "" {
|
|
cfg.API.BaseURL = channelCfg.API.BaseURL
|
|
}
|
|
if channelCfg.BaseURL != "" {
|
|
cfg.BaseURL = channelCfg.BaseURL
|
|
}
|
|
if channelCfg.API.Timeout != "" {
|
|
cfg.API.Timeout = channelCfg.API.Timeout
|
|
}
|
|
if channelCfg.Timeout != "" {
|
|
cfg.Timeout = channelCfg.Timeout
|
|
}
|
|
}
|
|
}
|
|
baseURL := cfg.API.BaseURL
|
|
if baseURL == "" {
|
|
baseURL = cfg.BaseURL
|
|
}
|
|
if baseURL == "" {
|
|
baseURL = "http://api.yundaiot.cn/v1"
|
|
}
|
|
timeout := 10 * time.Second
|
|
if cfg.API.Timeout != "" {
|
|
if parsed, err := time.ParseDuration(cfg.API.Timeout); err == nil {
|
|
timeout = parsed
|
|
}
|
|
}
|
|
if cfg.Timeout != "" {
|
|
if parsed, err := time.ParseDuration(cfg.Timeout); err == nil {
|
|
timeout = parsed
|
|
}
|
|
}
|
|
appKey, appSecret := "", ""
|
|
if channelConfig != nil && channelConfig.Channel != nil {
|
|
appKey = channelConfig.Channel.AppKey
|
|
appSecret = channelConfig.Channel.AppSecret
|
|
}
|
|
return &sSimYunda{channelConfig: channelConfig, client: yunda.NewClient(yunda.Config{BaseURL: baseURL, AppKey: appKey, AppSecret: appSecret, Timeout: timeout})}
|
|
}
|
|
|
|
func yundaCardValue(key *model.SimKey, field string) string {
|
|
if key == nil {
|
|
return ""
|
|
}
|
|
switch field {
|
|
case "iccid":
|
|
return key.ICCID
|
|
case "msisdn":
|
|
return key.MSISDN
|
|
case "imsi":
|
|
return key.IMSI
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (s *sSimYunda) clientPost(ctx context.Context, path string, params map[string]string, out *yundaCards) error {
|
|
_, err := s.client.Post(ctx, path, params, out)
|
|
return err
|
|
}
|
|
|
|
func (s *sSimYunda) requestCard(ctx context.Context, path string, key *model.SimKey, fields map[string]string, out *yundaCards) error {
|
|
if key == nil {
|
|
return errors.New("sim key is required")
|
|
}
|
|
params := map[string]string{}
|
|
for name, field := range fields {
|
|
if value := yundaCardValue(key, field); value != "" {
|
|
params[name] = value
|
|
}
|
|
}
|
|
if len(params) == 0 {
|
|
return errors.New("iccid, msisdn or imsi is required")
|
|
}
|
|
return s.clientPost(ctx, path, params, out)
|
|
}
|
|
|
|
func (s *sSimYunda) QuerySimBasicInfo(ctx context.Context, input *model.SimBasicInfoInput) (model.SimBasicInfoOutput, error) {
|
|
items := make(model.SimBasicInfoOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
var result yundaCards
|
|
err := s.requestCard(ctx, "BatchGetSimInfo", key, map[string]string{"iccids": "iccid", "msisdns": "msisdn", "imsis": "imsi"}, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, yundaBasicError(key, errOr(err, "yunda returned empty card info")))
|
|
continue
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimBasicInfoItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimBasicInfoItem{ICCID: card.ICCID, IMSI: card.IMSI, MSISDN: card.MSISDN, OpenDate: card.OpenTime}})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func (s *sSimYunda) QuerySimImei(ctx context.Context, input *model.SimImeiInput) (model.SimImeiOutput, error) {
|
|
items := make(model.SimImeiOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
var result yundaCards
|
|
err := s.requestCard(ctx, "BatchGetSimInfo", key, map[string]string{"iccids": "iccid", "msisdns": "msisdn", "imsis": "imsi"}, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimImeiItem]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty card info")})
|
|
continue
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimImeiItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimImeiItem{Imei: card.IMEI}})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func (s *sSimYunda) QuerySimCardStatus(ctx context.Context, input *model.SimCardStatusInput) (model.SimCardStatusOutput, error) {
|
|
items := make(model.SimCardStatusOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
var result yundaCards
|
|
err := s.requestCard(ctx, "BatchGetSimStatus", key, map[string]string{"iccids": "iccid", "msisdns": "msisdn"}, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimCardStatusItem]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty card status")})
|
|
continue
|
|
}
|
|
status, err := mapYundaCardStatus(card.Status)
|
|
if err != nil {
|
|
items = append(items, &model.SimBaseRes[model.SimCardStatusItem]{Code: consts.ApiStatusError, SimKey: key, Message: err.Error()})
|
|
continue
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimCardStatusItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimCardStatusItem{CardStatus: status}})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
// Yunda lifecycle codes: 0 testing, 1 dormant, 2 inventory, 3 in use, 4 stopped, 5 cancelled.
|
|
func mapYundaCardStatus(value string) (int, error) {
|
|
switch strings.TrimSpace(value) {
|
|
case "0", "测试期":
|
|
return 6, nil
|
|
case "1", "沉默期":
|
|
return 1, nil
|
|
case "2", "库存期":
|
|
return 7, nil
|
|
case "3", "正使用":
|
|
return 2, nil
|
|
case "4", "已停机":
|
|
return 4, nil
|
|
case "5", "已销户":
|
|
return 9, nil
|
|
default:
|
|
return 0, fmt.Errorf("yunda: unsupported card status %q", value)
|
|
}
|
|
}
|
|
|
|
func (s *sSimYunda) QuerySimDataUsage(ctx context.Context, input *model.SimDataUsageInput) (model.SimDataUsageOutput, error) {
|
|
items := make(model.SimDataUsageOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
var result yundaCards
|
|
err := s.requestCard(ctx, "BatchGetCurrentMonthGprs", key, map[string]string{"iccids": "iccid", "msisdns": "msisdn"}, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimDataUsageItem]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty usage")})
|
|
continue
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimDataUsageItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimDataUsageItem{DataUsage: firstYundaUsage(card)}})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func (s *sSimYunda) QuerySimDataUsageMonthly(ctx context.Context, input *model.SimDataUsageMonthlyInput) (model.SimDataUsageMonthlyOutput, error) {
|
|
items := make(model.SimDataUsageMonthlyOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
var result yundaCards
|
|
params := map[string]string{"month": input.ReqData.QueryDate}
|
|
if key != nil {
|
|
params["iccids"] = key.ICCID
|
|
params["msisdns"] = key.MSISDN
|
|
}
|
|
err := s.clientPost(ctx, "BatchGetSimMonthGPRS", params, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimDataUsageMonthlyOutputItem]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty monthly usage"), ResData: model.SimDataUsageMonthlyOutputItem{DeadLine: input.ReqData.QueryDate}})
|
|
continue
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimDataUsageMonthlyOutputItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimDataUsageMonthlyOutputItem{DeadLine: input.ReqData.QueryDate, DataAmount: firstYundaUsage(card)}})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func (s *sSimYunda) QuerySimDataUsageDaily(ctx context.Context, input *model.SimDataUsageDailyInput) (model.SimDataUsageDailyOutput, error) {
|
|
items := make(model.SimDataUsageDailyOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
var result yundaCards
|
|
month, date, dateErr := yundaMonthAndDate(input.ReqData.QueryDate)
|
|
if dateErr != nil {
|
|
items = append(items, &model.SimBaseRes[model.SimDataUsageDailyOutputItem]{Code: consts.ApiStatusError, SimKey: key, Message: dateErr.Error()})
|
|
continue
|
|
}
|
|
params := map[string]string{"month": month, "date": date}
|
|
if key != nil {
|
|
params["iccids"] = key.ICCID
|
|
params["msisdns"] = key.MSISDN
|
|
}
|
|
err := s.clientPost(ctx, "BatchGetSimDayGPRS", params, &result)
|
|
card := firstYundaCard(result)
|
|
amount, date := firstYundaDailyUsage(card, date)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimDataUsageDailyOutputItem]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty daily usage"), ResData: model.SimDataUsageDailyOutputItem{QueryDate: date}})
|
|
continue
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimDataUsageDailyOutputItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimDataUsageDailyOutputItem{QueryDate: date, DataAmount: amount}})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func (s *sSimYunda) QuerySimSession(ctx context.Context, input *model.SimSessionInput) (model.SimSessionOutput, error) {
|
|
items := make(model.SimSessionOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
keyword := yundaCardValue(key, "iccid")
|
|
if keyword == "" {
|
|
keyword = yundaCardValue(key, "msisdn")
|
|
}
|
|
if keyword == "" {
|
|
keyword = yundaCardValue(key, "imsi")
|
|
}
|
|
var result yundaCards
|
|
err := s.clientPost(ctx, "SimOnlineQuery", map[string]string{"keyword": keyword}, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimSessionItem]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty online status")})
|
|
continue
|
|
}
|
|
status := "-1"
|
|
if card.GPRSStatus == "01" || card.GPRSStatusLower == "01" {
|
|
status = "0"
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimSessionItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimSessionItem{ApnId: card.APN, Imei: card.IMEI, Rat: card.RAT, Ipv4: card.IP, Status: status, CreateTime: card.StatTimestamp}})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func (s *sSimYunda) QuerySimDeviceStatus(ctx context.Context, input *model.SimDeviceStatusInput) (model.SimDeviceStatusOutput, error) {
|
|
items := make(model.SimDeviceStatusOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
var result yundaCards
|
|
err := s.requestCard(ctx, "BatchGetSimGPRSStatus", key, map[string]string{"iccids": "iccid", "msisdns": "msisdn"}, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimDeviceStatusItem]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty GPRS status")})
|
|
continue
|
|
}
|
|
status := card.GPRSStatus
|
|
if status == "" {
|
|
status = card.GPRSStatusLower
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimDeviceStatusItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimDeviceStatusItem{DeviceStatus: status}})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func yundaUnsupported[T any](items []*model.SimBaseRes[T], keys []*model.SimKey, operation string) ([]*model.SimBaseRes[T], error) {
|
|
for _, key := range keys {
|
|
items = append(items, &model.SimBaseRes[T]{Code: consts.ApiStatusError, SimKey: key, Message: fmt.Sprintf("yunda does not support %s yet", operation)})
|
|
}
|
|
return items, nil
|
|
}
|
|
func (s *sSimYunda) QuerySimStopReason(ctx context.Context, input *model.SimStopReasonInput) (model.SimStopReasonOutput, error) {
|
|
return yundaUnsupported[model.SimStopReasonItem](nil, input.SimKeys, "stop reason query")
|
|
}
|
|
func (s *sSimYunda) QuerySimFrozenState(ctx context.Context, input *model.SimFrozenStateInput) (model.SimFrozenStateOutput, error) {
|
|
return yundaUnsupported[model.SimFrozenStateItem](nil, input.SimKeys, "frozen state query")
|
|
}
|
|
func (s *sSimYunda) QuerySimDataDiagnosis(ctx context.Context, input *model.SimDataDiagnosisInput) (model.SimDataDiagnosisOutput, error) {
|
|
return yundaUnsupported[any](nil, input.SimKeys, "data diagnosis")
|
|
}
|
|
func (s *sSimYunda) QuerySimApnInfo(ctx context.Context, input *model.SimApnInfoInput) (model.SimApnInfoOutput, error) {
|
|
items := make(model.SimApnInfoOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
keyword := yundaCardValue(key, "iccid")
|
|
if keyword == "" {
|
|
keyword = yundaCardValue(key, "msisdn")
|
|
}
|
|
if keyword == "" {
|
|
keyword = yundaCardValue(key, "imsi")
|
|
}
|
|
var result yundaCards
|
|
err := s.clientPost(ctx, "SimOnlineQuery", map[string]string{"keyword": keyword}, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimApnInfoItemList]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty APN info")})
|
|
continue
|
|
}
|
|
status := "0"
|
|
if strings.TrimSpace(card.APN) != "" {
|
|
status = "1"
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimApnInfoItemList]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimApnInfoItemList{ApnList: []model.SimApnInfoItem{{ApnName: card.APN, Status: status}}}})
|
|
}
|
|
return items, nil
|
|
}
|
|
func (s *sSimYunda) ChangeSimStatus(ctx context.Context, input *model.SimCardStatusChangeInput) (model.SimCardStatusChangeOutput, error) {
|
|
return yundaUnsupported[model.SimCardStatusChangeItem](nil, input.SimKeys, "status change")
|
|
}
|
|
func (s *sSimYunda) ChangeSimApnFunction(ctx context.Context, input *model.SimCardOperateChangeApnInput) (model.SimCardOperateChangeApnOutput, error) {
|
|
return yundaUnsupported[model.SimCardOperateChangeApnItem](nil, input.SimKeys, "APN change")
|
|
}
|
|
func (s *sSimYunda) QuerySimCardBindStatus(ctx context.Context, input *model.SimCardBindStatusInput) (model.SimCardBindStatusOutput, error) {
|
|
items := make(model.SimCardBindStatusOutput, 0, len(input.SimKeys))
|
|
for _, key := range input.SimKeys {
|
|
var result yundaCards
|
|
err := s.requestCard(ctx, "BatchGetSimInfo", key, map[string]string{"iccids": "iccid", "msisdns": "msisdn", "imsis": "imsi"}, &result)
|
|
card := firstYundaCard(result)
|
|
if err != nil || card == nil {
|
|
items = append(items, &model.SimBaseRes[model.SimCardBindStatusItem]{Code: consts.ApiStatusError, SimKey: key, Message: errMessage(err, "yunda returned empty card info")})
|
|
continue
|
|
}
|
|
bindStatus, bindingType := "0", "sim"
|
|
if strings.TrimSpace(card.IMEI) != "" {
|
|
bindStatus, bindingType = "1", "imei"
|
|
}
|
|
items = append(items, &model.SimBaseRes[model.SimCardBindStatusItem]{Code: consts.ApiStatusSuccess, SimKey: key, ResData: model.SimCardBindStatusItem{BindStatus: bindStatus, CardBindingType: bindingType}})
|
|
}
|
|
return items, nil
|
|
}
|
|
func (s *sSimYunda) QuerySimRegionLimitStatus(ctx context.Context, input *model.SimRegionLimitStatusInput) (model.SimRegionLimitStatusOutput, error) {
|
|
return yundaUnsupported[model.SimRegionLimitStatusItem](nil, input.SimKeys, "region limit query")
|
|
}
|
|
|
|
func firstYundaCard(cards yundaCards) *yundaCard {
|
|
if len(cards) == 0 {
|
|
return nil
|
|
}
|
|
return &cards[0]
|
|
}
|
|
func firstYundaUsage(card *yundaCard) float64 {
|
|
if card == nil || len(card.APNList) == 0 {
|
|
return 0
|
|
}
|
|
return float64(card.APNList[0].UsedFlow)
|
|
}
|
|
func firstYundaDailyUsage(card *yundaCard, fallback string) (float64, string) {
|
|
if card == nil || len(card.APNList) == 0 || len(card.APNList[0].DailyList) == 0 {
|
|
return 0, fallback
|
|
}
|
|
item := card.APNList[0].DailyList[0]
|
|
if item.Date == "" {
|
|
item.Date = fallback
|
|
}
|
|
return float64(item.UsedFlow), item.Date
|
|
}
|
|
func yundaBasicError(key *model.SimKey, err error) *model.SimBaseRes[model.SimBasicInfoItem] {
|
|
return &model.SimBaseRes[model.SimBasicInfoItem]{Code: consts.ApiStatusError, SimKey: key, Message: err.Error()}
|
|
}
|
|
func errOr(err error, fallback string) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return errors.New(fallback)
|
|
}
|
|
|
|
func errMessage(err error, fallback string) string {
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func yundaMonthAndDate(value string) (string, string, error) {
|
|
value = strings.TrimSpace(value)
|
|
for _, layout := range []string{"20060102", "2006-01-02"} {
|
|
parsed, err := time.Parse(layout, value)
|
|
if err == nil {
|
|
return parsed.Format("2006-01"), parsed.Format("2006-01-02"), nil
|
|
}
|
|
}
|
|
return "", "", fmt.Errorf("invalid daily queryDate: %s", value)
|
|
}
|