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
266 lines
9.3 KiB
Go
266 lines
9.3 KiB
Go
package upstreamimpl
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/consts"
|
|
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/model"
|
|
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/service"
|
|
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/service/daihe"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
)
|
|
|
|
const daiheTemplateKey = "sim_daihe_v1"
|
|
|
|
type daiheConfig struct {
|
|
AppID string `json:"appId"`
|
|
AppSecret string `json:"appSecret"`
|
|
BaseURL string `json:"baseUrl"`
|
|
Timeout string `json:"timeout"`
|
|
API struct {
|
|
BaseURL string `json:"baseUrl"`
|
|
Timeout string `json:"timeout"`
|
|
} `json:"api"`
|
|
}
|
|
type daiheUsage struct {
|
|
ICCID string `json:"iccid"`
|
|
Month int `json:"month"`
|
|
Used float64 `json:"used"`
|
|
}
|
|
type daiheStatus struct {
|
|
ICCID string `json:"iccid"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
type sSimDaihe struct {
|
|
channelConfig *model.SimChannelConfigItemCache
|
|
client *daihe.Client
|
|
}
|
|
|
|
func init() { service.UpstreamAPI().RegisterTemp(daiheTemplateKey, NewSimDaihe()) }
|
|
func NewSimDaihe() *sSimDaihe { return &sSimDaihe{} }
|
|
|
|
func parseDaiheConfig(raw string) daiheConfig {
|
|
var cfg daiheConfig
|
|
_ = json.Unmarshal([]byte(raw), &cfg)
|
|
return cfg
|
|
}
|
|
func pickDaiheConfig(cfg *model.SimChannelConfigItemCache) (daiheConfig, bool) {
|
|
if cfg == nil || cfg.Channel == nil || cfg.Template == nil {
|
|
return daiheConfig{}, false
|
|
}
|
|
channel := parseDaiheConfig(cfg.Channel.ChanConfig)
|
|
template := parseDaiheConfig(cfg.Template.TempConfig)
|
|
out := template
|
|
if strings.TrimSpace(channel.AppID) != "" {
|
|
out.AppID = channel.AppID
|
|
}
|
|
if strings.TrimSpace(channel.AppSecret) != "" {
|
|
out.AppSecret = channel.AppSecret
|
|
}
|
|
if strings.TrimSpace(channel.BaseURL) != "" {
|
|
out.BaseURL = channel.BaseURL
|
|
}
|
|
if strings.TrimSpace(channel.API.BaseURL) != "" {
|
|
out.BaseURL = channel.API.BaseURL
|
|
}
|
|
if strings.TrimSpace(channel.Timeout) != "" {
|
|
out.Timeout = channel.Timeout
|
|
}
|
|
if strings.TrimSpace(channel.API.Timeout) != "" {
|
|
out.Timeout = channel.API.Timeout
|
|
}
|
|
if out.AppID == "" {
|
|
out.AppID = cfg.Channel.AppKey
|
|
}
|
|
if out.AppSecret == "" {
|
|
out.AppSecret = cfg.Channel.AppSecret
|
|
}
|
|
if out.BaseURL == "" {
|
|
out.BaseURL = "https://open.flymodem.com.cn"
|
|
}
|
|
return out, out.AppID != "" && out.AppSecret != ""
|
|
}
|
|
|
|
func (s *sSimDaihe) NewTemp(ctx context.Context, cfg *model.SimChannelConfigItemCache) model.SimCardChannelI {
|
|
raw, ok := pickDaiheConfig(cfg)
|
|
if !ok {
|
|
g.Log().Warning(ctx, "daihe.NewTemp: missing appId/appSecret")
|
|
return nil
|
|
}
|
|
timeout := 15 * time.Second
|
|
if d, err := time.ParseDuration(raw.Timeout); err == nil && d > 0 {
|
|
timeout = d
|
|
}
|
|
return &sSimDaihe{channelConfig: cfg, client: daihe.NewClient(daihe.Config{BaseURL: raw.BaseURL, AppID: raw.AppID, AppSecret: raw.AppSecret, Timeout: timeout})}
|
|
}
|
|
|
|
func daiheICCID(key *model.SimKey) string {
|
|
if key == nil {
|
|
return ""
|
|
}
|
|
return strings.TrimSpace(key.ICCID)
|
|
}
|
|
func daiheStatusCode(status string) (int, bool) {
|
|
switch strings.TrimSpace(status) {
|
|
case "库存":
|
|
return 7, true
|
|
case "可测试", "测试激活", "测试去激活":
|
|
return 6, true
|
|
case "可激活", "开始":
|
|
return 1, true
|
|
case "已激活":
|
|
return 2, true
|
|
case "已停用":
|
|
return 4, true
|
|
case "预清除":
|
|
return 8, true
|
|
case "已清除", "已失效", "已更换":
|
|
return 9, true
|
|
default:
|
|
return 0, false
|
|
}
|
|
}
|
|
func daiheUnsupported[T any](keys []*model.SimKey, name string) (out []*model.SimBaseRes[T], err error) {
|
|
for _, key := range keys {
|
|
out = append(out, &model.SimBaseRes[T]{Code: consts.ApiStatusError, SimKey: key, Message: "daihe does not support " + name})
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s *sSimDaihe) QuerySimCardStatus(ctx context.Context, in *model.SimCardStatusInput) (out model.SimCardStatusOutput, err error) {
|
|
for _, key := range in.SimKeys {
|
|
r := &model.SimBaseRes[model.SimCardStatusItem]{SimKey: key}
|
|
iccid := daiheICCID(key)
|
|
var data daiheStatus
|
|
if iccid == "" {
|
|
r.Code = consts.ApiStatusError
|
|
r.Message = "iccid is required"
|
|
} else if e := s.client.QueryStatus(ctx, iccid, &data); e != nil {
|
|
r.Code = consts.ApiStatusError
|
|
r.Message = e.Error()
|
|
} else if status, ok := daiheStatusCode(data.Status); !ok {
|
|
r.Code = consts.ApiStatusError
|
|
r.Message = fmt.Sprintf("unsupported daihe card status: %s", data.Status)
|
|
} else {
|
|
r.Code = consts.ApiStatusSuccess
|
|
r.ResData.CardStatus = status
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return
|
|
}
|
|
func (s *sSimDaihe) QuerySimDataUsage(ctx context.Context, in *model.SimDataUsageInput) (out model.SimDataUsageOutput, err error) {
|
|
return s.queryUsage(ctx, in, "")
|
|
}
|
|
func (s *sSimDaihe) QuerySimDataUsageMonthly(ctx context.Context, in *model.SimDataUsageMonthlyInput) (out model.SimDataUsageMonthlyOutput, err error) {
|
|
month := ""
|
|
if in != nil {
|
|
month = strings.TrimSpace(in.ReqData.QueryDate)
|
|
}
|
|
result := make(model.SimDataUsageMonthlyOutput, 0, len(in.SimKeys))
|
|
for _, key := range in.SimKeys {
|
|
r := &model.SimBaseRes[model.SimDataUsageMonthlyOutputItem]{SimKey: key}
|
|
iccid := daiheICCID(key)
|
|
var data daiheUsage
|
|
if iccid == "" {
|
|
r.Code = consts.ApiStatusError
|
|
r.Message = "iccid is required"
|
|
} else if e := s.client.QueryUsage(ctx, iccid, month, &data); e != nil {
|
|
r.Code = consts.ApiStatusError
|
|
r.Message = e.Error()
|
|
} else {
|
|
r.Code = consts.ApiStatusSuccess
|
|
r.ResData.DeadLine = fmt.Sprintf("%06d", data.Month)
|
|
r.ResData.DataAmount = data.Used
|
|
}
|
|
result = append(result, r)
|
|
}
|
|
return result, nil
|
|
}
|
|
func (s *sSimDaihe) queryUsage(ctx context.Context, in *model.SimDataUsageInput, month string) (out model.SimDataUsageOutput, err error) {
|
|
for _, key := range in.SimKeys {
|
|
r := &model.SimBaseRes[model.SimDataUsageItem]{SimKey: key}
|
|
iccid := daiheICCID(key)
|
|
var data daiheUsage
|
|
if iccid == "" {
|
|
r.Code = consts.ApiStatusError
|
|
r.Message = "iccid is required"
|
|
} else if e := s.client.QueryUsage(ctx, iccid, month, &data); e != nil {
|
|
r.Code = consts.ApiStatusError
|
|
r.Message = e.Error()
|
|
} else {
|
|
r.Code = consts.ApiStatusSuccess
|
|
r.ResData.DataUsage = data.Used
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return
|
|
}
|
|
func (s *sSimDaihe) ChangeSimStatus(ctx context.Context, in *model.SimCardStatusChangeInput) (out model.SimCardStatusChangeOutput, err error) {
|
|
op, ok := normalizeCardStatusChangeOperType(ctx, in.ReqData.OperType)
|
|
if !ok {
|
|
return newInvalidCardStatusChangeOutput(in.SimKeys), nil
|
|
}
|
|
for _, key := range in.SimKeys {
|
|
r := &model.SimBaseRes[model.SimCardStatusChangeItem]{SimKey: key}
|
|
iccid := daiheICCID(key)
|
|
var e error
|
|
if iccid == "" {
|
|
e = fmt.Errorf("iccid is required")
|
|
} else if op == consts.CardStatusChangeOperTypeApplyStop {
|
|
e = s.client.Deactivate(ctx, iccid)
|
|
} else {
|
|
e = s.client.Activate(ctx, iccid)
|
|
}
|
|
if e != nil {
|
|
r.Code = consts.ApiStatusError
|
|
r.Message = e.Error()
|
|
} else {
|
|
r.Code = consts.ApiStatusSuccess
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return
|
|
}
|
|
func (s *sSimDaihe) QuerySimBasicInfo(ctx context.Context, in *model.SimBasicInfoInput) (model.SimBasicInfoOutput, error) {
|
|
return daiheUnsupported[model.SimBasicInfoItem](in.SimKeys, "basic info query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimSession(ctx context.Context, in *model.SimSessionInput) (model.SimSessionOutput, error) {
|
|
return daiheUnsupported[model.SimSessionItem](in.SimKeys, "session query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimStopReason(ctx context.Context, in *model.SimStopReasonInput) (model.SimStopReasonOutput, error) {
|
|
return daiheUnsupported[model.SimStopReasonItem](in.SimKeys, "stop reason query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimFrozenState(ctx context.Context, in *model.SimFrozenStateInput) (model.SimFrozenStateOutput, error) {
|
|
return daiheUnsupported[model.SimFrozenStateItem](in.SimKeys, "frozen state query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimCardBindStatus(ctx context.Context, in *model.SimCardBindStatusInput) (model.SimCardBindStatusOutput, error) {
|
|
return daiheUnsupported[model.SimCardBindStatusItem](in.SimKeys, "card binding query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimDeviceStatus(ctx context.Context, in *model.SimDeviceStatusInput) (model.SimDeviceStatusOutput, error) {
|
|
return daiheUnsupported[model.SimDeviceStatusItem](in.SimKeys, "device status query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimRegionLimitStatus(ctx context.Context, in *model.SimRegionLimitStatusInput) (model.SimRegionLimitStatusOutput, error) {
|
|
return daiheUnsupported[model.SimRegionLimitStatusItem](in.SimKeys, "region limit query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimImei(ctx context.Context, in *model.SimImeiInput) (model.SimImeiOutput, error) {
|
|
return daiheUnsupported[model.SimImeiItem](in.SimKeys, "IMEI query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimDataDiagnosis(ctx context.Context, in *model.SimDataDiagnosisInput) (model.SimDataDiagnosisOutput, error) {
|
|
return daiheUnsupported[any](in.SimKeys, "data diagnosis")
|
|
}
|
|
func (s *sSimDaihe) QuerySimDataUsageDaily(ctx context.Context, in *model.SimDataUsageDailyInput) (model.SimDataUsageDailyOutput, error) {
|
|
return daiheUnsupported[model.SimDataUsageDailyOutputItem](in.SimKeys, "daily usage query")
|
|
}
|
|
func (s *sSimDaihe) QuerySimApnInfo(ctx context.Context, in *model.SimApnInfoInput) (model.SimApnInfoOutput, error) {
|
|
return daiheUnsupported[model.SimApnInfoItemList](in.SimKeys, "APN query")
|
|
}
|
|
func (s *sSimDaihe) ChangeSimApnFunction(ctx context.Context, in *model.SimCardOperateChangeApnInput) (model.SimCardOperateChangeApnOutput, error) {
|
|
return daiheUnsupported[model.SimCardOperateChangeApnItem](in.SimKeys, "APN change")
|
|
}
|