package upstream import ( "context" "encoding/json" "fmt" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service" "net/http" "net/url" "strings" "time" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/gclient" "github.com/gogf/gf/v2/net/gsvc" ) type sUpstreamChan struct { } type upstreamConfigSceneKey struct{} func diagnosisQueryURL(ctx context.Context, client *gclient.Client, address string, path string) string { if scene, _ := ctx.Value(upstreamConfigSceneKey{}).(string); scene == upstreamConfigSceneDiagnose { client.SetContentType("application/json") if token := strings.TrimSpace(g.Cfg().MustGet(ctx, "upstream.appDiagnosisToken").String()); token != "" { client.SetHeader("X-App-Diagnosis-Token", token) path = "/internal/app-diagnosis" + path } } return fmt.Sprintf("http://%s%s", address, path) } type preserveUpstreamResultsKey struct{} const upstreamConfigSceneDiagnose = "diagnose" const upstreamConfigSceneGateway = "gateway" const upstreamRefreshMaxTimeout = 15 * time.Second // WithDiagnoseUpstreamConfig selects the authenticated diagnosis proxy endpoint. func WithDiagnoseUpstreamConfig(ctx context.Context) context.Context { return context.WithValue(ctx, upstreamConfigSceneKey{}, upstreamConfigSceneDiagnose) } // WithGatewayUpstreamConfig marks calls that must use the configured gateway // endpoint without falling back to the proxy endpoint. func WithGatewayUpstreamConfig(ctx context.Context) context.Context { return context.WithValue(ctx, upstreamConfigSceneKey{}, upstreamConfigSceneGateway) } // WithPreservedUpstreamResults keeps failed per-card results for diagnostic callers. // Normal business callers continue to receive only successful items. func WithPreservedUpstreamResults(ctx context.Context) context.Context { return context.WithValue(ctx, preserveUpstreamResultsKey{}, true) } func preserveUpstreamResults(ctx context.Context) bool { preserve, _ := ctx.Value(preserveUpstreamResultsKey{}).(bool) return preserve } func setClientTimeout(client *gclient.Client, timeout time.Duration) { client.SetTimeout(timeout) if transport, ok := client.Transport.(*http.Transport); ok { transport.ResponseHeaderTimeout = timeout } } func NewUpstreamChan() *sUpstreamChan { return &sUpstreamChan{} } func init() { service.RegisterUpstreamChan(NewUpstreamChan()) } func (s *sUpstreamChan) GetUpstreamChanConfig(ctx context.Context) (output model.UpstreamChanConfig, err error) { if scene, _ := ctx.Value(upstreamConfigSceneKey{}).(string); scene == upstreamConfigSceneDiagnose { value, getErr := g.Cfg().Get(ctx, "upstream.appDiagnosisToken") if getErr != nil { return output, gerror.Wrap(getErr, "读取智能诊断代理凭据失败") } if value == nil || strings.TrimSpace(value.String()) == "" { return output, gerror.New("智能诊断代理凭据未配置") } return s.getUpstreamChanConfigFromPaths(ctx, "upstream.proxy") } if scene, _ := ctx.Value(upstreamConfigSceneKey{}).(string); scene == upstreamConfigSceneGateway { return s.getUpstreamChanConfigFromPaths(ctx, "upstream.gateway") } return s.getUpstreamChanConfigFromPaths(ctx, "upstream.proxy") } func (s *sUpstreamChan) getUpstreamChanConfigFromPaths(ctx context.Context, paths ...string) (output model.UpstreamChanConfig, err error) { var lastErr error for _, path := range paths { value, getErr := g.Cfg().Get(ctx, path) if getErr != nil { lastErr = getErr continue } if value == nil { continue } var cfg model.UpstreamChanConfig if scanErr := value.Scan(&cfg); scanErr != nil { lastErr = scanErr continue } if strings.TrimSpace(cfg.Address) == "" { continue } if cfg.Timeout <= 0 { cfg.Timeout = 10 * time.Second } return cfg, nil } if lastErr != nil { return output, lastErr } return output, gerror.New("upstream chan config not found") } type upstreamRefreshResponse struct { Code int `json:"code"` Message string `json:"message"` } func (s *sUpstreamChan) RefreshGatewayChannel(ctx context.Context, chanKey string) error { return s.refreshChannel(ctx, upstreamConfigSceneGateway, chanKey) } func (s *sUpstreamChan) RefreshProxyChannel(ctx context.Context, chanKey string) error { return s.refreshChannel(ctx, "", chanKey) } func (s *sUpstreamChan) TestChannel(ctx context.Context, input *model.UpstreamChannelTestRequest) (*model.TSimChannelsTestOutput, error) { if input == nil || input.ChannelID <= 0 || strings.TrimSpace(input.TenantID) == "" { return nil, gerror.New("通道不存在或无权访问") } config, err := s.getUpstreamChanConfigFromPaths(ctx, "upstream.gateway") if err != nil { return nil, gerror.Wrap(err, "获取上游通道配置失败") } requestCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) defer cancel() client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) // The upstream endpoint applies its own per-item timeout and executes items // sequentially. Keep the client alive for the whole bounded request. setClientTimeout(client, 2*time.Minute) body, err := json.Marshal(input) if err != nil { return nil, gerror.Wrap(err, "序列化通道测试请求失败") } client.SetHeader("Content-Type", "application/json") response, err := client.Post(requestCtx, fmt.Sprintf("http://%s/internal/channel/test", config.Address), body) if err != nil { return nil, gerror.Wrap(err, "请求上游通道测试失败") } defer response.Close() responseBody := response.ReadAll() var envelope struct { Code int `json:"code"` Message string `json:"message"` Data model.TSimChannelsTestOutput `json:"data"` } if err := json.Unmarshal(responseBody, &envelope); err != nil { return nil, &model.TSimChannelsTestError{ Err: gerror.Wrap(err, "解析上游通道测试响应失败"), GatewayResponseRaw: string(responseBody), } } if envelope.Code != 0 { if envelope.Message == "" { envelope.Message = "上游通道测试失败" } return nil, &model.TSimChannelsTestError{ Err: gerror.New(envelope.Message), GatewayResponseRaw: string(responseBody), } } envelope.Data.GatewayResponseRaw = string(responseBody) for _, item := range envelope.Data.Items { if item != nil { item.ResponseJSON = string(responseBody) } } return &envelope.Data, nil } func (s *sUpstreamChan) refreshChannel(ctx context.Context, scene string, chanKey string) error { if strings.TrimSpace(chanKey) == "" { return gerror.New("chanKey is required") } refreshCtx := ctx if scene == upstreamConfigSceneGateway { refreshCtx = WithGatewayUpstreamConfig(ctx) } chanConfig, err := s.GetUpstreamChanConfig(refreshCtx) if err != nil { return err } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) timeout := chanConfig.Timeout if timeout <= 0 || timeout > upstreamRefreshMaxTimeout { timeout = upstreamRefreshMaxTimeout } requestCtx, cancel := context.WithTimeout(ctx, timeout) defer cancel() setClientTimeout(client, timeout) refreshURL := fmt.Sprintf("http://%s/internal/channel/refresh?chanKey=%s", chanConfig.Address, url.QueryEscape(chanKey)) resp, err := client.Post(requestCtx, refreshURL, nil) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.refreshChannel, post error %+v, scene %s, url %s", err, scene, refreshURL) return err } var output upstreamRefreshResponse if err := json.Unmarshal(resp.ReadAll(), &output); err != nil { g.Log().Errorf(ctx, "sUpstreamChan.refreshChannel, unmarshal error %+v, scene %s, url %s", err, scene, refreshURL) return err } if output.Code != 0 { if output.Message == "" { output.Message = "refresh channel failed" } return gerror.New(output.Message) } return nil } // 获取卡基本信息 func (s *sUpstreamChan) QuerySimBasicInfo(ctx context.Context, input *model.SimBasicInfoInput) ([]model.SimBaseRes[model.SimBasicInfoItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimBasicInfo, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-basic-info", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-basic-info") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimBasicInfo, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimBasicInfoOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimBasicInfo, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimBasicInfo, query sim basic info error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var basicInfo []model.SimBaseRes[model.SimBasicInfoItem] for _, item := range output.Data { if item.Code != 0 && !preserveUpstreamResults(ctx) { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimBasicInfo, query sim basic info error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } basicInfo = append(basicInfo, item) } return basicInfo, nil } // 查询会话信息 func (s *sUpstreamChan) QuerySimSession(ctx context.Context, input *model.SimSessionInput) ([]model.SimBaseRes[model.SimSessionItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimSession, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-session", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-session") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimSession, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimSessionOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimSession, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimSession, query sim session error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var session []model.SimBaseRes[model.SimSessionItem] for _, item := range output.Data { if item.Code != 0 && !preserveUpstreamResults(ctx) { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimSession, query sim session error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } session = append(session, item) } return session, nil } // 查询状态 func (s *sUpstreamChan) QuerySimCardStatus(ctx context.Context, input *model.SimCardStatusInput) ([]model.SimBaseRes[model.SimCardStatusItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimCardStatus, get upstream chan config error %+v, path %s", err, "/sim/query/sim-card-status") return nil, gerror.Wrap(err, "获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-status") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimCardStatus, post error %+v, url %s, count %d", err, url, len(input.SimKeys)) return nil, gerror.Wrap(err, "请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } cardStatus, err := parseSimCardStatusResponse(body) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimCardStatus, response error %+v, url %s, count %d", err, url, len(input.SimKeys)) return nil, err } if preserveUpstreamResults(ctx) { for index := range cardStatus { if cardStatus[index].Code == 0 && !diagnosisNumericValuePresent(body, index, "cardStatus") { cardStatus[index].Code = 500 cardStatus[index].Message = "卡状态未返回有效数值" } } } return cardStatus, nil } func parseSimCardStatusResponse(body []byte) ([]model.SimBaseRes[model.SimCardStatusItem], error) { output := model.SimCardStatusOutput{} if err := json.Unmarshal(body, &output); err != nil { return nil, gerror.Wrap(err, "解析响应失败") } if output.Code != 0 { return nil, gerror.New(output.Message) } return output.Data, nil } func normalizeSimCardBindStatus(item model.SimCardBindStatusItem) string { if status := strings.TrimSpace(item.BindStatus); status != "" { switch status { case "0", "1", "2": return status } } cardBindingType := strings.TrimSpace(item.CardBindingType) switch cardBindingType { case "1", "2", "3", "4", "5": return "1" case "", "-1": return "2" default: return "2" } } // 查询IMEI func (s *sUpstreamChan) QuerySimStopReason(ctx context.Context, input *model.SimStopReasonInput) ([]model.SimBaseRes[model.SimStopReasonItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimStopReason, get upstream chan config error %+v, path %s", err, "/sim/query/sim-stop-reason") return nil, gerror.Wrap(err, "获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-stop-reason") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimStopReason, post error %+v, url %s, count %d", err, url, len(input.SimKeys)) return nil, gerror.Wrap(err, "请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimStopReasonOutput{} if err = json.Unmarshal([]byte(body), &output); err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimStopReason, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimStopReason, query sim stop reason error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var stopReason []model.SimBaseRes[model.SimStopReasonItem] for _, item := range output.Data { if item.Code != 0 && !preserveUpstreamResults(ctx) { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimStopReason, query sim stop reason error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } stopReason = append(stopReason, item) } return stopReason, nil } func (s *sUpstreamChan) QuerySimFrozenState(ctx context.Context, input *model.SimFrozenStateInput) ([]model.SimBaseRes[model.SimFrozenStateItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimFrozenState, get upstream chan config error %+v, path %s", err, "/sim/query/sim-frozen-state") return nil, gerror.Wrap(err, "获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-frozen-state") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimFrozenState, post error %+v, url %s, count %d", err, url, len(input.SimKeys)) return nil, gerror.Wrap(err, "请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimFrozenStateOutput{} if err = json.Unmarshal([]byte(body), &output); err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimFrozenState, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimFrozenState, query sim frozen state error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var frozenState []model.SimBaseRes[model.SimFrozenStateItem] for _, item := range output.Data { if item.Code != 0 && !preserveUpstreamResults(ctx) { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimFrozenState, query sim frozen state error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } frozenState = append(frozenState, item) } return frozenState, nil } func (s *sUpstreamChan) QuerySimImei(ctx context.Context, input *model.SimImeiInput) ([]model.SimBaseRes[model.SimImeiItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimImei, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-imei", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-imei") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimImei, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimImeiOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimImei, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimImei, query sim imei error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var imei []model.SimBaseRes[model.SimImeiItem] for _, item := range output.Data { if item.Code != 0 && !preserveUpstreamResults(ctx) { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimImei, query sim imei error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } imei = append(imei, item) } return imei, nil } // 查询流量 func (s *sUpstreamChan) QuerySimDatausage(ctx context.Context, input *model.SimDataUsageInput) ([]model.SimBaseRes[model.SimDataUsageItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDataUsage, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-datausage", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-datausage") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDataUsage, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } dataUsage, err := parseSimDataUsageResponse(body) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDataUsage, response error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, err } if preserveUpstreamResults(ctx) { for index := range dataUsage { if dataUsage[index].Code == 0 && !diagnosisNumericValuePresent(body, index, "dataUsage") { dataUsage[index].Code = 500 dataUsage[index].Message = "实时流量未返回有效数值" } } } return dataUsage, nil } func parseSimDataUsageResponse(body []byte) ([]model.SimBaseRes[model.SimDataUsageItem], error) { output := model.SimDataUsageOutput{} if err := json.Unmarshal(body, &output); err != nil { return nil, gerror.Wrap(err, "解析响应失败") } if output.Code != 0 { return nil, gerror.New(output.Message) } return output.Data, nil } // 查询达量限速档位 func (s *sUpstreamChan) QuerySimDataDiagnosis(ctx context.Context, input *model.SimDataDiagnosisInput) ([]model.SimBaseRes[model.SimDataDiagnosisItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDataDiagnosis, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-data-diagnosis", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-data-diagnosis") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDataDiagnosis, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimResponseData[json.RawMessage]{} if err = json.Unmarshal([]byte(body), &output); err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDataDiagnosis, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimDataDiagnosis, query sim data diagnosis error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } items := make([]model.SimBaseRes[model.SimDataDiagnosisItem], 0, len(output.Data)) for _, item := range output.Data { switch item.Code { case 5000: items = append(items, model.SimBaseRes[model.SimDataDiagnosisItem]{ Code: item.Code, Message: item.Message, SimKey: item.SimKey, ResData: model.SimDataDiagnosisItem{ RateLimitStatus: "3", RateLimitReason: item.Message, }, }) case 0: parsed, parseErr := parseYdDataDiagnosisBody(item.ResData) if parseErr != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDataDiagnosis, parse body error %+v,url %s, params %+v, body %s, ", parseErr, url, input, item.ResData) items = append(items, model.SimBaseRes[model.SimDataDiagnosisItem]{ Code: 1, Message: "解析响应失败", SimKey: item.SimKey, ResData: model.SimDataDiagnosisItem{RateLimitStatus: "2"}, }) continue } items = append(items, model.SimBaseRes[model.SimDataDiagnosisItem]{ Code: item.Code, Message: item.Message, SimKey: item.SimKey, ResData: parsed, }) default: items = append(items, model.SimBaseRes[model.SimDataDiagnosisItem]{ Code: item.Code, Message: item.Message, SimKey: item.SimKey, ResData: model.SimDataDiagnosisItem{RateLimitStatus: "2"}, }) } } return items, nil } // 查询月流量 func (s *sUpstreamChan) QuerySimDatausageMonthly(ctx context.Context, input *model.SimDataUsageMonthlyInput) ([]model.SimBaseRes[model.SimDataUsageMonthlyOutputItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDatausageMonthly, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-datausage-monthly", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) g.Log().Debug(ctx, chanConfig.Timeout*time.Duration(len(input.SimKeys))) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-datausage-monthly") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDatausageMonthly, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body := resp.ReadAll() output := model.SimDataUsageMonthlyOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDatausageMonthly, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimDatausageMonthly, query sim datausage monthly error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var dataUsage []model.SimBaseRes[model.SimDataUsageMonthlyOutputItem] for _, item := range output.Data { if item.Code != 0 && !preserveUpstreamResults(ctx) { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimDatausageMonthly, query sim datausage monthly error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } dataUsage = append(dataUsage, item) } return dataUsage, nil } // 查询日流量 func (s *sUpstreamChan) QuerySimDatausageDaily(ctx context.Context, input *model.SimDataUsageDailyInput) ([]model.SimBaseRes[model.SimDataUsageDailyOutputItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDatausageDaily, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-datausage-daily", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-datausage-daily") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDatausageDaily, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body := resp.ReadAll() output := model.SimDataUsageDailyOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDatausageDaily, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimDatausageDaily, query sim datausage daily error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var dataUsage []model.SimBaseRes[model.SimDataUsageDailyOutputItem] for _, item := range output.Data { if item.Code != 0 && !preserveUpstreamResults(ctx) { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimDatausageDaily, query sim datausage daily error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } dataUsage = append(dataUsage, item) } return dataUsage, nil } // 查询已开通APN信息 func (s *sUpstreamChan) QuerySimApnInfo(ctx context.Context, input *model.SimApnInfoInput) ([]model.SimBaseRes[model.SimApnInfoItemList], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimApnInfo, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-apn-info", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-apn-info") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimApnInfo, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimApnInfoOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimApnInfo, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimApnInfo, query sim apn info error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var apnInfo []model.SimBaseRes[model.SimApnInfoItemList] for _, item := range output.Data { if item.Code != 0 && !preserveUpstreamResults(ctx) { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimApnInfo, query sim apn info error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } apnInfo = append(apnInfo, item) } return apnInfo, nil } // 卡状态变更 func (s *sUpstreamChan) ChangeSimStatus(ctx context.Context, input *model.SimCardStatusChangeInput) ([]model.SimBaseRes[model.SimCardStatusChangeItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.ChangeSimStatus, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/change/sim-status", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/change/sim-status") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.ChangeSimStatus, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body := resp.ReadAll() output := model.SimCardStatusChangeOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.ChangeSimStatus, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.ChangeSimStatus, change sim status error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var statusList []model.SimBaseRes[model.SimCardStatusChangeItem] for _, item := range output.Data { if item.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.ChangeSimStatus, change sim status error %+v, path %s, params %+v, body %s, ", err, url, input, body) } statusList = append(statusList, item) } return statusList, nil } // 卡APN功能开停 func (s *sUpstreamChan) ChangeSimApnFunction(ctx context.Context, input *model.SimCardOperateChangeApnInput) ([]model.SimBaseRes[model.SimCardOperateChangeApnItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.ChangeSimApnFunction, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/change/sim-apn", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/change/sim-apn") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.ChangeSimApnFunction, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body := resp.ReadAll() output := model.SimCardOperateChangeApnOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.ChangeSimApnFunction, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.ChangeSimApnFunction, change sim apn function error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } var statusList []model.SimBaseRes[model.SimCardOperateChangeApnItem] for _, item := range output.Data { if item.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.ChangeSimApnFunction, change sim apn function error %+v, path %s, params %+v, body %s, ", err, url, input, body) continue } statusList = append(statusList, item) } return statusList, nil } // 查询机卡绑定状态 func (s *sUpstreamChan) QuerySimCardBindStatus(ctx context.Context, input *model.SimCardBindStatusInput) ([]model.SimBaseRes[model.SimCardBindStatusItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimCardBindStatus, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-card-bind-status", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-card-bind-status") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimCardBindStatus, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimCardBindStatusOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimCardBindStatus, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimCardBindStatus, query sim card bind status error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } for i := range output.Data { if output.Data[i].Code != 0 { continue } output.Data[i].ResData.BindStatus = normalizeSimCardBindStatus(output.Data[i].ResData) } return output.Data, nil } // 查询设备状态 func (s *sUpstreamChan) QuerySimDeviceStatus(ctx context.Context, input *model.SimDeviceStatusInput) ([]model.SimBaseRes[model.SimDeviceStatusItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDeviceStatus, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-device-status", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-device-status") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDeviceStatus, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimDeviceStatusOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimDeviceStatus, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimDeviceStatus, query sim device status error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } return output.Data, nil } // 查询地域限制状态 func (s *sUpstreamChan) QuerySimRegionLimitStatus(ctx context.Context, input *model.SimRegionLimitStatusInput) ([]model.SimBaseRes[model.SimRegionLimitStatusItem], error) { chanConfig, err := s.GetUpstreamChanConfig(ctx) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimRegionLimitStatus, get upstream chan config error %+v, path %s, input %+v, ", err, "/sim/query/sim-region-limit-status", input) return nil, gerror.New("获取上游通道配置失败") } client := g.Client() client.SetDiscovery(gsvc.GetRegistry()) setClientTimeout(client, chanConfig.Timeout*time.Duration(len(input.SimKeys))) url := diagnosisQueryURL(ctx, client, chanConfig.Address, "/sim/query/sim-region-limit-status") resp, err := client.Post(ctx, url, input) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimRegionLimitStatus, post error %+v,url %s, params %+v, ", err, url, input) return nil, gerror.New("请求失败") } body, err := readQueryResponse(ctx, resp) if err != nil { return nil, err } output := model.SimRegionLimitStatusOutput{} err = json.Unmarshal([]byte(body), &output) if err != nil { g.Log().Errorf(ctx, "sUpstreamChan.QuerySimRegionLimitStatus, unmarshal error %+v,url %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New("解析响应失败") } if output.Code != 0 { g.Log().Debugf(ctx, "sUpstreamChan.QuerySimRegionLimitStatus, query sim region limit status error %+v, path %s, params %+v, body %s, ", err, url, input, body) return nil, gerror.New(output.Message) } return output.Data, nil }