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") }