sync: 同步 v1.0.4 开源代码并脱敏
This commit is contained in:
@@ -3,6 +3,8 @@ package upstreamimpl
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -10,7 +12,6 @@ import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/model"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// 移动 OneLink「通信功能开停」接口(2026 接口改版后,替代原 ec/operate/sim-apn-function)。
|
||||
@@ -75,6 +76,9 @@ type ydApnRequester interface {
|
||||
// changeSimApnFunctionYD 平台「开通数据(dataStart)/停用数据(dataStop)/达量断网(dataCut)」在移动侧的统一入口。
|
||||
func changeSimApnFunctionYD(ctx context.Context, c ydApnRequester, input *model.SimCardOperateChangeApnInput) (model.SimCardOperateChangeApnOutput, error) {
|
||||
items := make(model.SimCardOperateChangeApnOutput, 0, len(input.SimKeys))
|
||||
if jobID := strings.TrimSpace(input.ReqData.QueryJobID); jobID != "" {
|
||||
return mapYdQueryResult(input.SimKeys, jobID, queryBatchResultOnceYD(ctx, c, jobID)), nil
|
||||
}
|
||||
|
||||
// 缺 msisdn 的卡不能进批量接口,先分流出来单独走单卡。
|
||||
withMsisdn := make([]*model.SimKey, 0, len(input.SimKeys))
|
||||
@@ -101,9 +105,29 @@ func changeSimApnFunctionYD(ctx context.Context, c ydApnRequester, input *model.
|
||||
continue
|
||||
}
|
||||
items = append(items, changeApnBatchYD(ctx, c, chunk, input.ReqData)...)
|
||||
if input.ReqData.SubmitOnly {
|
||||
if checkpoint, ok := ctx.Value(model.ApnOperationCheckpointKey{}).(func(model.SimCardOperateChangeApnOutput) error); ok {
|
||||
if err := checkpoint(items); err != nil {
|
||||
g.Log().Errorf(ctx, "APN批量结果持久化失败 operationId=%s error=%v", input.ReqData.OperationID, err)
|
||||
return items, fmt.Errorf("APN批量结果持久化失败,停止后续办理:%w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items = append(items, changeApnSingleYD(ctx, c, singleKeys, input.ReqData)...)
|
||||
if input.ReqData.SubmitOnly {
|
||||
for _, key := range singleKeys {
|
||||
items = append(items, changeApnSingleYD(ctx, c, []*model.SimKey{key}, input.ReqData)...)
|
||||
if checkpoint, ok := ctx.Value(model.ApnOperationCheckpointKey{}).(func(model.SimCardOperateChangeApnOutput) error); ok {
|
||||
if err := checkpoint(items); err != nil {
|
||||
g.Log().Errorf(ctx, "APN单卡结果持久化失败 operationId=%s error=%v", input.ReqData.OperationID, err)
|
||||
return items, fmt.Errorf("APN单卡结果持久化失败,停止后续办理:%w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
items = append(items, changeApnSingleYD(ctx, c, singleKeys, input.ReqData)...)
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
@@ -123,7 +147,7 @@ func changeApnSingleYD(ctx context.Context, c ydApnRequester, simKeys []*model.S
|
||||
}
|
||||
|
||||
url := c.getUrl(ctx, ydCommunicationServicePath)
|
||||
// {"status":"0","message":"正确","result":[{"iccid":"898602B2221430000005","orderNum":"xxxxxxx"}]}
|
||||
// {"status":"0","message":"正确","result":[{"iccid":"89860000000000000002","orderNum":"xxxxxxx"}]}
|
||||
type ydSingleResp struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
@@ -156,19 +180,23 @@ func changeApnSingleYD(ctx context.Context, c ydApnRequester, simKeys []*model.S
|
||||
resp, err := c.requestYd(ctx, "ChangeSimApnFunction", url, params)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "changeApnSingleYD request error %+v, url %s, params %+v", err, url, params)
|
||||
items = append(items, ydApnErrorItem(simKey, err.Error()))
|
||||
item := ydApnErrorItem(simKey, err.Error())
|
||||
item.ResData.Uncertain = req.SubmitOnly
|
||||
items = append(items, item)
|
||||
continue
|
||||
}
|
||||
body := resp.ReadAllString()
|
||||
var ydResp ydSingleResp
|
||||
if err = json.Unmarshal([]byte(body), &ydResp); err != nil {
|
||||
g.Log().Errorf(ctx, "changeApnSingleYD unmarshal error %+v, url %s, params %+v, body %s", err, url, params, body)
|
||||
items = append(items, ydApnErrorItem(simKey, err.Error()))
|
||||
item := ydApnErrorItem(simKey, err.Error())
|
||||
item.ResData.Uncertain = req.SubmitOnly
|
||||
items = append(items, item)
|
||||
continue
|
||||
}
|
||||
if ydResp.Status != "0" {
|
||||
g.Log().Warningf(ctx, "changeApnSingleYD upstream error %s, url %s, params %+v, body %s", ydResp.Message, url, params, body)
|
||||
items = append(items, ydApnResultItem(simKey, gconv.Int(ydResp.Status), ydResp.Message, ""))
|
||||
items = append(items, ydApnRejectedItem(simKey, ydResp.Status, ydResp.Message))
|
||||
continue
|
||||
}
|
||||
orderNum := ""
|
||||
@@ -219,7 +247,9 @@ func changeApnBatchYD(ctx context.Context, c ydApnRequester, simKeys []*model.Si
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "changeApnBatchYD request error %+v, url %s, params %+v", err, url, params)
|
||||
for _, simKey := range simKeys {
|
||||
items = append(items, ydApnErrorItem(simKey, err.Error()))
|
||||
item := ydApnErrorItem(simKey, err.Error())
|
||||
item.ResData.Uncertain = req.SubmitOnly
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
@@ -228,14 +258,16 @@ func changeApnBatchYD(ctx context.Context, c ydApnRequester, simKeys []*model.Si
|
||||
if err = json.Unmarshal([]byte(body), &ydResp); err != nil {
|
||||
g.Log().Errorf(ctx, "changeApnBatchYD unmarshal error %+v, url %s, params %+v, body %s", err, url, params, body)
|
||||
for _, simKey := range simKeys {
|
||||
items = append(items, ydApnErrorItem(simKey, err.Error()))
|
||||
item := ydApnErrorItem(simKey, err.Error())
|
||||
item.ResData.Uncertain = req.SubmitOnly
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
if ydResp.Status != "0" {
|
||||
g.Log().Warningf(ctx, "changeApnBatchYD upstream error %s, url %s, params %+v, body %s", ydResp.Message, url, params, body)
|
||||
for _, simKey := range simKeys {
|
||||
items = append(items, ydApnResultItem(simKey, gconv.Int(ydResp.Status), ydResp.Message, ""))
|
||||
items = append(items, ydApnRejectedItem(simKey, ydResp.Status, ydResp.Message))
|
||||
}
|
||||
return items
|
||||
}
|
||||
@@ -246,7 +278,18 @@ func changeApnBatchYD(ctx context.Context, c ydApnRequester, simKeys []*model.Si
|
||||
if jobId == "" {
|
||||
g.Log().Warningf(ctx, "changeApnBatchYD accepted without jobId, url %s, params %+v, body %s", url, params, body)
|
||||
for _, simKey := range simKeys {
|
||||
items = append(items, ydApnResultItem(simKey, consts.ApiStatusError, "上游受理成功但未返回 jobId", ""))
|
||||
item := ydApnResultItem(simKey, consts.ApiStatusError, "上游受理成功但未返回 jobId,需核对受理结果", "")
|
||||
item.ResData.Uncertain = true
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
if req.SubmitOnly {
|
||||
for _, simKey := range simKeys {
|
||||
item := ydApnResultItem(simKey, 0, "上游已受理,等待查询最终结果", jobId)
|
||||
item.ResData.Pending = true
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
@@ -263,26 +306,41 @@ func changeApnBatchYD(ctx context.Context, c ydApnRequester, simKeys []*model.Si
|
||||
for _, simKey := range simKeys {
|
||||
card, exist := result.cards[strings.TrimSpace(simKey.MSISDN)]
|
||||
if !exist {
|
||||
items = append(items, ydApnResultItem(simKey, consts.ApiStatusError, "上游批量结果未返回该卡", jobId))
|
||||
item := ydApnResultItem(simKey, consts.ApiStatusError, "上游批量结果未返回该卡", jobId)
|
||||
item.ResData.Uncertain = true
|
||||
items = append(items, item)
|
||||
continue
|
||||
}
|
||||
items = append(items, ydApnResultItem(simKey, card.code, card.message, jobId))
|
||||
item := ydApnResultItem(simKey, card.code, card.message, jobId)
|
||||
item.ResData.Uncertain = card.uncertain
|
||||
items = append(items, item)
|
||||
}
|
||||
default:
|
||||
// 轮询超时或查询失败:该子批下每张卡都按"查询上游通信结果失败"落库,避免误报成功。
|
||||
// 该文案会逐卡写进执行日志明细;日后若增加"重新查询上游结果"的补偿能力,从这一层补做即可。
|
||||
g.Log().Warningf(ctx, "changeApnBatchYD result poll not finished, jobId %s, params %+v", jobId, params)
|
||||
for _, simKey := range simKeys {
|
||||
items = append(items, ydApnResultItem(simKey, consts.ApiStatusError, ydBatchResultQueryFailedMessage, jobId))
|
||||
item := ydApnResultItem(simKey, consts.ApiStatusError, ydBatchResultQueryFailedMessage+":"+result.reason, jobId)
|
||||
item.ResData.Uncertain = true
|
||||
items = append(items, item)
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func (s *sSimYD) QuerySimApnFunctionResult(ctx context.Context, input *model.SimCardOperateChangeApnInput) (model.SimCardOperateChangeApnOutput, error) {
|
||||
return mapYdQueryResult(input.SimKeys, input.ReqData.QueryJobID, queryBatchResultOnceYD(ctx, s, input.ReqData.QueryJobID)), nil
|
||||
}
|
||||
|
||||
func (s *sSimYDMock) QuerySimApnFunctionResult(ctx context.Context, input *model.SimCardOperateChangeApnInput) (model.SimCardOperateChangeApnOutput, error) {
|
||||
return mapYdQueryResult(input.SimKeys, input.ReqData.QueryJobID, queryBatchResultOnceYD(ctx, s, input.ReqData.QueryJobID)), nil
|
||||
}
|
||||
|
||||
// ydBatchCardResult 批量任务中单张卡的最终办理结果。
|
||||
type ydBatchCardResult struct {
|
||||
code int
|
||||
message string
|
||||
code int
|
||||
message string
|
||||
uncertain bool
|
||||
}
|
||||
|
||||
// ydBatchQueryResult 批量办理结果查询的结论。
|
||||
@@ -290,6 +348,7 @@ type ydBatchQueryResult struct {
|
||||
finished bool // 是否已取得终态(jobStatus 2/3/4)
|
||||
failed bool // jobStatus=4,整批处理失败
|
||||
cards map[string]ydBatchCardResult // resultId(msisdn)-> 单卡结果
|
||||
reason string
|
||||
}
|
||||
|
||||
// ydBatchResultItem 5.1.2 sim-batch-result 的逐卡结果项。
|
||||
@@ -313,43 +372,83 @@ type ydBatchResultResp struct {
|
||||
// queryBatchResultYD 轮询 7.2.2 批量任务结果,直到取得终态或超时。
|
||||
// 超时 / 请求失败均返回 finished=false,由调用方按"未确认"处理。
|
||||
func queryBatchResultYD(ctx context.Context, c ydApnRequester, jobId string) ydBatchQueryResult {
|
||||
url := c.getUrl(ctx, ydCommunicationBatchResultPath)
|
||||
deadline := time.Now().Add(ydBatchResultPollTimeout)
|
||||
pollCtx, cancel := context.WithTimeout(ctx, ydBatchResultPollTimeout)
|
||||
defer cancel()
|
||||
var last ydBatchQueryResult
|
||||
for {
|
||||
params := g.Map{
|
||||
"transid": c.getTransId(ctx),
|
||||
"jobId": jobId,
|
||||
if err := pollCtx.Err(); err != nil {
|
||||
last.reason = "查询上游通信结果截止:" + err.Error() + ";" + last.reason
|
||||
return last
|
||||
}
|
||||
resp, err := c.requestYd(ctx, "QuerySimBatchResult", url, params)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "queryBatchResultYD request error %+v, jobId %s", err, jobId)
|
||||
} else {
|
||||
body := resp.ReadAllString()
|
||||
var parsed ydBatchResultResp
|
||||
if jsonErr := json.Unmarshal([]byte(body), &parsed); jsonErr != nil {
|
||||
g.Log().Warningf(ctx, "queryBatchResultYD unmarshal error %+v, jobId %s, body %s", jsonErr, jobId, body)
|
||||
} else if parsed.Status != "0" {
|
||||
g.Log().Warningf(ctx, "queryBatchResultYD upstream error %s, jobId %s, body %s", parsed.Message, jobId, body)
|
||||
} else if len(parsed.Result) > 0 {
|
||||
switch parsed.Result[0].JobStatus {
|
||||
case ydJobStatusDone, ydJobStatusDonePartial:
|
||||
return ydBatchQueryResult{finished: true, cards: toYdBatchCardMap(parsed.Result[0].ResultList)}
|
||||
case ydJobStatusFailed:
|
||||
return ydBatchQueryResult{finished: true, failed: true}
|
||||
}
|
||||
}
|
||||
}
|
||||
if time.Now().After(deadline) {
|
||||
return ydBatchQueryResult{}
|
||||
last = queryBatchResultOnceYD(pollCtx, c, jobId)
|
||||
if last.finished {
|
||||
return last
|
||||
}
|
||||
timer := time.NewTimer(ydBatchResultPollInterval)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ydBatchQueryResult{}
|
||||
case <-time.After(ydBatchResultPollInterval):
|
||||
case <-pollCtx.Done():
|
||||
timer.Stop()
|
||||
last.reason = "查询上游通信结果截止:" + pollCtx.Err().Error() + ";" + last.reason
|
||||
return last
|
||||
case <-timer.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// queryBatchResultOnceYD 只查询一次;持久化调度器负责后续补查。
|
||||
func queryBatchResultOnceYD(ctx context.Context, c ydApnRequester, jobID string) ydBatchQueryResult {
|
||||
params := g.Map{"transid": c.getTransId(ctx), "jobId": jobID}
|
||||
resp, err := c.requestYd(ctx, "QuerySimBatchResult", c.getUrl(ctx, ydCommunicationBatchResultPath), params)
|
||||
if err != nil {
|
||||
return ydBatchQueryResult{reason: "查询上游通信结果失败:" + err.Error()}
|
||||
}
|
||||
body := resp.ReadAllString()
|
||||
var parsed ydBatchResultResp
|
||||
if err := json.Unmarshal([]byte(body), &parsed); err != nil {
|
||||
return ydBatchQueryResult{reason: "查询上游通信结果解析失败:" + err.Error()}
|
||||
}
|
||||
if parsed.Status != "0" {
|
||||
return ydBatchQueryResult{reason: "查询上游通信结果失败,status=" + parsed.Status + ",message=" + parsed.Message}
|
||||
}
|
||||
if len(parsed.Result) == 0 {
|
||||
return ydBatchQueryResult{reason: "上游查询未返回任务结果"}
|
||||
}
|
||||
switch parsed.Result[0].JobStatus {
|
||||
case ydJobStatusDone, ydJobStatusDonePartial:
|
||||
return ydBatchQueryResult{finished: true, cards: toYdBatchCardMap(parsed.Result[0].ResultList)}
|
||||
case ydJobStatusFailed:
|
||||
return ydBatchQueryResult{finished: true, failed: true, reason: parsed.Message}
|
||||
default:
|
||||
return ydBatchQueryResult{reason: "上游任务尚未完成,jobStatus=" + parsed.Result[0].JobStatus}
|
||||
}
|
||||
}
|
||||
|
||||
func mapYdQueryResult(keys []*model.SimKey, jobID string, result ydBatchQueryResult) model.SimCardOperateChangeApnOutput {
|
||||
items := make(model.SimCardOperateChangeApnOutput, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
if key == nil {
|
||||
continue
|
||||
}
|
||||
item := ydApnResultItem(key, consts.ApiStatusError, result.reason, jobID)
|
||||
switch {
|
||||
case !result.finished:
|
||||
item.ResData.Pending = true
|
||||
case result.failed:
|
||||
item.Message = "上游批量任务处理失败:" + result.reason
|
||||
default:
|
||||
if card, ok := result.cards[strings.TrimSpace(key.MSISDN)]; ok {
|
||||
item.Code, item.Message = card.code, card.message
|
||||
item.ResData.Uncertain = card.uncertain
|
||||
} else {
|
||||
item.Message = "上游批量结果未返回该卡,需继续核对"
|
||||
item.ResData.Uncertain = true
|
||||
}
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// toYdBatchCardMap 把逐卡结果按 resultId(msisdn)建索引。
|
||||
func toYdBatchCardMap(list []ydBatchResultItem) map[string]ydBatchCardResult {
|
||||
cards := make(map[string]ydBatchCardResult, len(list))
|
||||
@@ -358,11 +457,26 @@ func toYdBatchCardMap(list []ydBatchResultItem) map[string]ydBatchCardResult {
|
||||
if id == "" {
|
||||
continue
|
||||
}
|
||||
cards[id] = ydBatchCardResult{code: gconv.Int(item.Status), message: item.Message}
|
||||
code, err := strconv.Atoi(strings.TrimSpace(item.Status))
|
||||
if err != nil {
|
||||
cards[id] = ydBatchCardResult{code: consts.ApiStatusError, message: "上游逐卡结果状态无效,status=" + item.Status + ",message=" + item.Message, uncertain: true}
|
||||
continue
|
||||
}
|
||||
cards[id] = ydBatchCardResult{code: code, message: item.Message}
|
||||
}
|
||||
return cards
|
||||
}
|
||||
|
||||
func ydApnRejectedItem(key *model.SimKey, status, message string) *model.SimBaseRes[model.SimCardOperateChangeApnItem] {
|
||||
code, err := strconv.Atoi(strings.TrimSpace(status))
|
||||
if err != nil || code == 0 {
|
||||
item := ydApnErrorItem(key, "上游受理状态无效,status="+status+",message="+message)
|
||||
item.ResData.Uncertain = true
|
||||
return item
|
||||
}
|
||||
return ydApnResultItem(key, code, message, "")
|
||||
}
|
||||
|
||||
func ydApnErrorItem(simKey *model.SimKey, message string) *model.SimBaseRes[model.SimCardOperateChangeApnItem] {
|
||||
return &model.SimBaseRes[model.SimCardOperateChangeApnItem]{
|
||||
SimKey: simKey,
|
||||
|
||||
Reference in New Issue
Block a user