sync: 同步生产版 v1.0.4 并脱敏
This commit is contained in:
@@ -11,3 +11,4 @@
|
||||
*.ttf binary
|
||||
*.pdf binary
|
||||
*.exe binary
|
||||
*.go linguist-language=Go
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# iotlcm-upstream-proxy
|
||||
|
||||
配置示例见 `build/config.example.yaml` 与 `config/config.example.yaml`。请使用获授权的测试卡。
|
||||
|
||||
## 本地测试
|
||||
```
|
||||
curl -d '{"simKeys":[
|
||||
{"chanKey":"12234",
|
||||
"iccid":"23434",
|
||||
"imsi":"222",
|
||||
"msisdn":"2222"}
|
||||
], "reqData":{"a":234}}' 127.0.0.1:8510/sim/adfds
|
||||
|
||||
|
||||
curl -d '{"simKeys":[
|
||||
{"chanKey":"",
|
||||
"iccid":"89860000000000000001",
|
||||
"imsi":"",
|
||||
"msisdn":""}
|
||||
], "reqData":{"yearMonth":"202602"}}' 127.0.0.1:8510/sim/query/sim-datausage-monthly
|
||||
```
|
||||
+14
-9
@@ -1,33 +1,38 @@
|
||||
FROM golang:1.25-alpine AS builder
|
||||
|
||||
ARG BASE_REGISTRY=docker.io/library
|
||||
FROM ${BASE_REGISTRY}/golang:1.25-alpine AS builder
|
||||
LABEL stage=gobuilder
|
||||
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
|
||||
# RUN apk update --no-cache && apk add --no-cache tzdata
|
||||
# 安装GCC和相关依赖
|
||||
# RUN apk add --no-cache gcc g++ make autoconf automake binutils-dev gmp-dev isl-dev patchelf
|
||||
# RUN apk update --no-cache && apk add --no-cache tzdata git expect
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
COPY go.mod go.sum ./
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
COPY . .
|
||||
|
||||
ARG BuildVersion
|
||||
ARG BuildTime
|
||||
ARG CommitID
|
||||
|
||||
RUN go build -o iotlcmupstreamproxy_svc -ldflags "-w -s -X main.BuildVersion=${BuildVersion} -X main.CommitID=${CommitID} -X main.BuildTime=${BuildTime}"
|
||||
RUN go build -o iotlcmupstreamproxy_svc -ldflags "-w -s -X main.BuildVersion=${BuildVersion} -X main.CommitID=${CommitID} -X main.BuildTime=${BuildTime}"
|
||||
|
||||
FROM alpine:3.23
|
||||
FROM ${BASE_REGISTRY}/alpine:3.23 AS alpine
|
||||
|
||||
RUN apk add --no-cache ca-certificates tzdata
|
||||
|
||||
# RUN apk update --no-cache && apk add --no-cache ca-certificates
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
EXPOSE 18510
|
||||
EXPOSE 11140
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /build/iotlcmupstreamproxy_svc /app/iotlcmupstreamproxy_svc
|
||||
COPY --from=builder /build/build/dev_config.yaml /app/config/config.yaml
|
||||
COPY --from=builder /build/build/config.example.yaml /app/config/config.yaml
|
||||
|
||||
CMD ["./iotlcmupstreamproxy_svc"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# config.yaml 配置文件
|
||||
# @Origin 源自内部工程基座
|
||||
|
||||
# @Origin 源自内网工程库,公开版已移除内部标识
|
||||
|
||||
# @Link https://github.com/xiujiecn/xiu-admin
|
||||
# @Copyright Copyright (c) 2025 LiXiujie
|
||||
# @Author Lxj <xxx@example.com>
|
||||
# @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
# 系统配置
|
||||
system:
|
||||
name: "XiuAdmin"
|
||||
@@ -33,7 +33,7 @@ server:
|
||||
|
||||
registry:
|
||||
type: "consul"
|
||||
address: "${REDIS_ADDR}"
|
||||
address: "127.0.0.1:8500"
|
||||
|
||||
# 日志配置
|
||||
logger:
|
||||
@@ -61,7 +61,7 @@ database:
|
||||
level: "all"
|
||||
stdout: true
|
||||
default: # 分组名称,可自定义,默认为default
|
||||
link: "mysql:${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:3306)/db_yz_iot?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai"
|
||||
link: "${DB_DSN}"
|
||||
debug: true #开启调试模式
|
||||
charset: "utf8mb4" # (可选)数据库编码(如: utf8mb4/utf8/gbk/gb2312),一般设置为utf8mb4。默认为utf8。
|
||||
dryRun: false #ORM空跑(只读不写)
|
||||
@@ -70,7 +70,7 @@ database:
|
||||
maxLifetime: 120 #(单位秒)连接对象可重复使用的时间长度
|
||||
memorydb:
|
||||
# link: "sqlite::@file(jieiotmem.db)?journal_mode=WAL"
|
||||
link: "sqlite::@file(:memory:)"
|
||||
link: "${DB_DSN}"
|
||||
# link: ""
|
||||
debug: true
|
||||
maxIdle: 1
|
||||
@@ -87,10 +87,10 @@ redis:
|
||||
# 单实例配置
|
||||
default:
|
||||
mode: "single" #redis模式,支持:single|cluster|sentinel
|
||||
sentinelMasterName: "${REDIS_SENTINEL_MASTER}" #哨兵模式主节点名称
|
||||
address: "${REDIS_ADDR}"
|
||||
sentinelMasterName: "example-master" #哨兵模式主节点名称
|
||||
address: 127.0.0.1:6382
|
||||
db: 0
|
||||
pass: "${REDIS_PASSWORD}"
|
||||
pass: "${SERVICE_PASSWORD}"
|
||||
minIdle: 5 #最小空闲连接数
|
||||
maxIdle: 30 #允许闲置的最大连接数
|
||||
maxActive: 5000 #最大活跃连接数
|
||||
@@ -98,10 +98,10 @@ redis:
|
||||
ClientName: "SystemCache"
|
||||
queue:
|
||||
mode: "single" #redis模式,支持:single|cluster|sentinel
|
||||
sentinelMasterName: "${REDIS_SENTINEL_MASTER}" #哨兵模式主节点名称
|
||||
address: "${REDIS_ADDR}"
|
||||
sentinelMasterName: "example-master" #哨兵模式主节点名称
|
||||
address: 127.0.0.1:6382
|
||||
db: 0
|
||||
pass: "${REDIS_PASSWORD}"
|
||||
pass: "${SERVICE_PASSWORD}"
|
||||
minIdle: 5 #最小空闲连接数
|
||||
maxIdle: 30 #允许闲置的最大连接数
|
||||
maxActive: 5000 #最大活跃连接数
|
||||
@@ -1,8 +1,8 @@
|
||||
# config.yaml 配置文件
|
||||
# @Origin 源自内部工程基座
|
||||
|
||||
# @Origin 源自内网工程库,公开版已移除内部标识
|
||||
|
||||
# @Link https://github.com/xiujiecn/xiu-admin
|
||||
# @Copyright Copyright (c) 2025 LiXiujie
|
||||
# @Author Lxj <xxx@example.com>
|
||||
# @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
# 系统配置
|
||||
system:
|
||||
name: "XiuAdmin"
|
||||
@@ -33,8 +33,8 @@ server:
|
||||
|
||||
registry:
|
||||
type: "consul"
|
||||
address: "${REDIS_ADDR}"
|
||||
# address: "${REDIS_ADDR}"
|
||||
address: "127.0.0.1:8500"
|
||||
# address: "127.0.0.1:8500"
|
||||
|
||||
# 日志配置
|
||||
logger:
|
||||
@@ -62,7 +62,7 @@ database:
|
||||
level: "all"
|
||||
stdout: true
|
||||
default: # 分组名称,可自定义,默认为default
|
||||
link: "mysql:${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:3306)/db_iotlcm?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai"
|
||||
link: "${DB_DSN}"
|
||||
debug: true #开启调试模式
|
||||
charset: "utf8mb4" # (可选)数据库编码(如: utf8mb4/utf8/gbk/gb2312),一般设置为utf8mb4。默认为utf8。
|
||||
dryRun: false #ORM空跑(只读不写)
|
||||
@@ -71,7 +71,7 @@ database:
|
||||
maxLifetime: 120 #(单位秒)连接对象可重复使用的时间长度
|
||||
memorydb:
|
||||
# link: "sqlite::@file(jieiotmem.db)?journal_mode=WAL"
|
||||
link: "sqlite::@file(:memory:)"
|
||||
link: "${DB_DSN}"
|
||||
# link: ""
|
||||
debug: true
|
||||
maxIdle: 1
|
||||
@@ -88,10 +88,10 @@ redis:
|
||||
# 单实例配置
|
||||
default:
|
||||
mode: "single" #redis模式,支持:single|cluster|sentinel
|
||||
sentinelMasterName: "${REDIS_SENTINEL_MASTER}" #哨兵模式主节点名称
|
||||
address: "${REDIS_ADDR}"
|
||||
sentinelMasterName: "example-master" #哨兵模式主节点名称
|
||||
address: 127.0.0.1:6379
|
||||
db: 0
|
||||
pass: "${REDIS_PASSWORD}"
|
||||
pass: "${SERVICE_PASSWORD}"
|
||||
minIdle: 5 #最小空闲连接数
|
||||
maxIdle: 30 #允许闲置的最大连接数
|
||||
maxActive: 5000 #最大活跃连接数
|
||||
@@ -6,12 +6,10 @@ require (
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.10.0
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0
|
||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.10.3
|
||||
github.com/gogf/gf/contrib/rpc/grpcx/v2 v2.10.0
|
||||
github.com/gogf/gf/v2 v2.10.3
|
||||
golang.org/x/sync v0.20.0
|
||||
google.golang.org/grpc v1.79.3
|
||||
google.golang.org/protobuf v1.36.11
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -29,6 +27,7 @@ require (
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.10.3
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.10.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
@@ -53,6 +52,7 @@ require (
|
||||
github.com/redis/go-redis/v9 v9.18.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||
@@ -64,6 +64,7 @@ require (
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
@@ -19,6 +21,7 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
@@ -26,6 +29,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -36,6 +41,9 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
@@ -71,17 +79,30 @@ github.com/gogf/gf/contrib/registry/file/v2 v2.10.0 h1:yy93PGhz2CE3PpF2JSGa2MXJW
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.10.0/go.mod h1:ZzGWiTbQ9nAmDynrmzaRJlqYHD/F3MeMwCvHrkv/LP4=
|
||||
github.com/gogf/gf/contrib/rpc/grpcx/v2 v2.10.0 h1:MWHgX/h/62+Oo1Jbeq8DrXbEWSOZxskpBBm3cFAV4/Q=
|
||||
github.com/gogf/gf/contrib/rpc/grpcx/v2 v2.10.0/go.mod h1:zGZdjS08IqiSGhKfy69/qgcYKUYUL/VsOx5fuT++TVE=
|
||||
github.com/gogf/gf/v2 v2.10.0 h1:rzDROlyqGMe/eM6dCalSR8dZOuMIdLhmxKSH1DGhbFs=
|
||||
github.com/gogf/gf/v2 v2.10.0/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
||||
github.com/gogf/gf/v2 v2.10.3 h1:tZvEk+58x9uyuOAMgT5VV8yAPHGPBwJkPYRuXj2cfBI=
|
||||
github.com/gogf/gf/v2 v2.10.3/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
@@ -208,6 +229,7 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
|
||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
@@ -239,6 +261,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
|
||||
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
|
||||
@@ -261,17 +285,30 @@ go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -280,10 +317,12 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -291,6 +330,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -310,15 +350,33 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
@@ -332,6 +390,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
|
||||
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
gfcli:
|
||||
gen:
|
||||
dao:
|
||||
link: "mysql:${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:3306)/db_iotlcm?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai"
|
||||
link: "${DB_DSN}"
|
||||
tables: "t_sim_card_info, t_sim_channel_templatem, t_sim_channels"
|
||||
descriptionTag: true # 数据表字段注释
|
||||
noModelComment: true
|
||||
+2
-7
@@ -5,7 +5,7 @@
|
||||
up: cli.install
|
||||
@gf up -a
|
||||
|
||||
# Build binary using configuration from hack/config.yaml.
|
||||
# Build binary using configuration from hack/config.example.yaml.
|
||||
.PHONY: build
|
||||
build: cli.install
|
||||
@gf build -ew
|
||||
@@ -75,10 +75,6 @@ pbentity: cli.install
|
||||
@gf gen pbentity
|
||||
|
||||
|
||||
mod:
|
||||
|
||||
|
||||
|
||||
export AppName=jieiot_linux
|
||||
export BuildVersion=$(shell git describe --abbrev=0 --tags)
|
||||
export BuildTime=$(shell date +%FT%T%z)
|
||||
@@ -88,7 +84,7 @@ export HasImages=$(shell docker images | grep docker_iotlcmupstreamproxy:v0 | gr
|
||||
.PHONY: docker_iotlcmupstreamproxy
|
||||
docker_iotlcmupstreamproxy:
|
||||
if [ -n "${HasImages}" ]; then \
|
||||
docker tag docker_iotlcmupstreamproxy:v0 ${REGISTRY}/docker_iotlcmupstreamproxy:v0 \
|
||||
docker tag docker_iotlcmupstreamproxy:v0 docker_iotlcmupstreamproxy:v0.${NOWTIME}.bak; \
|
||||
docker rmi docker_iotlcmupstreamproxy:v0; \
|
||||
fi
|
||||
docker build --rm -f build/Dockerfile --progress=plain --platform linux/amd64 -t docker_iotlcmupstreamproxy:v0 --build-arg BuildVersion=${BuildVersion} --build-arg BuildTime=${BuildTime} --build-arg CommitID=${CommitID} .
|
||||
@@ -96,4 +92,3 @@ docker_iotlcmupstreamproxy:
|
||||
|
||||
dockerbuild: docker_iotlcmupstreamproxy
|
||||
echo "docker build success"
|
||||
dockerpush:
|
||||
@@ -1,12 +1,134 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
v1 "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/api/cardquery/v1"
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/logic/simKeyFill"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/logic/upstreamapi"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/logic/upstreamimpl"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
)
|
||||
|
||||
func TestAPNHTTPHarness(t *testing.T) {
|
||||
if os.Getenv("APN_HTTP_CHAIN_HELPER") != "1" {
|
||||
t.Skip("未启用本机HTTP模拟链")
|
||||
}
|
||||
gateway, err := url.Parse(os.Getenv("APN_HTTP_CHAIN_CHAN"))
|
||||
if err != nil || gateway.Scheme != "http" || gateway.Hostname() != "127.0.0.1" || gateway.Port() == "" {
|
||||
t.Fatal("只允许本机模拟chan")
|
||||
}
|
||||
adapter, err := gcfg.NewAdapterContent(fmt.Sprintf(`{"gateway":{"address":%q,"timeout":"2s"}}`, gateway.Host))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
g.Cfg().SetAdapter(adapter)
|
||||
api := upstreamapi.NewUpstreamAPI()
|
||||
api.RegisterChan("fake-channel", "1", &model.SimCardChannelCache{Instance: upstreamimpl.NewSimYD()})
|
||||
service.RegisterUpstreamAPI(api)
|
||||
server := ghttp.GetServer(t.Name())
|
||||
server.SetAddr("127.0.0.1:0")
|
||||
bindHTTPRoutes(server)
|
||||
stop := make(chan struct{})
|
||||
server.BindHandler("POST:/__test/stop", func(r *ghttp.Request) { close(stop) })
|
||||
if err := server.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Shutdown()
|
||||
fmt.Printf("APN_CHAIN_READY=http://127.0.0.1:%d\n", server.GetListenedPort())
|
||||
select {
|
||||
case <-stop:
|
||||
case <-time.After(3 * time.Minute):
|
||||
t.Error("HTTP模拟链未正常结束")
|
||||
}
|
||||
}
|
||||
|
||||
type apnBindingTestFill struct {
|
||||
service.ISimKeyFill
|
||||
captured chan model.SimBaseReqJson
|
||||
}
|
||||
|
||||
func (s *apnBindingTestFill) SimKeyFill(_ context.Context, input *model.SimBaseReqJson) (model.SimBaseResJson, error) {
|
||||
s.captured <- *input
|
||||
return model.SimBaseResJson{}, nil
|
||||
}
|
||||
|
||||
func TestAPNProductionHTTPBindingPreservesRawPayload(t *testing.T) {
|
||||
old := service.SimKeyFill()
|
||||
capture := &apnBindingTestFill{ISimKeyFill: old, captured: make(chan model.SimBaseReqJson, 1)}
|
||||
service.RegisterSimKeyFill(capture)
|
||||
t.Cleanup(func() { service.RegisterSimKeyFill(old) })
|
||||
server := ghttp.GetServer(t.Name())
|
||||
server.SetAddr("127.0.0.1:0")
|
||||
bindHTTPRoutes(server)
|
||||
server.BindHandler("POST:/__test/legacy-binding", func(r *ghttp.Request) {
|
||||
var req v1.SimBaseReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
t.Error(err)
|
||||
r.Response.WriteStatus(400)
|
||||
return
|
||||
}
|
||||
capture.captured <- req.SimBaseReqJson
|
||||
})
|
||||
if err := server.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = server.Shutdown() })
|
||||
for _, data := range []string{
|
||||
`{"operationId":"frozen-operation","submitOnly":true,"operType":"1","apnName":"CMIOT"}`,
|
||||
`{"operationId":"frozen-operation","queryJobId":"saved-job","operType":"1","apnName":"CMIOT"}`,
|
||||
`{"operationId":"frozen-operation","recoverOnly":true,"operType":"1","apnName":"CMIOT"}`,
|
||||
} {
|
||||
for _, path := range []string{"/sim/change/sim-apn", "/sim/query/sim-apn-capability", "/sim/query/sim-session"} {
|
||||
input := model.SimBaseReqJson{SimKeys: []*model.SimKey{{ChanKey: "fake", ICCID: "fake-card", MSISDN: "frozen-number"}}, ReqData: json.RawMessage(data)}
|
||||
response, err := g.Client().ContentJson().Post(context.Background(), fmt.Sprintf("http://127.0.0.1:%d%s", server.GetListenedPort(), path), input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body := response.ReadAll()
|
||||
_ = response.Close()
|
||||
select {
|
||||
case got := <-capture.captured:
|
||||
var wantData, gotData map[string]any
|
||||
_ = json.Unmarshal(input.ReqData, &wantData)
|
||||
_ = json.Unmarshal(got.ReqData, &gotData)
|
||||
wantJSON, _ := json.Marshal(wantData)
|
||||
gotJSON, _ := json.Marshal(gotData)
|
||||
if path == "/sim/query/sim-session" {
|
||||
baselineResponse, err := g.Client().ContentJson().Post(context.Background(), fmt.Sprintf("http://127.0.0.1:%d/__test/legacy-binding", server.GetListenedPort()), input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = baselineResponse.Close()
|
||||
baseline := <-capture.captured
|
||||
if string(got.ReqData) != string(baseline.ReqData) {
|
||||
t.Fatalf("非APN旧绑定行为改变:got=%q baseline=%q", got.ReqData, baseline.ReqData)
|
||||
}
|
||||
} else if sha256.Sum256(wantJSON) != sha256.Sum256(gotJSON) {
|
||||
t.Fatalf("APN冻结请求摘要改变:path=%s want=%s got=%s", path, wantJSON, gotJSON)
|
||||
}
|
||||
if len(got.SimKeys) != 1 || *got.SimKeys[0] != *input.SimKeys[0] {
|
||||
t.Fatalf("代理生产绑定丢字段:%+v", got)
|
||||
}
|
||||
default:
|
||||
t.Fatalf("未经过生产代理controller:%s", body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindHTTPRoutesRegistersChannelControlRoutes(t *testing.T) {
|
||||
server := ghttp.GetServer("proxy-channel-refresh-route-test")
|
||||
server.SetAddr("127.0.0.1:0")
|
||||
|
||||
@@ -2,6 +2,10 @@ package cardquery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
v1 "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/api/cardquery/v1"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
)
|
||||
@@ -46,6 +50,13 @@ import (
|
||||
// }
|
||||
|
||||
func (c *ControllerV1) SimBase(ctx context.Context, req *v1.SimBaseReq) (res *v1.SimBaseRes, err error) {
|
||||
request := g.RequestFromCtx(ctx)
|
||||
if request != nil && (request.URL.Path == "/sim/change/sim-apn" || request.URL.Path == "/sim/query/sim-apn-capability") && strings.HasPrefix(strings.ToLower(request.Header.Get("Content-Type")), "application/json") {
|
||||
// GoFrame通用字段转换不能保留json.RawMessage,APN协议直接按原始JSON绑定。
|
||||
if err := json.Unmarshal(request.GetBody(), &req.SimBaseReqJson); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
out, err := service.SimKeyFill().SimKeyFill(ctx, &req.SimBaseReqJson)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -48,7 +48,7 @@ type TSimCardInfoColumns struct {
|
||||
DataServiceStatus string // 数据服务状态:1启用、0禁用
|
||||
PackageTotalFlowMb string // 套餐总流量MB
|
||||
UsedFlowMb string // 已用流量MB
|
||||
TrafficCutoffStatus string // 达量断网配置状态:0未配置,1已开启,2已关闭
|
||||
TrafficCutoffStatus string // 达量断网配置状态:0未配置,1已开启,2已关闭
|
||||
TrafficCutoffThreshold string // 达量断网阈值
|
||||
SmsServiceStatus string // 短信服务状态:1启用、0禁用
|
||||
PackageTotalSms string // 套餐短信总条数
|
||||
@@ -107,7 +107,7 @@ var tSimCardInfoColumns = TSimCardInfoColumns{
|
||||
DataServiceStatus: "data_service_status",
|
||||
PackageTotalFlowMb: "package_total_flow_mb",
|
||||
UsedFlowMb: "used_flow_mb",
|
||||
TrafficCutoffStatus: "traffic_cutoff_status",
|
||||
TrafficCutoffStatus: "traffic_cutoff_status",
|
||||
TrafficCutoffThreshold: "traffic_cutoff_threshold",
|
||||
SmsServiceStatus: "sms_service_status",
|
||||
PackageTotalSms: "package_total_sms",
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/dao"
|
||||
"sync"
|
||||
"time"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/dao"
|
||||
|
||||
"github.com/gogf/gf/v2/crypto/gmd5"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
|
||||
@@ -2,8 +2,8 @@ package channelconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model/entity"
|
||||
"testing"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model/entity"
|
||||
)
|
||||
|
||||
func TestChannelVersionDetectsCredentialChanges(t *testing.T) {
|
||||
|
||||
@@ -2,11 +2,12 @@ package simKeyFill
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -24,6 +25,21 @@ func init() {
|
||||
}
|
||||
|
||||
func (s *sSimKeyFill) SimKeyFill(ctx context.Context, input *model.SimBaseReqJson) (output model.SimBaseResJson, err error) {
|
||||
var operation struct {
|
||||
OperationID string `json:"operationId"`
|
||||
}
|
||||
request := g.RequestFromCtx(ctx)
|
||||
if request != nil && (request.URL.Path == "/sim/change/sim-apn" || request.URL.Path == "/sim/query/sim-apn-capability") && json.Unmarshal(input.ReqData, &operation) == nil && operation.OperationID != "" {
|
||||
if len(input.SimKeys) == 0 || len(input.SimKeys) > 100 {
|
||||
return nil, gerror.New("异步子任务卡数必须在1至100之间")
|
||||
}
|
||||
for _, key := range input.SimKeys {
|
||||
if key == nil || key.ChanKey == "" || key.ICCID == "" {
|
||||
return nil, gerror.New("异步子任务必须保留chanKey和ICCID快照")
|
||||
}
|
||||
}
|
||||
return service.UpstreamAPI().SimBase(ctx, input)
|
||||
}
|
||||
simKeys, err := s.batchGetSimKey(ctx, input.SimKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package simKeyFill
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
)
|
||||
|
||||
type snapshotTestAPI struct {
|
||||
service.IUpstreamAPI
|
||||
input *model.SimBaseReqJson
|
||||
}
|
||||
|
||||
func (a *snapshotTestAPI) SimBase(_ context.Context, in *model.SimBaseReqJson) (model.SimBaseResJson, error) {
|
||||
a.input = in
|
||||
return nil, nil
|
||||
}
|
||||
func TestAsyncOperationPreservesCardSnapshot(t *testing.T) {
|
||||
api := &snapshotTestAPI{}
|
||||
service.RegisterUpstreamAPI(api)
|
||||
defer service.RegisterUpstreamAPI(nil)
|
||||
in := &model.SimBaseReqJson{SimKeys: []*model.SimKey{{ChanKey: "test", ICCID: "test-card", MSISDN: "snapshot-number"}}, ReqData: json.RawMessage(`{"operationId":"stable-id","submitOnly":true}`)}
|
||||
_, err := NewSimKeyFill().SimKeyFill((&ghttp.Request{Request: httptest.NewRequest("POST", "/sim/change/sim-apn", nil)}).Context(), in)
|
||||
if err != nil || api.input != in || api.input.SimKeys[0].MSISDN != "snapshot-number" {
|
||||
t.Fatalf("异步请求不应重新填充或改写卡快照:%v", err)
|
||||
}
|
||||
}
|
||||
func TestAsyncOperationRejectsIncompleteSnapshot(t *testing.T) {
|
||||
_, err := NewSimKeyFill().SimKeyFill((&ghttp.Request{Request: httptest.NewRequest("POST", "/sim/change/sim-apn", nil)}).Context(), &model.SimBaseReqJson{SimKeys: []*model.SimKey{{ICCID: "test-card"}}, ReqData: json.RawMessage(`{"operationId":"stable-id"}`)})
|
||||
if err == nil {
|
||||
t.Fatal("缺失通道快照应在调用前拒绝")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package upstreamapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
)
|
||||
|
||||
type apnPassthroughTestChannel struct{ reqData json.RawMessage }
|
||||
|
||||
func (c *apnPassthroughTestChannel) SimBase(_ context.Context, input *model.SimBaseReqJson) (model.SimBaseResJson, error) {
|
||||
c.reqData = append(json.RawMessage(nil), input.ReqData...)
|
||||
return model.SimBaseResJson{&model.SimBaseRes[json.RawMessage]{SimKey: input.SimKeys[0], Code: 0, Message: "已受理", ResData: json.RawMessage(`{"orderNum":"job-persisted","pending":true,"uncertain":false}`)}}, nil
|
||||
}
|
||||
func TestAPNProxyUnknownChannelPreservesUncertain(t *testing.T) {
|
||||
api := NewUpstreamAPI()
|
||||
out, err := api.SimBase((&ghttp.Request{Request: httptest.NewRequest("POST", "/sim/change/sim-apn", nil)}).Context(), &model.SimBaseReqJson{
|
||||
SimKeys: []*model.SimKey{{ChanKey: "missing_chan", ICCID: "test"}},
|
||||
ReqData: json.RawMessage(`{"operationId":"stable-id","submitOnly":true}`),
|
||||
})
|
||||
if err != nil || len(out) != 1 || !strings.Contains(string(out[0].ResData), `"uncertain":true`) {
|
||||
t.Fatalf("未知通道不能误报业务失败: result=%+v err=%v", out, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonAPNProxySameNamedFieldsKeepLegacyFailure(t *testing.T) {
|
||||
api := NewUpstreamAPI()
|
||||
ctx := (&ghttp.Request{Request: httptest.NewRequest("POST", "/sim/change/sim-status", nil)}).Context()
|
||||
out, err := api.SimBase(ctx, &model.SimBaseReqJson{SimKeys: []*model.SimKey{{ChanKey: "missing_chan", ICCID: "test"}}, ReqData: json.RawMessage(`{"operationId":"other-domain","submitOnly":true,"recoverOnly":true,"queryJobId":"unrelated"}`)})
|
||||
if err != nil || len(out) != 1 || string(out[0].ResData) != `{"status":"-2"}` {
|
||||
t.Fatalf("非APN同名字段改变既有失败语义:%+v %v", out, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPNProxyPreservesOperationAndAsyncFields(t *testing.T) {
|
||||
api := NewUpstreamAPI()
|
||||
instance := &apnPassthroughTestChannel{}
|
||||
api.RegisterChan("test_chan", "test", &model.SimCardChannelCache{Instance: instance})
|
||||
req := json.RawMessage(`{"operationId":"stable-id","submitOnly":true,"recoverOnly":false,"operType":"1"}`)
|
||||
out, err := api.SimBase((&ghttp.Request{Request: httptest.NewRequest("POST", "/sim/change/sim-apn", nil)}).Context(), &model.SimBaseReqJson{SimKeys: []*model.SimKey{{ChanKey: "test_chan", ICCID: "test"}}, ReqData: req})
|
||||
if err != nil || len(out) != 1 {
|
||||
t.Fatalf("proxy请求错误:%v %+v", err, out)
|
||||
}
|
||||
if !strings.Contains(string(instance.reqData), `"operationId":"stable-id"`) {
|
||||
t.Fatalf("operationId丢失:%s", instance.reqData)
|
||||
}
|
||||
if !strings.Contains(string(out[0].ResData), `"pending":true`) || !strings.Contains(string(out[0].ResData), `"orderNum":"job-persisted"`) {
|
||||
t.Fatalf("受理标识丢失:%s", out[0].ResData)
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ func (f *errCodeTestChannel) SimBase(context.Context, *model.SimBaseReqJson) (mo
|
||||
}
|
||||
|
||||
func TestSimBasePreservesCarrierErrCode(t *testing.T) {
|
||||
const payload = `{"code":0,"message":"success","data":[{"code":9999,"message":"http status 797","errCode":"S00004","simKey":{"chanKey":"channel_003","iccid":"8986112520409968013"},"resData":{}}]}`
|
||||
const payload = `{"code":0,"message":"success","data":[{"code":9999,"message":"http status 797","errCode":"S00004","simKey":{"chanKey":"channel_003","iccid":"8986000000000000002"},"resData":{}}]}`
|
||||
|
||||
var upstream model.SimResponseData[model.SimBaseResJson]
|
||||
if err := json.Unmarshal([]byte(payload), &upstream); err != nil {
|
||||
@@ -38,7 +38,7 @@ func TestSimBasePreservesCarrierErrCode(t *testing.T) {
|
||||
output, err := api.SimBase(context.Background(), &model.SimBaseReqJson{
|
||||
SimKeys: []*model.SimKey{{
|
||||
ChanKey: "channel_003",
|
||||
ICCID: "8986112520409968013",
|
||||
ICCID: "8986000000000000002",
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -3,14 +3,14 @@ package upstreamapi
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/consts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -317,6 +317,17 @@ func (u *sUpstreamAPI) packChanKey(ctx context.Context, simKeys []*model.SimKey)
|
||||
func (u *sUpstreamAPI) SimBase(ctx context.Context, input *model.SimBaseReqJson) (model.SimBaseResJson, error) {
|
||||
output := make([]*model.SimBaseRes[json.RawMessage], 0)
|
||||
inputMap := make(map[string]*model.SimBaseReqJson)
|
||||
// 提交/恢复/查询阶段的代理异常不是运营商办理失败。
|
||||
failureResData := json.RawMessage(`{"status":"-2"}`)
|
||||
var apnRequest struct {
|
||||
SubmitOnly bool `json:"submitOnly"`
|
||||
RecoverOnly bool `json:"recoverOnly"`
|
||||
QueryJobID string `json:"queryJobId"`
|
||||
}
|
||||
request := g.RequestFromCtx(ctx)
|
||||
if request != nil && request.URL.Path == "/sim/change/sim-apn" && json.Unmarshal(input.ReqData, &apnRequest) == nil && (apnRequest.SubmitOnly || apnRequest.RecoverOnly || apnRequest.QueryJobID != "") {
|
||||
failureResData = json.RawMessage(`{"uncertain":true}`)
|
||||
}
|
||||
chanKeyMap, err := u.packChanKey(ctx, input.SimKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -334,7 +345,7 @@ func (u *sUpstreamAPI) SimBase(ctx context.Context, input *model.SimBaseReqJson)
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusError,
|
||||
Message: "通道未配置",
|
||||
ResData: json.RawMessage(`{"status": "-2"}`),
|
||||
ResData: failureResData,
|
||||
})
|
||||
}
|
||||
continue
|
||||
@@ -346,7 +357,7 @@ func (u *sUpstreamAPI) SimBase(ctx context.Context, input *model.SimBaseReqJson)
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusError,
|
||||
Message: "通道未实例化",
|
||||
ResData: json.RawMessage(`{"status": "-2"}`),
|
||||
ResData: failureResData,
|
||||
})
|
||||
}
|
||||
continue
|
||||
@@ -358,7 +369,7 @@ func (u *sUpstreamAPI) SimBase(ctx context.Context, input *model.SimBaseReqJson)
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusError,
|
||||
Message: err.Error(),
|
||||
ResData: json.RawMessage(`{"status": "-2"}`),
|
||||
ResData: failureResData,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package upstreamimpl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/logic/upstreamapi"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
)
|
||||
|
||||
func TestAPNProxyHTTPFailureIsUncertainOnlyOnAPNRoute(t *testing.T) {
|
||||
oldAdapter := g.Cfg().GetAdapter()
|
||||
defer g.Cfg().SetAdapter(oldAdapter)
|
||||
for _, tc := range []struct {
|
||||
name, path, body string
|
||||
disconnect, uncertain bool
|
||||
}{
|
||||
{"HTTP200顶层9999", "/sim/change/sim-apn", `{"code":9999,"message":"模拟网关未确认"}`, false, true},
|
||||
{"通道连接断开", "/sim/change/sim-apn", "", true, true},
|
||||
{"非APN同名字段", "/sim/change/sim-status", `{"code":9999,"message":"模拟非APN网关错误"}`, false, false},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
chanServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if tc.disconnect {
|
||||
conn, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte(tc.body))
|
||||
}))
|
||||
defer chanServer.Close()
|
||||
adapter, err := gcfg.NewAdapterContent(`{"gateway":{"address":"` + strings.TrimPrefix(chanServer.URL, "http://") + `","timeout":"1s"}}`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
g.Cfg().SetAdapter(adapter)
|
||||
api := upstreamapi.NewUpstreamAPI()
|
||||
api.RegisterChan("fake-channel", "test", &model.SimCardChannelCache{Instance: &sSimYD{}})
|
||||
proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var input model.SimBaseReqJson
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
ctx := (&ghttp.Request{Request: r}).Context()
|
||||
items, err := api.SimBase(ctx, &input)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"code": 0, "data": items})
|
||||
}))
|
||||
defer proxy.Close()
|
||||
body := []byte(`{"simKeys":[{"chanKey":"fake-channel","iccid":"fake-card"}],"reqData":{"operationId":"fake-operation","submitOnly":true}}`)
|
||||
response, err := http.Post(proxy.URL+tc.path, "application/json", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
var output struct {
|
||||
Code int `json:"code"`
|
||||
Data model.SimBaseResJson `json:"data"`
|
||||
}
|
||||
if err := json.NewDecoder(response.Body).Decode(&output); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if response.StatusCode != 200 || output.Code != 0 || len(output.Data) != 1 || output.Data[0].Code != 9999 || output.Data[0].Message == "" {
|
||||
t.Fatalf("代理异常响应无效:HTTP=%d result=%+v", response.StatusCode, output)
|
||||
}
|
||||
isUncertain := strings.Contains(string(output.Data[0].ResData), `"uncertain":true`)
|
||||
if isUncertain != tc.uncertain {
|
||||
t.Fatalf("APN路由隔离失效:%s", output.Data[0].ResData)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPNProxyHTTPKeepsDurableJobAndFrozenRequest(t *testing.T) {
|
||||
oldAdapter := g.Cfg().GetAdapter()
|
||||
defer g.Cfg().SetAdapter(oldAdapter)
|
||||
var captured model.SimBaseReqJson
|
||||
chanServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := json.NewDecoder(r.Body).Decode(&captured); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"code":0,"data":[{"code":0,"simKey":{"chanKey":"fake-channel","iccid":"fake-card","msisdn":"frozen-number"},"resData":{"orderNum":"saved-job","pending":true}}]}`))
|
||||
}))
|
||||
defer chanServer.Close()
|
||||
adapter, err := gcfg.NewAdapterContent(`{"gateway":{"address":"` + strings.TrimPrefix(chanServer.URL, "http://") + `","timeout":"1s"}}`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
g.Cfg().SetAdapter(adapter)
|
||||
api := upstreamapi.NewUpstreamAPI()
|
||||
api.RegisterChan("fake-channel", "test", &model.SimCardChannelCache{Instance: &sSimYD{}})
|
||||
input := &model.SimBaseReqJson{SimKeys: []*model.SimKey{{ChanKey: "fake-channel", ICCID: "fake-card", MSISDN: "frozen-number"}}, ReqData: json.RawMessage(`{"operationId":"stable-operation","recoverOnly":true}`)}
|
||||
ctx := (&ghttp.Request{Request: httptest.NewRequest("POST", "/sim/change/sim-apn", nil)}).Context()
|
||||
items, err := api.SimBase(ctx, input)
|
||||
if err != nil || len(items) != 1 || !strings.Contains(string(items[0].ResData), `"orderNum":"saved-job"`) || !strings.Contains(string(items[0].ResData), `"pending":true`) {
|
||||
t.Fatalf("HTTP转发丢失jobId:%+v %v", items, err)
|
||||
}
|
||||
if string(captured.ReqData) != string(input.ReqData) || captured.SimKeys[0].MSISDN != "frozen-number" {
|
||||
t.Fatalf("恢复请求被改写:%+v", captured)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,80 @@
|
||||
package upstreamimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"fmt"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"strings"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gclient"
|
||||
)
|
||||
|
||||
const (
|
||||
// gatewayBatchTimeoutConfigKey 限制单次批量转发的最长等待,防止上游异常时无限占用连接。
|
||||
gatewayBatchTimeoutConfigKey = "gateway.batchTimeout"
|
||||
// defaultGatewayBatchTimeout 覆盖 100 张卡按单卡 10 秒预算的最坏耗时,并留有余量。
|
||||
defaultGatewayBatchTimeout = 20 * time.Minute
|
||||
// defaultDataServiceTimeout 是数据开停转发的独立预算。
|
||||
defaultDataServiceTimeout = 210 * time.Second
|
||||
)
|
||||
|
||||
// configureGatewayTimeout 让响应头等待与整次请求使用同一预算,避免默认30秒提前中断。
|
||||
// upstream-chan 对批量操作按卡串行调用运营商接口,耗时随卡数线性增长;
|
||||
// 因此批量请求不能沿用 gclient 默认的 30 秒响应头超时,否则请求仍在办理就会被判为失败。
|
||||
func configureGatewayTimeout(ctx context.Context, client *gclient.Client, path string, count int, perCard time.Duration) {
|
||||
if path == "/sim/change/sim-apn" || path == "/sim/query/sim-apn-capability" {
|
||||
client.SetContentType("application/json")
|
||||
}
|
||||
applyGatewayTimeout(client, path, count, perCard,
|
||||
configDuration(ctx, "gateway.dataServiceTimeout", defaultDataServiceTimeout),
|
||||
configDuration(ctx, gatewayBatchTimeoutConfigKey, defaultGatewayBatchTimeout))
|
||||
}
|
||||
|
||||
// applyGatewayTimeout 计算并应用单次转发预算:整次请求与响应头等待必须一致,
|
||||
// 否则响应头超时会在业务仍在办理时提前中断请求。
|
||||
func applyGatewayTimeout(client *gclient.Client, path string, count int, perCard, dataServiceTimeout, batchTimeout time.Duration) {
|
||||
if count < 1 {
|
||||
count = 1
|
||||
}
|
||||
if perCard <= 0 {
|
||||
perCard = 10 * time.Second
|
||||
}
|
||||
timeout := perCard * time.Duration(count)
|
||||
if path == "/sim/change/sim-apn" {
|
||||
timeout = dataServiceTimeout
|
||||
if timeout <= 0 {
|
||||
timeout = defaultDataServiceTimeout
|
||||
}
|
||||
} else if batchTimeout > 0 && timeout > batchTimeout {
|
||||
timeout = batchTimeout
|
||||
}
|
||||
client.SetTimeout(timeout)
|
||||
if transport, ok := client.Transport.(*http.Transport); ok {
|
||||
transport.ResponseHeaderTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// configDuration 读取时长配置,兼容写成 "20m" 字符串或秒数整数两种形式。
|
||||
func configDuration(ctx context.Context, key string, fallback time.Duration) time.Duration {
|
||||
value := g.Cfg().MustGet(ctx, key)
|
||||
if value == nil || value.IsNil() {
|
||||
return fallback
|
||||
}
|
||||
if duration := value.Duration(); duration >= time.Second {
|
||||
return duration
|
||||
}
|
||||
if seconds := value.Int(); seconds > 0 {
|
||||
return time.Duration(seconds) * time.Second
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func readGatewayResponse(response *gclient.Response) (model.SimBaseResJson, error) {
|
||||
defer response.Close()
|
||||
body := response.ReadAll()
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package upstreamimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func TestGatewayTimeoutAllowsDelayedHeaders(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
time.Sleep(40 * time.Millisecond)
|
||||
_, _ = w.Write([]byte(`{"code":0,"data":[]}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
client := g.Client()
|
||||
other := g.Client()
|
||||
original := other.Transport.(*http.Transport)
|
||||
original.ResponseHeaderTimeout = time.Millisecond
|
||||
client.Transport.(*http.Transport).ResponseHeaderTimeout = time.Millisecond
|
||||
configureGatewayTimeout(context.Background(), client, "/sim/change/sim-apn", 1, time.Second)
|
||||
response, err := client.Post(context.Background(), server.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer response.Close()
|
||||
if original.ResponseHeaderTimeout != time.Millisecond {
|
||||
t.Fatal("修改了共享Transport")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonAPNGatewayTimeoutPreservesHeaderBudget(t *testing.T) {
|
||||
client := g.Client()
|
||||
transport := client.Transport.(*http.Transport)
|
||||
transport.ResponseHeaderTimeout = 17 * time.Second
|
||||
configureGatewayTimeout(context.Background(), client, "/sim/query/test", 2, 3*time.Second)
|
||||
if client.Client.Timeout != 6*time.Second || transport.ResponseHeaderTimeout != 6*time.Second {
|
||||
t.Fatalf("非APN响应头预算必须与请求预算一致:request=%s header=%s", client.Client.Timeout, transport.ResponseHeaderTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNonAPNBatchExpandsHeaderBudget 覆盖批量停复机等非 APN 路径:
|
||||
// 50 张卡按单卡预算放大后,响应头等待不能继续停留在 gclient 的 30 秒默认值。
|
||||
func TestNonAPNBatchExpandsHeaderBudget(t *testing.T) {
|
||||
client := g.Client()
|
||||
transport := client.Transport.(*http.Transport)
|
||||
transport.ResponseHeaderTimeout = 30 * time.Second
|
||||
applyGatewayTimeout(client, "/sim/change/sim-status", 50, 10*time.Second, defaultDataServiceTimeout, defaultGatewayBatchTimeout)
|
||||
if client.Client.Timeout != 500*time.Second {
|
||||
t.Fatalf("请求预算=%s,期望500s", client.Client.Timeout)
|
||||
}
|
||||
if transport.ResponseHeaderTimeout != client.Client.Timeout {
|
||||
t.Fatalf("响应头预算=%s与请求预算不一致", transport.ResponseHeaderTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNonAPNBatchRespectsBatchTimeoutCap 保证异常上游不会无限占用连接:
|
||||
// 超出批量上限时按上限截断,且响应头预算同步截断。
|
||||
func TestNonAPNBatchRespectsBatchTimeoutCap(t *testing.T) {
|
||||
client := g.Client()
|
||||
transport := client.Transport.(*http.Transport)
|
||||
applyGatewayTimeout(client, "/sim/query/usage", 1000, 10*time.Second, defaultDataServiceTimeout, defaultGatewayBatchTimeout)
|
||||
if client.Client.Timeout != defaultGatewayBatchTimeout {
|
||||
t.Fatalf("请求预算=%s,期望批量上限%s", client.Client.Timeout, defaultGatewayBatchTimeout)
|
||||
}
|
||||
if transport.ResponseHeaderTimeout != defaultGatewayBatchTimeout {
|
||||
t.Fatalf("响应头预算=%s,期望批量上限%s", transport.ResponseHeaderTimeout, defaultGatewayBatchTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNonAPNSingleCardKeepsPerCardBudget 保证单卡请求不被放大成批量预算。
|
||||
func TestNonAPNSingleCardKeepsPerCardBudget(t *testing.T) {
|
||||
for _, count := range []int{0, 1} {
|
||||
client := g.Client()
|
||||
transport := client.Transport.(*http.Transport)
|
||||
applyGatewayTimeout(client, "/sim/query/test", count, 10*time.Second, defaultDataServiceTimeout, defaultGatewayBatchTimeout)
|
||||
if client.Client.Timeout != 10*time.Second || transport.ResponseHeaderTimeout != 10*time.Second {
|
||||
t.Fatalf("count=%d request=%s header=%s", count, client.Client.Timeout, transport.ResponseHeaderTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDataServiceTimeoutOverridesCardBudget(t *testing.T) {
|
||||
for _, count := range []int{0, 1, 100} {
|
||||
client := g.Client()
|
||||
configureGatewayTimeout(context.Background(), client, "/sim/change/sim-apn", count, time.Millisecond)
|
||||
if client.Client.Timeout != 210*time.Second {
|
||||
t.Fatalf("count=%d timeout=%s", count, client.Client.Timeout)
|
||||
}
|
||||
if client.Transport.(*http.Transport).ResponseHeaderTimeout != client.Client.Timeout {
|
||||
t.Fatal("响应头预算不一致")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/logic"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
)
|
||||
|
||||
func TestMingqianProxyTemplate(t *testing.T) {
|
||||
|
||||
@@ -3,11 +3,11 @@ package upstreamimpl
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"time"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/logic/upstreamimpl/dx"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -85,7 +85,7 @@ func (s *sSimDX) SimBase(ctx context.Context, input *model.SimBaseReqJson) (mode
|
||||
}
|
||||
client := g.Client()
|
||||
client.SetDiscovery(gsvc.GetRegistry())
|
||||
client.SetTimeout(s.getUpstreamTimeout(ctx) * time.Duration(len(input.SimKeys)))
|
||||
configureGatewayTimeout(ctx, client, path, len(input.SimKeys), s.getUpstreamTimeout(ctx))
|
||||
resp, err := client.Post(ctx, url, input)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "SimBase post error %+v,url %s, params %+v, ", err, url, input)
|
||||
|
||||
@@ -3,10 +3,10 @@ package upstreamimpl
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -106,11 +106,11 @@ func (s *sSimYD) SimBase(ctx context.Context, input *model.SimBaseReqJson) (mode
|
||||
g.Log().Debugf(ctx, "SimYD.SimBase, url %s", url)
|
||||
client := g.Client()
|
||||
client.SetDiscovery(gsvc.GetRegistry())
|
||||
client.SetTimeout(s.getUpstreamTimeout(ctx) * time.Duration(len(input.SimKeys)))
|
||||
configureGatewayTimeout(ctx, client, path, len(input.SimKeys), s.getUpstreamTimeout(ctx))
|
||||
resp, err := client.Post(ctx, url, input)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "SimYD.SimBase, post error %+v,url %s, params %+v, ", err, url, input)
|
||||
return nil, gerror.New("请求失败")
|
||||
return nil, gerror.Wrap(err, "请求通道失败")
|
||||
}
|
||||
return readGatewayResponse(resp)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// package version
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2025 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @Author Lxj <xxx@example.com>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
package version
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Package xjpubconsts
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2025 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @Author Lxj <xxx@example.com>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
package xjpubconsts
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// package middleware
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2025 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @Author Lxj <xxx@example.com>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
package middleware
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// package response
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2025 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @Author Lxj <xxx@example.com>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
package response
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// package response
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2025 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @Author Lxj <xxx@example.com>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
package response
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/packed"
|
||||
"os"
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/packed"
|
||||
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpublogic"
|
||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# config.yaml 配置文件
|
||||
# @Link https://github.com/xiujiecn/xiu-admin
|
||||
# @Copyright Copyright (c) 2025 LiXiujie
|
||||
# @Author Lxj <li@xiujie.cn>
|
||||
# @Author Lxj <xxx@example.com>
|
||||
# @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
# 系统配置
|
||||
system:
|
||||
@@ -34,7 +34,7 @@ server:
|
||||
registry:
|
||||
type: "consul"
|
||||
address: "localhost:8500"
|
||||
# address: "192.0.2.70:8500"
|
||||
# address: "127.0.0.1:8500"
|
||||
|
||||
# 日志配置
|
||||
logger:
|
||||
@@ -62,7 +62,7 @@ database:
|
||||
level: "all"
|
||||
stdout: true
|
||||
default: # 分组名称,可自定义,默认为default
|
||||
link: "mysql:${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:3306)/db_iotlcm?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai"
|
||||
link: "${DB_DSN}"
|
||||
debug: true #开启调试模式
|
||||
charset: "utf8mb4" # (可选)数据库编码(如: utf8mb4/utf8/gbk/gb2312),一般设置为utf8mb4。默认为utf8。
|
||||
dryRun: false #ORM空跑(只读不写)
|
||||
@@ -71,7 +71,7 @@ database:
|
||||
maxLifetime: 120 #(单位秒)连接对象可重复使用的时间长度
|
||||
memorydb:
|
||||
# link: "sqlite::@file(jieiotmem.db)?journal_mode=WAL"
|
||||
link: "sqlite::@file(:memory:)"
|
||||
link: "${DB_DSN}"
|
||||
# link: ""
|
||||
debug: true
|
||||
maxIdle: 1
|
||||
@@ -88,10 +88,10 @@ redis:
|
||||
# 单实例配置
|
||||
default:
|
||||
mode: "single" #redis模式,支持:single|cluster|sentinel
|
||||
sentinelMasterName: "${REDIS_SENTINEL_MASTER}" #哨兵模式主节点名称
|
||||
address: 192.0.2.29:6379
|
||||
sentinelMasterName: "example-master" #哨兵模式主节点名称
|
||||
address: 127.0.0.1:6379
|
||||
db: 0
|
||||
pass: "${REDIS_PASSWORD}"
|
||||
pass: "${SERVICE_PASSWORD}"
|
||||
minIdle: 5 #最小空闲连接数
|
||||
maxIdle: 30 #允许闲置的最大连接数
|
||||
maxActive: 5000 #最大活跃连接数
|
||||
Reference in New Issue
Block a user