Files

213 lines
7.2 KiB
Go

package simwarning
import (
"context"
"fmt"
"strconv"
"strings"
"time"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/do"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
)
const (
warnActionDataCut = "data_cut"
warnDataServiceStatusEnabled = 1
warnDataServiceStatusDisabled = 0
)
func (s *sSimWarning) handleAutoAction(ctx context.Context, hit warningHit, warnLogID int64, runTime time.Time) (bool, error) {
if !autoDataCutEnabled(hit) {
return false, nil
}
allowed, reason := autoDataCutEligibility(hit)
if !allowed {
g.Log().Infof(ctx, "SimWarning auto data cut skipped, reason:%s, configId:%d, cardId:%d, warnLogId:%d", reason, hit.Config.Id, hit.Card.Id, warnLogID)
return false, nil
}
acquired, actionKey, err := acquireWarningActionDedupe(ctx, hit, warnActionDataCut, runTime)
if err != nil {
return false, err
}
if !acquired {
g.Log().Infof(ctx, "SimWarning auto data cut duplicated, action:%s, configId:%d, cardId:%d, warnLogId:%d", warnActionDataCut, hit.Config.Id, hit.Card.Id, warnLogID)
return false, nil
}
eligible, reason, err := s.ensureDataCutEligible(ctx, hit)
if err != nil {
releaseWarningDedupe(ctx, actionKey)
return false, err
}
if !eligible {
releaseWarningDedupe(ctx, actionKey)
g.Log().Infof(ctx, "SimWarning auto data cut skipped, reason:%s, configId:%d, cardId:%d, warnLogId:%d", reason, hit.Config.Id, hit.Card.Id, warnLogID)
return false, nil
}
orderNum, err := s.disableCardDataService(ctx, hit)
if err != nil {
releaseWarningDedupe(ctx, actionKey)
return false, err
}
g.Log().Infof(ctx, "SimWarning auto data cut success, action:%s, configId:%d, cardId:%d, warnLogId:%d, orderNum:%s", warnActionDataCut, hit.Config.Id, hit.Card.Id, warnLogID, orderNum)
return true, nil
}
func autoDataCutEnabled(hit warningHit) bool {
return hit.Config.ItemType == warnItemTypeCard &&
(isExpireKind(hit.Kind) || isTrafficKind(hit.Kind)) &&
hit.WarnStage == warnStageThird &&
hit.Config.AutoAction == warnAutoActionDataCut
}
func autoDataCutEligibility(hit warningHit) (bool, string) {
if hit.Card.BossCardStatus == consts.V3ApiSimBossCardStatusStopped {
return false, "\u5361\u5df2\u505c\u673a\uff0c\u81ea\u52a8\u65ad\u7f51\u672a\u6267\u884c"
}
if hit.Card.BossCardStatus != consts.V3ApiSimBossCardStatusActivated {
return false, "\u5f53\u524d\u8fd0\u8425\u5546\u72b6\u6001\u4e3a" + bossCardStatusText(hit.Card.BossCardStatus) + "\uff0c\u4ec5\u5df2\u6fc0\u6d3b\u5361\u53ef\u4ee5\u81ea\u52a8\u65ad\u7f51"
}
if hit.Card.DataServiceStatus == warnDataServiceStatusDisabled {
return false, "\u6570\u636e\u670d\u52a1\u5df2\u505c\u7528\uff0c\u81ea\u52a8\u65ad\u7f51\u672a\u6267\u884c"
}
if hit.Card.DataServiceStatus != warnDataServiceStatusEnabled {
return false, "\u6570\u636e\u670d\u52a1\u72b6\u6001\u65e0\u6548\uff0c\u81ea\u52a8\u65ad\u7f51\u672a\u6267\u884c"
}
if strings.TrimSpace(hit.Card.ChanKey) == "" {
return false, "\u5361\u7f3a\u5c11\u901a\u9053\u6807\u8bc6\uff0c\u81ea\u52a8\u65ad\u7f51\u672a\u6267\u884c"
}
if strings.TrimSpace(hit.Card.Iccid) == "" &&
strings.TrimSpace(hit.Card.Msisdn) == "" &&
strings.TrimSpace(hit.Card.Imsi) == "" {
return false, "\u5361\u7f3a\u5c11 ICCID/MSISDN/IMSI\uff0c\u81ea\u52a8\u65ad\u7f51\u672a\u6267\u884c"
}
return true, "\u5df2\u914d\u7f6e\u7b2c\u4e09\u6863\u65ad\u7f51\uff0c\u7cfb\u7edf\u5c06\u5728\u72b6\u6001\u6821\u9a8c\u901a\u8fc7\u540e\u53d1\u8d77\u6570\u636e\u670d\u52a1\u505c\u7528"
}
func (s *sSimWarning) ensureDataCutEligible(ctx context.Context, hit warningHit) (bool, string, error) {
simKey, err := dataCutSimKey(hit)
if err != nil {
return false, "", err
}
output, err := service.UpstreamChan().QuerySimCardStatus(ctx, &model.SimCardStatusInput{
SimKeys: []*model.SimKey{simKey},
})
if err != nil {
return false, "", err
}
if len(output) == 0 {
return false, "", gerror.New("upstream card status is empty")
}
status := output[0].ResData.CardStatus
if status == consts.V3ApiSimBossCardStatusStopped {
return false, "\u4e0a\u6e38\u5361\u5df2\u505c\u673a\uff0c\u81ea\u52a8\u65ad\u7f51\u672a\u6267\u884c", nil
}
if status != consts.V3ApiSimBossCardStatusActivated {
return false, fmt.Sprintf("\u4e0a\u6e38\u5f53\u524d\u72b6\u6001\u4e3a%s\uff0c\u4ec5\u5df2\u6fc0\u6d3b\u5361\u53ef\u4ee5\u81ea\u52a8\u65ad\u7f51", bossCardStatusText(status)), nil
}
return true, "\u4e0a\u6e38\u72b6\u6001\u5df2\u786e\u8ba4\uff0c\u53ef\u6267\u884c\u6570\u636e\u670d\u52a1\u505c\u7528", nil
}
func bossCardStatusText(status int) string {
if name := consts.V3ApiSimBossCardStatusNameMap[status]; name != "" {
return name
}
return "\u672a\u77e5\u72b6\u6001"
}
func (s *sSimWarning) disableCardDataService(ctx context.Context, hit warningHit) (string, error) {
simKey, err := dataCutSimKey(hit)
if err != nil {
return "", err
}
output, err := service.UpstreamChan().ChangeSimApnFunction(ctx, &model.SimCardOperateChangeApnInput{
SimKeys: []*model.SimKey{simKey},
ReqData: model.SimCardOperateChangeApnInputItem{
OperType: strconv.Itoa(consts.SimCardDataOperTypeStop),
ApnName: consts.SimCardDataApnName,
},
})
if err != nil {
return "", err
}
if len(output) == 0 {
return "", gerror.New("upstream data service stop response is empty")
}
item := output[0]
if item.Code != 0 {
message := strings.TrimSpace(item.Message)
if message == "" {
message = "upstream data service stop failed"
}
return "", gerror.New(message)
}
if err = s.updateLocalDataServiceDisabled(ctx, hit); err != nil {
return item.ResData.OrderNum, err
}
return item.ResData.OrderNum, nil
}
func dataCutSimKey(hit warningHit) (*model.SimKey, error) {
chanKey := strings.TrimSpace(hit.Card.ChanKey)
if chanKey == "" {
return nil, gerror.New("card chan key is empty")
}
if strings.TrimSpace(hit.Card.Iccid) == "" &&
strings.TrimSpace(hit.Card.Msisdn) == "" &&
strings.TrimSpace(hit.Card.Imsi) == "" {
return nil, gerror.New("card identity is empty")
}
return &model.SimKey{
ChanKey: chanKey,
ICCID: strings.TrimSpace(hit.Card.Iccid),
MSISDN: strings.TrimSpace(hit.Card.Msisdn),
IMSI: strings.TrimSpace(hit.Card.Imsi),
}, nil
}
func (s *sSimWarning) updateLocalDataServiceDisabled(ctx context.Context, hit warningHit) error {
columns := dao.TSimCardInfo.Columns()
result, err := dao.TSimCardInfo.Ctx(ctx).
Where(columns.Id, hit.Card.Id).
Where(columns.TenantId, hit.Config.TenantId).
Where(columns.DataServiceStatus, warnDataServiceStatusEnabled).
Data(do.TSimCardInfo{
DataServiceStatus: warnDataServiceStatusDisabled,
UpdatedBy: hit.Config.CreatedBy,
}).
Update()
if err != nil {
return err
}
affected, err := result.RowsAffected()
if err != nil {
return err
}
if affected == 1 {
return nil
}
count, err := dao.TSimCardInfo.Ctx(ctx).
Where(columns.Id, hit.Card.Id).
Where(columns.TenantId, hit.Config.TenantId).
Where(columns.DataServiceStatus, warnDataServiceStatusDisabled).
Count()
if err != nil {
return err
}
if count > 0 {
return nil
}
return gerror.New("local data service status changed before update")
}