chore: 初始开源发布
iotlcm-openapi:对外 OpenAPI 网关(V3 接口 + 旧版兼容接口)。
- Go module:iotlcm-openapi → git.5iot.com/iotlcm-public/iotlcm-openapi(178 文件)
- 凭据与地址脱敏:JWT signingKey、MySQL DSN、Redis 口令、
RabbitMQ DSN 全部改为 ${*} 占位;私网 IP → 文档地址段
- 7 处真实手机号 → 合法 11 位编造号
- 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名
- 移除内部资产:CI 触发器
- Dockerfile 改用公共基础镜像,移除 GOPRIVATE 内网设置
- README 重写(原为 GoFrame 模板占位文案),补 Apache-2.0 LICENSE,
LF 行尾 + .gitattributes
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/consts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/library/batchmetadata"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/model/entity"
|
||||
)
|
||||
|
||||
const (
|
||||
trafficCutoffConfigMaxCards = 1000
|
||||
trafficCutoffRequestIDMaxLen = 64
|
||||
)
|
||||
|
||||
func (s *sCommon) SubmitTrafficCutoffConfig(ctx context.Context, in *model.CommonTrafficCutoffConfigParam) (*model.CommonTrafficCutoffConfigRes, error) {
|
||||
return s.submitTrafficCutoffConfig(ctx, in, false, batchmetadata.Bulk)
|
||||
}
|
||||
|
||||
func (s *sCommon) submitTrafficCutoffConfig(ctx context.Context, in *model.CommonTrafficCutoffConfigParam, waitForCompletion bool, executionMode int) (*model.CommonTrafficCutoffConfigRes, error) {
|
||||
if in == nil {
|
||||
return nil, gerror.New("达量断网配置参数不能为空")
|
||||
}
|
||||
if strings.TrimSpace(in.AppId) == "" {
|
||||
return nil, gerror.New("appId不能为空")
|
||||
}
|
||||
idempotencyKey := strings.TrimSpace(in.IdempotencyKey)
|
||||
if len(idempotencyKey) > trafficCutoffRequestIDMaxLen {
|
||||
return nil, gerror.Newf("Idempotency-Key长度不能超过%d", trafficCutoffRequestIDMaxLen)
|
||||
}
|
||||
if in.TrafficCutoffStatus == 0 {
|
||||
in.TrafficCutoffThreshold = 0
|
||||
}
|
||||
if err := validateTrafficCutoffConfig(in.TrafficCutoffStatus, in.TrafficCutoffThreshold); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(in.Cards) == 0 {
|
||||
return nil, gerror.New("配置卡不能为空")
|
||||
}
|
||||
if len(in.Cards) > trafficCutoffConfigMaxCards {
|
||||
return nil, gerror.Newf("单次最多配置%d张卡", trafficCutoffConfigMaxCards)
|
||||
}
|
||||
|
||||
identifiers := make([]cardIdentifier, 0, len(in.Cards))
|
||||
seen := make(map[string]struct{}, len(in.Cards))
|
||||
for _, card := range in.Cards {
|
||||
identifier := cardIdentifier{
|
||||
Msisdn: strings.TrimSpace(card.Msisdn),
|
||||
Iccid: strings.TrimSpace(card.Iccid),
|
||||
Imsi: strings.TrimSpace(card.Imsi),
|
||||
}
|
||||
if err := validateCardIdentifier(identifier); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := cardIdentifierKey(identifier)
|
||||
if _, ok := seen[key]; ok {
|
||||
return nil, gerror.Newf("卡片标识重复:%s", key)
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
identifiers = append(identifiers, identifier)
|
||||
}
|
||||
|
||||
tenantID := strings.TrimSpace(contexts.GetTenantId(ctx))
|
||||
deptID := contexts.GetAgentDeptId(ctx)
|
||||
if tenantID == "" || deptID <= 0 {
|
||||
return nil, gerror.New("当前接口调用方信息不完整")
|
||||
}
|
||||
operatorID := contexts.GetUserId(ctx)
|
||||
if operatorID <= 0 {
|
||||
operatorID = deptID
|
||||
}
|
||||
|
||||
if idempotencyKey != "" {
|
||||
if existing, err := s.findTrafficCutoffBatch(ctx, tenantID, deptID, idempotencyKey); err != nil {
|
||||
return nil, err
|
||||
} else if existing != nil {
|
||||
return &model.CommonTrafficCutoffConfigRes{BatchNo: existing.BatchNo, BatchType: consts.BatchTypeTrafficCutoffConfig}, nil
|
||||
}
|
||||
}
|
||||
|
||||
deptIDs, err := s.loadRenewAccessibleDeptIds(ctx, tenantID, deptID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cardMap, err := s.loadCardsByIdentifiers(ctx, tenantID, deptIDs, identifiers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iccids := make([]string, 0, len(identifiers))
|
||||
for _, identifier := range identifiers {
|
||||
card := cardMap[cardIdentifierKey(identifier)]
|
||||
if !cardMatchesIdentifier(card, identifier) {
|
||||
return nil, gerror.New("卡片不存在或无权限")
|
||||
}
|
||||
iccids = append(iccids, strings.TrimSpace(card.Iccid))
|
||||
}
|
||||
|
||||
batchNo, err := s.BuildBatchNo(ctx, consts.BatchNoPrefixTrafficCutoffConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
now := gtime.Now()
|
||||
batchInfo := gjson.New(map[string]any{
|
||||
"operation": "traffic_cutoff_config",
|
||||
"configName": "达量断网配置",
|
||||
"submitScene": "openapi",
|
||||
"trafficCutoffStatus": in.TrafficCutoffStatus,
|
||||
"trafficCutoffThreshold": in.TrafficCutoffThreshold,
|
||||
"trafficCutoffThresholdUnit": "MB",
|
||||
"remark": strings.TrimSpace(in.Remark),
|
||||
"quantity": len(iccids),
|
||||
})
|
||||
if idempotencyKey != "" {
|
||||
batchInfo.Set("idempotencyKey", idempotencyKey)
|
||||
}
|
||||
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
main := &entity.BatchMain{
|
||||
BatchNo: batchNo,
|
||||
BatchType: consts.BatchTypeTrafficCutoffConfig,
|
||||
BatchStatus: consts.BatchStatusNormal,
|
||||
BatchAsyncStatus: consts.BatchAsyncStatusPending,
|
||||
SourceType: consts.BatchSourceTypeBatchInput,
|
||||
DeptId: deptID,
|
||||
TotalCount: len(iccids),
|
||||
ValidCount: len(iccids),
|
||||
RunResult: consts.BatchRunResultPending,
|
||||
BatchInfo: batchInfo,
|
||||
Remark: gjson.New(map[string]any{"remark": strings.TrimSpace(in.Remark)}),
|
||||
TenantId: tenantID,
|
||||
CreatedDept: deptID,
|
||||
CreatedBy: operatorID,
|
||||
CreatedAt: now,
|
||||
UpdatedBy: operatorID,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
if err := s.SaveBatchMain(ctx, tx, main, executionMode); err != nil {
|
||||
return err
|
||||
}
|
||||
details := make([]*entity.BatchDetail, 0, len(iccids))
|
||||
for index, iccid := range iccids {
|
||||
card := cardMap[cardIdentifierKey(identifiers[index])]
|
||||
snapshot := gjson.New(map[string]any{
|
||||
"iccid": card.Iccid,
|
||||
"msisdn": card.Msisdn,
|
||||
"imsi": card.Imsi,
|
||||
"authorized": true,
|
||||
"trafficCutoffStatus": in.TrafficCutoffStatus,
|
||||
"trafficCutoffThreshold": in.TrafficCutoffThreshold,
|
||||
"trafficCutoffThresholdUnit": "MB",
|
||||
})
|
||||
details = append(details, &entity.BatchDetail{
|
||||
BatchNo: batchNo,
|
||||
BatchType: consts.BatchTypeTrafficCutoffConfig,
|
||||
DetailStatus: consts.BatchDetailStatusPending,
|
||||
BlankOutStatus: consts.BlankOutStatusNo,
|
||||
RowNo: index + 1,
|
||||
ItemId: iccid,
|
||||
Snapshot: snapshot,
|
||||
TenantId: tenantID,
|
||||
CreatedDept: deptID,
|
||||
CreatedBy: operatorID,
|
||||
CreatedAt: now,
|
||||
UpdatedBy: operatorID,
|
||||
UpdatedAt: now,
|
||||
})
|
||||
}
|
||||
return s.SaveBatchDetails(ctx, tx, details)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
message := model.CommonBatchExecuteMessage{BatchNo: batchNo, BatchType: consts.BatchTypeTrafficCutoffConfig}
|
||||
if err := s.Publish(ctx, consts.QueueBatchExecute, message); err != nil {
|
||||
return nil, gerror.Wrap(err, "投递达量断网配置异步消息失败")
|
||||
}
|
||||
if waitForCompletion {
|
||||
if _, err := s.waitBatchCompletion(ctx, tenantID, deptID, batchNo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &model.CommonTrafficCutoffConfigRes{BatchNo: batchNo, BatchType: consts.BatchTypeTrafficCutoffConfig}, nil
|
||||
}
|
||||
|
||||
func (s *sCommon) SubmitSingleTrafficCutoffConfig(ctx context.Context, in *model.CommonTrafficCutoffSingleParam) (*model.CommonSingleTrafficCutoffRes, error) {
|
||||
if in == nil {
|
||||
return nil, gerror.New("traffic cutoff configuration parameters are required")
|
||||
}
|
||||
batch, err := s.submitTrafficCutoffConfig(ctx, &model.CommonTrafficCutoffConfigParam{
|
||||
AppId: in.AppId,
|
||||
Cards: []model.CommonTrafficCutoffCard{{Msisdn: in.Msisdn, Iccid: in.Iccid, Imsi: in.Imsi}},
|
||||
TrafficCutoffStatus: in.TrafficCutoffStatus,
|
||||
TrafficCutoffThreshold: in.TrafficCutoffThreshold,
|
||||
Remark: in.Remark,
|
||||
}, true, batchmetadata.Single)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.loadSingleTrafficCutoffResult(ctx, batch.BatchNo)
|
||||
}
|
||||
Reference in New Issue
Block a user