chore: 并入 iotlcm-upstream-proxy 历史到 upstream-proxy/(原提交 44209ec)
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# 统一使用 LF,避免跨平台协作时产生整文件 diff
|
||||
* text=auto eol=lf
|
||||
|
||||
# 二进制文件不做行尾转换
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
*.ttf binary
|
||||
*.pdf binary
|
||||
*.exe binary
|
||||
*.go linguist-language=Go
|
||||
@@ -0,0 +1,64 @@
|
||||
name: mirror-to-gitee
|
||||
|
||||
# 把本仓同步到 Gitee 企业仓 snowgoat/<同名仓库>。
|
||||
# 触发:main 分支推送、v* tag 推送、手动;另有每日兜底重试。
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- 'v*'
|
||||
schedule:
|
||||
# Gitea Actions 的 cron 用 UTC:18:30 UTC = 次日 02:30 北京时间
|
||||
- cron: '30 18 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: mirror-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
runs-on: host
|
||||
steps:
|
||||
- name: 同步到 Gitee
|
||||
env:
|
||||
SRC_TOKEN: ${{ secrets.SRC_GIT_TOKEN }}
|
||||
DST_TOKEN: ${{ secrets.GITEE_TOKEN }}
|
||||
DST_OWNER: ${{ secrets.GITEE_OWNER }}
|
||||
DST_USER: ${{ secrets.GITEE_USER }}
|
||||
REPO_NAME: ${{ github.event.repository.name }}
|
||||
run: |
|
||||
set -u
|
||||
|
||||
if [ -z "${REPO_NAME:-}" ]; then
|
||||
echo "未取到仓库名,退出"; exit 1
|
||||
fi
|
||||
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
echo "源:git.5iot.com/iotlcm-public/$REPO_NAME"
|
||||
echo "目标:gitee.com/$DST_OWNER/$REPO_NAME"
|
||||
|
||||
git clone --mirror "https://jenkins:${SRC_TOKEN}@git.5iot.com/iotlcm-public/${REPO_NAME}.git" "$WORK/repo.git"
|
||||
cd "$WORK/repo.git"
|
||||
echo "本地 ref:$(git for-each-ref --format='%(refname:short)' | tr '\n' ' ')"
|
||||
|
||||
# Gitee 在推送密集时会返回 429 Pending queue overflowed / 408 Authorization server timeout,
|
||||
# 属服务端限流,退避重试即可。
|
||||
attempt=0
|
||||
while [ "$attempt" -lt 5 ]; do
|
||||
attempt=$((attempt + 1))
|
||||
echo "----- 推送尝试 $attempt/5"
|
||||
if git push --mirror "https://${DST_USER}:${DST_TOKEN}@gitee.com/${DST_OWNER}/${REPO_NAME}.git" 2>&1; then
|
||||
echo "✅ 已同步到 Gitee"
|
||||
exit 0
|
||||
fi
|
||||
wait_s=$((attempt * 30))
|
||||
echo "推送失败,${wait_s}s 后重试"
|
||||
sleep "$wait_s"
|
||||
done
|
||||
|
||||
echo "❌ 连续 5 次推送失败,请检查 Gitee 状态或令牌"
|
||||
exit 1
|
||||
@@ -0,0 +1,80 @@
|
||||
name: trigger-jenkins-oss
|
||||
|
||||
# 打 tag 时触发 Jenkins 构建开源镜像并推送到镜像仓库。
|
||||
# 仅在 tag 推送时触发;main 分支的日常提交不触发。
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
|
||||
# 同一 ref 连续触发时取消旧任务,只跑最新的
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
runs-on: host
|
||||
steps:
|
||||
- name: 触发 Jenkins 镜像构建
|
||||
env:
|
||||
JU: ${{ secrets.JENKINS_USER }}
|
||||
JT: ${{ secrets.JENKINS_API_TOKEN }}
|
||||
JURL: ${{ secrets.JENKINS_URL }}
|
||||
JOB_PATH: ${{ secrets.JENKINS_JOB_PATH }}
|
||||
REPO_NAME: ${{ github.event.repository.name }}
|
||||
TAG_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
# 只有 tag 推送才构建;手动触发时按 tag 取,没有就退出
|
||||
case "${GITHUB_REF:-}" in
|
||||
refs/tags/v*) ;;
|
||||
*)
|
||||
if [ "${GITHUB_EVENT_NAME:-}" != "workflow_dispatch" ]; then
|
||||
echo "非 tag 推送,跳过:${GITHUB_REF:-unknown}"
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "${TAG_NAME:-}" ]; then
|
||||
echo "未取到 tag 名,退出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# job 在 Jenkins 文件夹下的路径(组织密钥 JENKINS_JOB_PATH),
|
||||
# 例如 job/iotlcm-opensrc/job/iotlcm-oss-build。
|
||||
# 用密钥而非硬编码,Jenkins 里移动 job 时不用改 11 个仓。
|
||||
JP="${JOB_PATH:-job/iotlcm-oss-build}"
|
||||
|
||||
echo "仓库:$REPO_NAME 版本:$TAG_NAME job:$JP"
|
||||
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
# 取 CSRF crumb
|
||||
curl -s -c "$WORK/cj" -u "$JU:$JT" "$JURL/crumbIssuer/api/json" -o "$WORK/crumb.json"
|
||||
CR=$(python3 -c "import json;print(json.load(open('$WORK/crumb.json'))['crumb'])")
|
||||
|
||||
# 触发参数化任务:SERVICES=仓库名,VERSION=tag
|
||||
code=$(curl -s -o "$WORK/out" -w '%{http_code}' -X POST -b "$WORK/cj" -u "$JU:$JT" \
|
||||
-H "Jenkins-Crumb: $CR" \
|
||||
--data-urlencode "SERVICES=$REPO_NAME" \
|
||||
--data-urlencode "VERSION=$TAG_NAME" \
|
||||
--data-urlencode "FORCE=true" \
|
||||
"$JURL/$JP/buildWithParameters")
|
||||
|
||||
echo "Jenkins 触发 HTTP $code"
|
||||
if [ "$code" != "201" ] && [ "$code" != "200" ] && [ "$code" != "302" ] && [ "$code" != "303" ]; then
|
||||
echo "触发失败:"
|
||||
cat "$WORK/out"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LINK="$JURL/$JP/"
|
||||
echo "=========================================="
|
||||
echo "Jenkins 构建:$LINK"
|
||||
echo "=========================================="
|
||||
echo "::notice title=Jenkins 镜像构建::[$LINK]($LINK)"
|
||||
@@ -0,0 +1,21 @@
|
||||
.buildpath
|
||||
.hgignore.swp
|
||||
.project
|
||||
.orig
|
||||
.swp
|
||||
.idea/
|
||||
.settings/
|
||||
.vscode/
|
||||
bin/
|
||||
**/.DS_Store
|
||||
gf
|
||||
main
|
||||
*.exe
|
||||
output/
|
||||
manifest/output/
|
||||
temp/
|
||||
temp.yaml
|
||||
bin
|
||||
*.log
|
||||
.keep-if-necessary
|
||||
.gitkeep
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,7 @@
|
||||
ROOT_DIR = $(shell pwd)
|
||||
NAMESPACE = "default"
|
||||
DEPLOY_NAME = "template-single"
|
||||
DOCKER_NAME = "template-single"
|
||||
|
||||
include ./hack/hack-cli.mk
|
||||
include ./hack/hack.mk
|
||||
@@ -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
|
||||
```
|
||||
@@ -0,0 +1,15 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package cardquery
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1 "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/api/cardquery/v1"
|
||||
)
|
||||
|
||||
type ICardqueryV1 interface {
|
||||
SimBase(ctx context.Context, req *v1.SimBaseReq) (res *v1.SimBaseRes, err error)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// sim
|
||||
type SimBaseReq struct {
|
||||
g.Meta `path:"/sim/*any" tags:"CardQuery" method:"GET,POST" summary:"物联网卡基础请求"`
|
||||
model.SimBaseReqJson
|
||||
}
|
||||
|
||||
type SimBaseRes = model.SimBaseResJson
|
||||
@@ -0,0 +1,12 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1 "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/api/channel/v1"
|
||||
)
|
||||
|
||||
type IChannelV1 interface {
|
||||
Refresh(ctx context.Context, req *v1.RefreshReq) (res *v1.RefreshRes, err error)
|
||||
Remove(ctx context.Context, req *v1.RemoveReq) (res *v1.RemoveRes, err error)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type RefreshReq struct {
|
||||
g.Meta `path:"/internal/channel/refresh" tags:"Internal" method:"POST" summary:"Refresh channel cache"`
|
||||
ChanKey string `json:"chanKey" in:"query" v:"required#chanKey is required"`
|
||||
}
|
||||
|
||||
type RefreshRes struct {
|
||||
ChanKey string `json:"chanKey"`
|
||||
Refreshed bool `json:"refreshed"`
|
||||
}
|
||||
|
||||
type RemoveReq struct {
|
||||
g.Meta `path:"/internal/channel/remove" tags:"Internal" method:"POST" summary:"Remove channel cache"`
|
||||
ChanKey string `json:"chanKey" in:"query" v:"required#chanKey is required"`
|
||||
}
|
||||
|
||||
type RemoveRes struct {
|
||||
ChanKey string `json:"chanKey"`
|
||||
Removed bool `json:"removed"`
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
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 ./
|
||||
|
||||
RUN go mod download
|
||||
|
||||
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}"
|
||||
|
||||
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 11140
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /build/iotlcmupstreamproxy_svc /app/iotlcmupstreamproxy_svc
|
||||
COPY --from=builder /build/build/config.example.yaml /app/config/config.yaml
|
||||
|
||||
CMD ["./iotlcmupstreamproxy_svc"]
|
||||
@@ -0,0 +1,118 @@
|
||||
# config.yaml 配置文件
|
||||
# @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"
|
||||
version: "1.0"
|
||||
description: "XiuAdmin Server"
|
||||
gfmode: "dev"
|
||||
upload:
|
||||
local:
|
||||
path: "resource/upload"
|
||||
|
||||
# 服务配置
|
||||
server:
|
||||
name: "yzupstreamproxy-http-svc"
|
||||
address: ":8510"
|
||||
# 接口文档
|
||||
openapiPath: "/api.json" # OpenAPI接口文档地址
|
||||
swaggerPath: "/swagger" # 内置SwaggerUI展示地址
|
||||
# 静态服务配置
|
||||
indexFiles: ["index.html","index.htm"] # 自动首页静态文件检索。默认为["index.html", "index.htm"]
|
||||
indexFolder: false # 当访问静态文件目录时,是否展示目录下的文件列表。默认关闭,那么请求将返回403
|
||||
# serverRoot: "resource/public" # 静态文件服务的目录根路径,配置时自动开启静态文件服务。默认关闭
|
||||
# searchPaths: ["/resource/public"] # 提供静态文件服务时额外的文件搜索路径,当根路径找不到时则按照顺序在搜索目录查找。默认关闭
|
||||
fileServerEnabled: true
|
||||
initLoadMemoryDB: false # 是否初始化内存数据库,默认关闭
|
||||
# 文件上传配置
|
||||
maxHeaderBytes: "20KB"
|
||||
clientMaxBodySize: "200MB"
|
||||
|
||||
registry:
|
||||
type: "consul"
|
||||
address: "127.0.0.1:8500"
|
||||
|
||||
# 日志配置
|
||||
logger:
|
||||
path: "/app/logs" # 日志文件路径。默认为空,表示关闭,仅输出到终端
|
||||
file: "{Y-m-d-H}.log" # 日志文件格式。默认为"{Y-m-d}.log"
|
||||
prefix: "" # 日志内容输出前缀。默认为空
|
||||
level: "dev" # 日志输出级别
|
||||
timeFormat: "2006-01-02T15:04:05" # 自定义日志输出的时间格式,使用Golang标准的时间格式配置
|
||||
ctxKeys: [] # 自定义Context上下文变量名称,自动打印Context的变量到日志中。默认为空
|
||||
header: true # 是否打印日志的头信息。默认true
|
||||
stdout: true # 日志是否同时输出到终端。默认true
|
||||
rotateSize: 0 # 按照日志文件大小对文件进行滚动切分。默认为0,表示关闭滚动切分特性
|
||||
rotateExpire: 0 # 按照日志文件时间间隔对文件滚动切分。默认为0,表示关闭滚动切分特性
|
||||
rotateBackupLimit: 0 # 按照切分的文件数量清理切分文件,当滚动切分特性开启时有效。默认为0,表示不备份,切分则删除
|
||||
rotateBackupExpire: 0 # 按照切分的文件有效期清理切分文件,当滚动切分特性开启时有效。默认为0,表示不备份,切分则删除
|
||||
rotateBackupCompress: 0 # 滚动切分文件的压缩比(0-9)。默认为0,表示不压缩
|
||||
rotateCheckInterval: "1h" # 滚动切分的时间检测间隔,一般不需要设置。默认为1小时
|
||||
stdoutColorDisabled: false # 关闭终端的颜色打印。默认开启
|
||||
writerColorEnable: false # 日志文件是否带上颜色。默认false,表示不带颜色
|
||||
|
||||
|
||||
database:
|
||||
logger:
|
||||
path: "/app/logs"
|
||||
level: "all"
|
||||
stdout: true
|
||||
default: # 分组名称,可自定义,默认为default
|
||||
link: "${DB_DSN}"
|
||||
debug: true #开启调试模式
|
||||
charset: "utf8mb4" # (可选)数据库编码(如: utf8mb4/utf8/gbk/gb2312),一般设置为utf8mb4。默认为utf8。
|
||||
dryRun: false #ORM空跑(只读不写)
|
||||
maxIdle: 30 #连接池最大闲置的连接数
|
||||
maxOpen: 100 #连接池最大打开的连接数
|
||||
maxLifetime: 120 #(单位秒)连接对象可重复使用的时间长度
|
||||
memorydb:
|
||||
# link: "sqlite::@file(jieiotmem.db)?journal_mode=WAL"
|
||||
link: "${DB_DSN}"
|
||||
# link: ""
|
||||
debug: true
|
||||
maxIdle: 1
|
||||
maxOpen: 1
|
||||
maxLifetime: 30
|
||||
|
||||
# 缓存配置
|
||||
cache:
|
||||
adapter: "redis" # 缓存适配器,支持:file|redis
|
||||
fileDir: "resource/cache" # 缓存文件目录
|
||||
|
||||
# Redis 配置示例
|
||||
redis:
|
||||
# 单实例配置
|
||||
default:
|
||||
mode: "single" #redis模式,支持:single|cluster|sentinel
|
||||
sentinelMasterName: "example-master" #哨兵模式主节点名称
|
||||
address: 127.0.0.1:6382
|
||||
db: 0
|
||||
pass: "${SERVICE_PASSWORD}"
|
||||
minIdle: 5 #最小空闲连接数
|
||||
maxIdle: 30 #允许闲置的最大连接数
|
||||
maxActive: 5000 #最大活跃连接数
|
||||
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/2m/2d
|
||||
ClientName: "SystemCache"
|
||||
queue:
|
||||
mode: "single" #redis模式,支持:single|cluster|sentinel
|
||||
sentinelMasterName: "example-master" #哨兵模式主节点名称
|
||||
address: 127.0.0.1:6382
|
||||
db: 0
|
||||
pass: "${SERVICE_PASSWORD}"
|
||||
minIdle: 5 #最小空闲连接数
|
||||
maxIdle: 30 #允许闲置的最大连接数
|
||||
maxActive: 5000 #最大活跃连接数
|
||||
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/2m/2d
|
||||
ClientName: "QueueCache"
|
||||
# 路由配置
|
||||
router:
|
||||
# 不需要验证登录的路由地址
|
||||
exceptLogin:
|
||||
- /v3/query/token
|
||||
|
||||
gateway:
|
||||
address: "iotlcmupstreamchan-http-svc"
|
||||
timeout: "10s"
|
||||
@@ -0,0 +1,112 @@
|
||||
# config.yaml 配置文件
|
||||
# @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"
|
||||
version: "1.0"
|
||||
description: "XiuAdmin Server"
|
||||
gfmode: "dev"
|
||||
upload:
|
||||
local:
|
||||
path: "resource/upload"
|
||||
|
||||
# 服务配置
|
||||
server:
|
||||
name: "yzupstreamproxy-http-svc"
|
||||
address: ":8510"
|
||||
# 接口文档
|
||||
openapiPath: "/api.json" # OpenAPI接口文档地址
|
||||
swaggerPath: "/swagger" # 内置SwaggerUI展示地址
|
||||
# 静态服务配置
|
||||
indexFiles: ["index.html","index.htm"] # 自动首页静态文件检索。默认为["index.html", "index.htm"]
|
||||
indexFolder: false # 当访问静态文件目录时,是否展示目录下的文件列表。默认关闭,那么请求将返回403
|
||||
# serverRoot: "resource/public" # 静态文件服务的目录根路径,配置时自动开启静态文件服务。默认关闭
|
||||
# searchPaths: ["/resource/public"] # 提供静态文件服务时额外的文件搜索路径,当根路径找不到时则按照顺序在搜索目录查找。默认关闭
|
||||
fileServerEnabled: true
|
||||
initLoadMemoryDB: false # 是否初始化内存数据库,默认关闭
|
||||
# 文件上传配置
|
||||
maxHeaderBytes: "20KB"
|
||||
clientMaxBodySize: "200MB"
|
||||
|
||||
registry:
|
||||
type: "consul"
|
||||
address: "127.0.0.1:8500"
|
||||
# address: "127.0.0.1:8500"
|
||||
|
||||
# 日志配置
|
||||
logger:
|
||||
path: "/app/logs" # 日志文件路径。默认为空,表示关闭,仅输出到终端
|
||||
file: "{Y-m-d-H}.log" # 日志文件格式。默认为"{Y-m-d}.log"
|
||||
prefix: "" # 日志内容输出前缀。默认为空
|
||||
level: "dev" # 日志输出级别
|
||||
timeFormat: "2006-01-02T15:04:05" # 自定义日志输出的时间格式,使用Golang标准的时间格式配置
|
||||
ctxKeys: [] # 自定义Context上下文变量名称,自动打印Context的变量到日志中。默认为空
|
||||
header: true # 是否打印日志的头信息。默认true
|
||||
stdout: true # 日志是否同时输出到终端。默认true
|
||||
rotateSize: 0 # 按照日志文件大小对文件进行滚动切分。默认为0,表示关闭滚动切分特性
|
||||
rotateExpire: 0 # 按照日志文件时间间隔对文件滚动切分。默认为0,表示关闭滚动切分特性
|
||||
rotateBackupLimit: 0 # 按照切分的文件数量清理切分文件,当滚动切分特性开启时有效。默认为0,表示不备份,切分则删除
|
||||
rotateBackupExpire: 0 # 按照切分的文件有效期清理切分文件,当滚动切分特性开启时有效。默认为0,表示不备份,切分则删除
|
||||
rotateBackupCompress: 0 # 滚动切分文件的压缩比(0-9)。默认为0,表示不压缩
|
||||
rotateCheckInterval: "1h" # 滚动切分的时间检测间隔,一般不需要设置。默认为1小时
|
||||
stdoutColorDisabled: false # 关闭终端的颜色打印。默认开启
|
||||
writerColorEnable: false # 日志文件是否带上颜色。默认false,表示不带颜色
|
||||
|
||||
|
||||
database:
|
||||
logger:
|
||||
path: "/app/logs/sql"
|
||||
level: "all"
|
||||
stdout: true
|
||||
default: # 分组名称,可自定义,默认为default
|
||||
link: "${DB_DSN}"
|
||||
debug: true #开启调试模式
|
||||
charset: "utf8mb4" # (可选)数据库编码(如: utf8mb4/utf8/gbk/gb2312),一般设置为utf8mb4。默认为utf8。
|
||||
dryRun: false #ORM空跑(只读不写)
|
||||
maxIdle: 30 #连接池最大闲置的连接数
|
||||
maxOpen: 100 #连接池最大打开的连接数
|
||||
maxLifetime: 120 #(单位秒)连接对象可重复使用的时间长度
|
||||
memorydb:
|
||||
# link: "sqlite::@file(jieiotmem.db)?journal_mode=WAL"
|
||||
link: "${DB_DSN}"
|
||||
# link: ""
|
||||
debug: true
|
||||
maxIdle: 1
|
||||
maxOpen: 1
|
||||
maxLifetime: 30
|
||||
|
||||
# 缓存配置
|
||||
cache:
|
||||
adapter: "redis" # 缓存适配器,支持:file|redis
|
||||
fileDir: "resource/cache" # 缓存文件目录
|
||||
|
||||
# Redis 配置示例
|
||||
redis:
|
||||
# 单实例配置
|
||||
default:
|
||||
mode: "single" #redis模式,支持:single|cluster|sentinel
|
||||
sentinelMasterName: "example-master" #哨兵模式主节点名称
|
||||
address: 127.0.0.1:6379
|
||||
db: 0
|
||||
pass: "${SERVICE_PASSWORD}"
|
||||
minIdle: 5 #最小空闲连接数
|
||||
maxIdle: 30 #允许闲置的最大连接数
|
||||
maxActive: 5000 #最大活跃连接数
|
||||
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/2m/2d
|
||||
ClientName: "SystemCache"
|
||||
|
||||
# 路由配置
|
||||
# router:
|
||||
# 不需要验证登录的路由地址
|
||||
# exceptLogin:
|
||||
# - /v3/query/token
|
||||
|
||||
# 上游通道服务
|
||||
gateway:
|
||||
# 上游通道服务名称
|
||||
address: "iotlcmupstreamchan-http-svc"
|
||||
# 调用上游通道服务超时时间,默认10(秒)
|
||||
timeout: "10s"
|
||||
@@ -0,0 +1,73 @@
|
||||
module git.5iot.com/iotlcm-public/iotlcm-upstream-proxy
|
||||
|
||||
go 1.25.5
|
||||
|
||||
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/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
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
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
|
||||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||
github.com/hashicorp/consul/api v1.33.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/serf v0.10.1 // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/olekukonko/tablewriter v1.1.0 // indirect
|
||||
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
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.39.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
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
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,402 @@
|
||||
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=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
|
||||
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
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=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
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=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
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=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0 h1:UvqxwinkelKxwdwnKUfdy51/ls4RL7MCeJqAZOVAy0I=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0/go.mod h1:6v7oGBF9wv59WERJIOJxXmLhkUcxwON3tPYW3AZ7wbY=
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.10.0 h1:OyAH7Ls2c9Un7CJiAq7G6eY1jWIICRkN8C5SyM94rnY=
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.10.0/go.mod h1:fwhAMG0qZpeHbbP2JE78rJRfV7eBbu9jXkxTMM1lwyo=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0 h1:N/F9CuDdUZLoM1nVRqrDE/33pDZuhVxpNY4wYdeIaBs=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0/go.mod h1:x6uoJGfZOtirIRQls8xUlYzC6f7T/eULPUa9er368X0=
|
||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.10.3 h1:h2tRpKTlEkBVnpmWdqrF5l6LmzjheDXAwSpR/zruxPM=
|
||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.10.3/go.mod h1:9Dk7HM3fXJxQp34CXWZEeHceJZwrMN1G4xLRVAgcdjs=
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.10.0 h1:yy93PGhz2CE3PpF2JSGa2MXJWd4JNHYC5l5NEFCFRV4=
|
||||
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=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
||||
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
||||
github.com/hashicorp/consul/api v1.33.2 h1:Q6mE0WZsUTJerlnl9TuXzqrtZ0cKdOCsxcZhj5mKbMs=
|
||||
github.com/hashicorp/consul/api v1.33.2/go.mod h1:K3yoL/vnIBcQV/25NeMZVokRvPPERiqp2Udtr4xAfhs=
|
||||
github.com/hashicorp/consul/sdk v0.17.1 h1:LumAh8larSXmXw2wvw/lK5ZALkJ2wK8VRwWMLVV5M5c=
|
||||
github.com/hashicorp/consul/sdk v0.17.1/go.mod h1:EngiixMhmw9T7wApycq6rDRFXXVUwjjf7HuLiGMH/Sw=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
||||
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
|
||||
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
|
||||
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
|
||||
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
|
||||
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
|
||||
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
|
||||
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
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=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=
|
||||
github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
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=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
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=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
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=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
||||
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
|
||||
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
# CLI tool, only in development environment.
|
||||
# https://goframe.org/docs/cli
|
||||
gfcli:
|
||||
gen:
|
||||
dao:
|
||||
link: "${DB_DSN}"
|
||||
tables: "t_sim_card_info, t_sim_channel_templatem, t_sim_channels"
|
||||
descriptionTag: true # 数据表字段注释
|
||||
noModelComment: true
|
||||
jsonCase: "CamelLower" # 生成json字段时,字段名使用驼峰命名
|
||||
gJsonSupport: true
|
||||
group: "default" # 分组 使用代码生成功能时必须填
|
||||
tablesEx: "sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。
|
||||
|
||||
docker:
|
||||
build: "-a amd64 -s linux -p temp -ew"
|
||||
tagPrefixes:
|
||||
- my.image.pub/my-app
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
# Install/Update to the latest CLI tool.
|
||||
.PHONY: cli
|
||||
cli:
|
||||
@set -e; \
|
||||
wget -O gf \
|
||||
https://github.com/gogf/gf/releases/latest/download/gf_$(shell go env GOOS)_$(shell go env GOARCH) && \
|
||||
chmod +x gf && \
|
||||
./gf install -y && \
|
||||
rm ./gf
|
||||
|
||||
|
||||
# Check and install CLI tool.
|
||||
.PHONY: cli.install
|
||||
cli.install:
|
||||
@set -e; \
|
||||
gf -v > /dev/null 2>&1 || if [[ "$?" -ne "0" ]]; then \
|
||||
echo "GoFame CLI is not installed, start proceeding auto installation..."; \
|
||||
make cli; \
|
||||
fi;
|
||||
@@ -0,0 +1,94 @@
|
||||
.DEFAULT_GOAL := build
|
||||
|
||||
# Update GoFrame and its CLI to latest stable version.
|
||||
.PHONY: up
|
||||
up: cli.install
|
||||
@gf up -a
|
||||
|
||||
# Build binary using configuration from hack/config.example.yaml.
|
||||
.PHONY: build
|
||||
build: cli.install
|
||||
@gf build -ew
|
||||
|
||||
# Parse api and generate controller/sdk.
|
||||
.PHONY: ctrl
|
||||
ctrl: cli.install
|
||||
@gf gen ctrl -m
|
||||
|
||||
# Generate Go files for DAO/DO/Entity.
|
||||
.PHONY: dao
|
||||
dao: cli.install
|
||||
@gf gen dao
|
||||
|
||||
# Parse current project go files and generate enums go file.
|
||||
.PHONY: enums
|
||||
enums: cli.install
|
||||
@gf gen enums
|
||||
|
||||
# Generate Go files for Service.
|
||||
.PHONY: service
|
||||
service: cli.install
|
||||
@gf gen service
|
||||
|
||||
|
||||
# Build docker image.
|
||||
.PHONY: image
|
||||
image: cli.install
|
||||
$(eval _TAG = $(shell git rev-parse --short HEAD))
|
||||
ifneq (, $(shell git status --porcelain 2>/dev/null))
|
||||
$(eval _TAG = $(_TAG).dirty)
|
||||
endif
|
||||
$(eval _TAG = $(if ${TAG}, ${TAG}, $(_TAG)))
|
||||
$(eval _PUSH = $(if ${PUSH}, ${PUSH}, ))
|
||||
@gf docker ${_PUSH} -tn $(DOCKER_NAME):${_TAG};
|
||||
|
||||
|
||||
# Build docker image and automatically push to docker repo.
|
||||
.PHONY: image.push
|
||||
image.push: cli.install
|
||||
@make image PUSH=-p;
|
||||
|
||||
|
||||
# Deploy image and yaml to current kubectl environment.
|
||||
.PHONY: deploy
|
||||
deploy: cli.install
|
||||
$(eval _TAG = $(if ${TAG}, ${TAG}, develop))
|
||||
|
||||
@set -e; \
|
||||
mkdir -p $(ROOT_DIR)/temp/kustomize;\
|
||||
cd $(ROOT_DIR)/manifest/deploy/kustomize/overlays/${_ENV};\
|
||||
kustomize build > $(ROOT_DIR)/temp/kustomize.yaml;\
|
||||
kubectl apply -f $(ROOT_DIR)/temp/kustomize.yaml; \
|
||||
if [ $(DEPLOY_NAME) != "" ]; then \
|
||||
kubectl patch -n $(NAMESPACE) deployment/$(DEPLOY_NAME) -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"$(shell date +%s)\"}}}}}"; \
|
||||
fi;
|
||||
|
||||
|
||||
# Parsing protobuf files and generating go files.
|
||||
.PHONY: pb
|
||||
pb: cli.install
|
||||
@gf gen pb
|
||||
|
||||
# Generate protobuf files for database tables.
|
||||
.PHONY: pbentity
|
||||
pbentity: cli.install
|
||||
@gf gen pbentity
|
||||
|
||||
|
||||
export AppName=jieiot_linux
|
||||
export BuildVersion=$(shell git describe --abbrev=0 --tags)
|
||||
export BuildTime=$(shell date +%FT%T%z)
|
||||
export CommitID=$(shell git rev-parse HEAD)
|
||||
export NOWTIME=$(shell date "+%Y%m%d%H%M%S")
|
||||
export HasImages=$(shell docker images | grep docker_iotlcmupstreamproxy:v0 | grep -v docker_iotlcmupstreamproxy:v0.)
|
||||
.PHONY: docker_iotlcmupstreamproxy
|
||||
docker_iotlcmupstreamproxy:
|
||||
if [ -n "${HasImages}" ]; then \
|
||||
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} .
|
||||
# docker save -o docker_iotlcmupstreamproxy.tar docker_iotlcmupstreamproxy:v0
|
||||
|
||||
dockerbuild: docker_iotlcmupstreamproxy
|
||||
echo "docker build success"
|
||||
@@ -0,0 +1,98 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/controller/infopb"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/controller/msgcallpb"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubconsts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
const (
|
||||
ServiceNamePrefix = "iotlcmupstreamproxy"
|
||||
)
|
||||
|
||||
var (
|
||||
gGrpcPort = 8700
|
||||
gAccessIP = "0.0.0.0"
|
||||
)
|
||||
var (
|
||||
Main = gcmd.Command{
|
||||
Name: "main",
|
||||
Usage: "main",
|
||||
Brief: "start http server",
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
s := g.Server()
|
||||
gGrpcPort = gconv.Int(gcmd.GetOptWithEnv("grpcport"))
|
||||
gAccessIP = gconv.String(gcmd.GetOptWithEnv("accessip"))
|
||||
|
||||
if len(gAccessIP) == 0 {
|
||||
gAccessIP = "0.0.0.0"
|
||||
}
|
||||
if gGrpcPort == 0 {
|
||||
gGrpcPort = 8110
|
||||
}
|
||||
nodeName := fmt.Sprintf("%s", ServiceNamePrefix)
|
||||
|
||||
xjpubservice.Info().SetInfoName(xjpubconsts.ServiceTypeAccess, fmt.Sprintf("%s-http-svc", ServiceNamePrefix), "上游运营商渠道服务", "上游运营商渠道服务")
|
||||
xjpubservice.Info().AddInfoData("grpcport", gGrpcPort)
|
||||
xjpubservice.Info().AddInfoData("accessip", gAccessIP)
|
||||
xjpubservice.Info().AddInfoData("nodeName", nodeName)
|
||||
|
||||
xjpubservice.InfoRpc().SetInfoName(xjpubconsts.ServiceTypeAccess, fmt.Sprintf("%s-grpc-svc", ServiceNamePrefix), "上游运营商渠道服务", "上游运营商渠道服务")
|
||||
xjpubservice.InfoRpc().AddInfoData("grpcport", gGrpcPort)
|
||||
xjpubservice.InfoRpc().AddInfoData("accessip", gAccessIP)
|
||||
xjpubservice.InfoRpc().AddInfoData("nodeName", nodeName)
|
||||
bindHTTPRoutes(s)
|
||||
err = service.ChannelConfig().Start(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = service.UpstreamAPI().Start(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
c := grpcx.Server.NewConfig()
|
||||
c.Endpoints = []string{fmt.Sprintf("%s:%d", gAccessIP, gGrpcPort)}
|
||||
c.Options = append(c.Options, []grpc.ServerOption{
|
||||
grpcx.Server.ChainUnary(
|
||||
grpcx.Server.UnaryValidate,
|
||||
),
|
||||
}...)
|
||||
sGRPC := grpcx.Server.New(c)
|
||||
sGRPC.Service(&gsvc.LocalService{
|
||||
Name: fmt.Sprintf("%s-grpc-svc", ServiceNamePrefix),
|
||||
Endpoints: gsvc.Endpoints{gsvc.NewEndpoint(fmt.Sprintf("%s:%d", gAccessIP, gGrpcPort))},
|
||||
Metadata: gsvc.Metadata{
|
||||
gsvc.MDProtocol: "grpc",
|
||||
gsvc.MDInsecure: true,
|
||||
},
|
||||
})
|
||||
infopb.Register(sGRPC)
|
||||
msgcallpb.Register(sGRPC)
|
||||
reflection.Register(sGRPC.Server)
|
||||
g.Log().Infof(ctx, "GRPC Server启动, listenPort:%d", gGrpcPort)
|
||||
sGRPC.Run()
|
||||
g.Log().Infof(ctx, "GRPC Server堵塞运行结束")
|
||||
}()
|
||||
|
||||
s.Run()
|
||||
service.UpstreamAPI().Stop(ctx)
|
||||
service.ChannelConfig().Stop(ctx)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/controller/cardquery"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/controller/channel"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
func bindHTTPRoutes(server *ghttp.Server) {
|
||||
server.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(ghttp.MiddlewareHandlerResponse)
|
||||
group.Bind(
|
||||
cardquery.NewV1(),
|
||||
channel.NewV1(),
|
||||
)
|
||||
group.POST("/internal/app-diagnosis/sim/*any", cardquery.AppDiagnosisQuery)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
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")
|
||||
bindHTTPRoutes(server)
|
||||
if err := server.Start(); err != nil {
|
||||
t.Fatalf("start HTTP server: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := server.Shutdown(); err != nil {
|
||||
t.Errorf("shutdown HTTP server: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
want := map[string]bool{
|
||||
"/internal/channel/refresh": false,
|
||||
"/internal/channel/remove": false,
|
||||
"/internal/app-diagnosis/sim/*any": false,
|
||||
}
|
||||
for _, route := range server.GetRoutes() {
|
||||
if _, ok := want[route.Route]; ok && strings.EqualFold(route.Method, "POST") {
|
||||
want[route.Route] = true
|
||||
}
|
||||
}
|
||||
for route, found := range want {
|
||||
if !found {
|
||||
t.Fatalf("POST %s route was not registered: %+v", route, server.GetRoutes())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package consts
|
||||
|
||||
const (
|
||||
ApiStatusSuccess = 0
|
||||
ApiStatusError = 9999
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package cardquery
|
||||
@@ -0,0 +1,79 @@
|
||||
package cardquery
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"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/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
var appDiagnosisQueryPaths = map[string]bool{
|
||||
"/sim/query/sim-basic-info": true,
|
||||
"/sim/query/sim-status": true,
|
||||
"/sim/query/sim-session": true,
|
||||
"/sim/query/sim-apn-info": true,
|
||||
"/sim/query/sim-imei": true,
|
||||
"/sim/query/sim-device-status": true,
|
||||
"/sim/query/sim-card-bind-status": true,
|
||||
"/sim/query/sim-data-diagnosis": true,
|
||||
"/sim/query/sim-stop-reason": true,
|
||||
"/sim/query/sim-frozen-state": true,
|
||||
"/sim/query/sim-datausage": true,
|
||||
"/sim/query/sim-region-limit-status": true,
|
||||
}
|
||||
|
||||
// AppDiagnosisQuery bypasses the proxy's local card lookup only for verified
|
||||
// internal, read-only diagnosis requests. The existing /sim/* API is untouched.
|
||||
func AppDiagnosisQuery(r *ghttp.Request) {
|
||||
secret := strings.TrimSpace(g.Cfg().MustGet(r.Context(), "appDiagnosis.internalToken").String())
|
||||
provided := r.Header.Get("X-App-Diagnosis-Token")
|
||||
if secret == "" || subtle.ConstantTimeCompare([]byte(secret), []byte(provided)) != 1 {
|
||||
appDiagnosisReject(r, http.StatusForbidden, "内部查询未授权")
|
||||
return
|
||||
}
|
||||
path := strings.TrimPrefix(r.URL.Path, "/internal/app-diagnosis")
|
||||
if !appDiagnosisQueryPaths[path] {
|
||||
appDiagnosisReject(r, http.StatusNotFound, "诊断接口不存在")
|
||||
return
|
||||
}
|
||||
if len(r.GetBody()) > 64*1024 {
|
||||
appDiagnosisReject(r, http.StatusRequestEntityTooLarge, "请求内容过大")
|
||||
return
|
||||
}
|
||||
var input model.SimBaseReqJson
|
||||
if err := json.Unmarshal(r.GetBody(), &input); err != nil || len(input.SimKeys) != 1 || input.SimKeys[0] == nil {
|
||||
appDiagnosisReject(r, http.StatusBadRequest, "诊断卡参数无效")
|
||||
return
|
||||
}
|
||||
key := input.SimKeys[0]
|
||||
key.ChanKey = strings.TrimSpace(key.ChanKey)
|
||||
if key.ChanKey == "" || strings.TrimSpace(key.ICCID) == "" {
|
||||
appDiagnosisReject(r, http.StatusBadRequest, "诊断卡通道或ICCID缺失")
|
||||
return
|
||||
}
|
||||
// Channel credentials and gateway routing are loaded by UpstreamAPI from
|
||||
// this proxy's own configured channel, never from the legacy database.
|
||||
channel, ok := service.UpstreamAPI().GetChan(key.ChanKey)
|
||||
if !ok || channel == nil || channel.Instance == nil {
|
||||
appDiagnosisReject(r, http.StatusNotFound, "诊断通道不可用")
|
||||
return
|
||||
}
|
||||
r.URL.Path = path
|
||||
data, err := service.UpstreamAPI().SimBase(r.Context(), &input)
|
||||
if err != nil {
|
||||
r.SetError(err)
|
||||
return
|
||||
}
|
||||
r.Response.WriteJson(g.Map{"code": 0, "data": data})
|
||||
}
|
||||
|
||||
func appDiagnosisReject(r *ghttp.Request, status int, message string) {
|
||||
r.Response.WriteStatus(status)
|
||||
r.Response.WriteJson(g.Map{"code": status, "message": message})
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cardquery
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
)
|
||||
|
||||
func TestDiagnosisProxyRejectsUntrustedAndInvalidRequests(t *testing.T) {
|
||||
adapter, err := gcfg.NewAdapterContent(`{"appDiagnosis":{"internalToken":"test-token"}}`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
previous := g.Cfg().GetAdapter()
|
||||
g.Cfg().SetAdapter(adapter)
|
||||
t.Cleanup(func() { g.Cfg().SetAdapter(previous) })
|
||||
server := ghttp.GetServer("diagnosis-proxy-auth-test")
|
||||
server.SetAddr("127.0.0.1:0")
|
||||
server.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.POST("/internal/app-diagnosis/sim/*any", AppDiagnosisQuery)
|
||||
})
|
||||
if err := server.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = server.Shutdown() })
|
||||
url := "http://" + server.GetListenedAddress() + "/internal/app-diagnosis"
|
||||
for _, tc := range []struct {
|
||||
path string
|
||||
token string
|
||||
body string
|
||||
status int
|
||||
}{
|
||||
{"/sim/query/sim-basic-info", "", `{"simKeys":[{"iccid":"123","chanKey":"test"}]}`, http.StatusForbidden},
|
||||
{"/sim/restart", "test-token", `{"simKeys":[{"iccid":"123","chanKey":"test"}]}`, http.StatusNotFound},
|
||||
{"/sim/query/sim-basic-info", "test-token", `{"simKeys":[{"iccid":"123"}]}`, http.StatusBadRequest},
|
||||
} {
|
||||
request, err := http.NewRequest(http.MethodPost, url+tc.path, strings.NewReader(tc.body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
request.Header.Set("X-App-Diagnosis-Token", tc.token)
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = response.Body.Close()
|
||||
if response.StatusCode != tc.status {
|
||||
t.Errorf("%s: got %d want %d", tc.path, response.StatusCode, tc.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package cardquery
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/api/cardquery"
|
||||
)
|
||||
|
||||
type ControllerV1 struct{}
|
||||
|
||||
func NewV1() cardquery.ICardqueryV1 {
|
||||
return &ControllerV1{}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// func (c *ControllerV1) SimBase(ctx context.Context, req *v1.SimBaseReq) (res *v1.SimBaseRes, err error) {
|
||||
// g.Log().Debugf(ctx, "SimBase req %+v", req)
|
||||
// r := g.RequestFromCtx(ctx)
|
||||
// if r.Method != "POST" {
|
||||
// return nil, gerror.New("method not allowed")
|
||||
// }
|
||||
// path := r.URL.Path
|
||||
// if path == "" {
|
||||
// return nil, gerror.New("path is required")
|
||||
// }
|
||||
// // 获取渠道KEY
|
||||
// for _, simKey := range req.SimKeys {
|
||||
// if simKey.ChanKey == "" {
|
||||
// simKey.ChanKey = "channel_003"
|
||||
// }
|
||||
// }
|
||||
// // 获取三码信息
|
||||
|
||||
// url := "http://iotlcmupstreamproxy-http-svc" + path
|
||||
// client := g.Client()
|
||||
// client.SetDiscovery(gsvc.GetRegistry())
|
||||
// client.SetTimeout(time.Second * 10)
|
||||
// postData, err := json.Marshal(req)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// resp, err := client.Post(ctx, url, postData)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// body := resp.ReadAllString()
|
||||
// var simBaseRes model.SimBaseResJson
|
||||
// err = json.Unmarshal([]byte(body), &simBaseRes)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return &simBaseRes, nil
|
||||
// }
|
||||
|
||||
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
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package channel
|
||||
|
||||
import "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/api/channel"
|
||||
|
||||
type ControllerV1 struct{}
|
||||
|
||||
func NewV1() channel.IChannelV1 {
|
||||
return &ControllerV1{}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1 "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/api/channel/v1"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Refresh(ctx context.Context, req *v1.RefreshReq) (res *v1.RefreshRes, err error) {
|
||||
if err = service.UpstreamAPI().RefreshChannel(ctx, req.ChanKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.RefreshRes{
|
||||
ChanKey: req.ChanKey,
|
||||
Refreshed: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *ControllerV1) Remove(ctx context.Context, req *v1.RemoveReq) (res *v1.RemoveRes, err error) {
|
||||
if err = service.UpstreamAPI().RemoveChannel(ctx, req.ChanKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.RemoveRes{ChanKey: req.ChanKey, Removed: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package infopb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pb"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
pb.UnimplementedInfoServer
|
||||
}
|
||||
|
||||
func Register(s *grpcx.GrpcServer) {
|
||||
pb.RegisterInfoServer(s.Server, &Controller{})
|
||||
}
|
||||
|
||||
func (*Controller) Info(ctx context.Context, req *pb.InfoReq) (*pb.InfoRes, error) {
|
||||
g.Log().Info(ctx, req)
|
||||
info := xjpubservice.InfoRpc().GetInfo()
|
||||
return &pb.InfoRes{
|
||||
Head: &pb.HeadRes{
|
||||
Code: 0,
|
||||
Message: "success",
|
||||
},
|
||||
Type: info.Type,
|
||||
Name: info.Name,
|
||||
Title: info.Title,
|
||||
Description: info.Description,
|
||||
Version: info.Version,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package msgcallpb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pb"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
pb.UnimplementedMsgCallServer
|
||||
}
|
||||
|
||||
func Register(s *grpcx.GrpcServer) {
|
||||
pb.RegisterMsgCallServer(s.Server, &Controller{})
|
||||
}
|
||||
|
||||
func (c *Controller) OneCall(ctx context.Context, req *pb.MsgReq) (res *pb.MsgRes, err error) {
|
||||
res = &pb.MsgRes{
|
||||
Head: &pb.HeadRes{
|
||||
Code: -1,
|
||||
Message: "service not found",
|
||||
},
|
||||
Service: req.Service,
|
||||
Method: req.Method,
|
||||
}
|
||||
if req.Head != nil {
|
||||
res.Head.RouterId = req.Head.RouterId
|
||||
res.Head.TraceId = req.Head.TraceId
|
||||
}
|
||||
|
||||
info := xjpubservice.InfoRpc().GetInfo()
|
||||
if req.Service != info.Name {
|
||||
g.Log().Errorf(ctx, "OneCall Service not found: service: %s, info: %s", req.Service, info.Name)
|
||||
return res, nil
|
||||
}
|
||||
{
|
||||
g.Log().Errorf(ctx, "OneCall Method not found: method: %s", req.Method)
|
||||
res.Head.Code = -1
|
||||
res.Head.Message = "method not found"
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// TSimCardInfoDao is the data access object for the table t_sim_card_info.
|
||||
type TSimCardInfoDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of the current DAO.
|
||||
columns TSimCardInfoColumns // columns contains all the column names of Table for convenient usage.
|
||||
handlers []gdb.ModelHandler // handlers for customized model modification.
|
||||
}
|
||||
|
||||
// TSimCardInfoColumns defines and stores column names for the table t_sim_card_info.
|
||||
type TSimCardInfoColumns struct {
|
||||
Id string // 主键ID
|
||||
Iccid string // ICCID
|
||||
Msisdn string // MSISDN/卡号
|
||||
Imsi string // IMSI
|
||||
Imei string // IMEI
|
||||
RegionCode string // 归属地
|
||||
DeptId string // 渠道客户ID
|
||||
CurrentPackageCode string // 当前套餐编号
|
||||
PackageStatus string // 套餐状态:0 无套餐,1待生效,2生效中,3已过期
|
||||
AccessType string // 接入方式:ipv4、ipv6、ipv4_ipv6
|
||||
BossCardStatus string // 运营商卡状态 枚举
|
||||
CardType string // 卡类型 枚举
|
||||
BossOpenAt string // 运营商开户日期
|
||||
BossActivateAt string // 运营商激活日期
|
||||
IsBossActivateEnabled string // 是否按运营商激活减去赠送时长方:1是,0否
|
||||
InboundBatchNo string // 入库批次
|
||||
OutboundBatchNo string // 出库批次
|
||||
AllocationBatchNo string // 划拨批次
|
||||
IsFlowPool string // 是否为池卡:1是,0否
|
||||
FlowPoolCode string // 流量池编号
|
||||
FlowPkgBeginAt string // 当前套餐生效时间
|
||||
FlowPkgPresentAt string // 套餐赠送结束时间
|
||||
FlowPkgRealPresentAt string // 实际赠送结束时间
|
||||
FlowPkgEndAt string // 当前套餐预计到期时间
|
||||
DataServiceStatus string // 数据服务状态:1启用、0禁用
|
||||
PackageTotalFlowMb string // 套餐总流量MB
|
||||
UsedFlowMb string // 已用流量MB
|
||||
TrafficCutoffStatus string // 达量断网配置状态:0未配置,1已开启,2已关闭
|
||||
TrafficCutoffThreshold string // 达量断网阈值
|
||||
SmsServiceStatus string // 短信服务状态:1启用、0禁用
|
||||
PackageTotalSms string // 套餐短信总条数
|
||||
UsedSms string // 已用短信条数
|
||||
VoiceServiceStatus string // 语音服务状态:1启用、0禁用
|
||||
PackageTotalVoice string // 套餐语音总分钟数
|
||||
UsedVoice string // 已用语音分钟数
|
||||
RoamServiceStatus string // 国漫服务状态:1启用、0禁用
|
||||
PackageTotalRoamFlowMb string // 套餐国际流量MB
|
||||
UsedRoamFlowMb string // 已用国际流量MB
|
||||
StatusSyncTime string // 状态最后一次同步时间
|
||||
FlowSyncTime string // 流量最后一次同步时间
|
||||
SmsSyncTime string // 短信最后一次同步时间
|
||||
VoiceSyncTime string // 语音最后一次同步时间
|
||||
RoamSyncTime string // 国漫最后一次同步时间
|
||||
ExtraFeeEnabled string // 是否收取附加费:1是,0否
|
||||
ExtraFeeMultiple string // 附加费用倍数
|
||||
ExtraFee string // 附加金额
|
||||
ChanKey string // 通道编号
|
||||
NetModel string // 网络类型:4G、5G、NB-IoT
|
||||
Remark string // 备注
|
||||
TenantId string // 租户ID
|
||||
CreatedDept string // 创建部门
|
||||
CreatedBy string // 创建者
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedBy string // 更新者
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// tSimCardInfoColumns holds the columns for the table t_sim_card_info.
|
||||
var tSimCardInfoColumns = TSimCardInfoColumns{
|
||||
Id: "id",
|
||||
Iccid: "iccid",
|
||||
Msisdn: "msisdn",
|
||||
Imsi: "imsi",
|
||||
Imei: "imei",
|
||||
RegionCode: "region_code",
|
||||
DeptId: "dept_id",
|
||||
CurrentPackageCode: "current_package_code",
|
||||
PackageStatus: "package_status",
|
||||
AccessType: "access_type",
|
||||
BossCardStatus: "boss_card_status",
|
||||
CardType: "card_type",
|
||||
BossOpenAt: "boss_open_at",
|
||||
BossActivateAt: "boss_activate_at",
|
||||
IsBossActivateEnabled: "is_boss_activate_enabled",
|
||||
InboundBatchNo: "inbound_batch_no",
|
||||
OutboundBatchNo: "outbound_batch_no",
|
||||
AllocationBatchNo: "allocation_batch_no",
|
||||
IsFlowPool: "is_flow_pool",
|
||||
FlowPoolCode: "flow_pool_code",
|
||||
FlowPkgBeginAt: "flow_pkg_begin_at",
|
||||
FlowPkgPresentAt: "flow_pkg_present_at",
|
||||
FlowPkgRealPresentAt: "flow_pkg_real_present_at",
|
||||
FlowPkgEndAt: "flow_pkg_end_at",
|
||||
DataServiceStatus: "data_service_status",
|
||||
PackageTotalFlowMb: "package_total_flow_mb",
|
||||
UsedFlowMb: "used_flow_mb",
|
||||
TrafficCutoffStatus: "traffic_cutoff_status",
|
||||
TrafficCutoffThreshold: "traffic_cutoff_threshold",
|
||||
SmsServiceStatus: "sms_service_status",
|
||||
PackageTotalSms: "package_total_sms",
|
||||
UsedSms: "used_sms",
|
||||
VoiceServiceStatus: "voice_service_status",
|
||||
PackageTotalVoice: "package_total_voice",
|
||||
UsedVoice: "used_voice",
|
||||
RoamServiceStatus: "roam_service_status",
|
||||
PackageTotalRoamFlowMb: "package_total_roam_flow_mb",
|
||||
UsedRoamFlowMb: "used_roam_flow_mb",
|
||||
StatusSyncTime: "status_sync_time",
|
||||
FlowSyncTime: "flow_sync_time",
|
||||
SmsSyncTime: "sms_sync_time",
|
||||
VoiceSyncTime: "voice_sync_time",
|
||||
RoamSyncTime: "roam_sync_time",
|
||||
ExtraFeeEnabled: "extra_fee_enabled",
|
||||
ExtraFeeMultiple: "extra_fee_multiple",
|
||||
ExtraFee: "extra_fee",
|
||||
ChanKey: "chan_key",
|
||||
NetModel: "net_model",
|
||||
Remark: "remark",
|
||||
TenantId: "tenant_id",
|
||||
CreatedDept: "created_dept",
|
||||
CreatedBy: "created_by",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedBy: "updated_by",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewTSimCardInfoDao creates and returns a new DAO object for table data access.
|
||||
func NewTSimCardInfoDao(handlers ...gdb.ModelHandler) *TSimCardInfoDao {
|
||||
return &TSimCardInfoDao{
|
||||
group: "default",
|
||||
table: "t_sim_card_info",
|
||||
columns: tSimCardInfoColumns,
|
||||
handlers: handlers,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of the current DAO.
|
||||
func (dao *TSimCardInfoDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of the current DAO.
|
||||
func (dao *TSimCardInfoDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of the current DAO.
|
||||
func (dao *TSimCardInfoDao) Columns() TSimCardInfoColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the database configuration group name of the current DAO.
|
||||
func (dao *TSimCardInfoDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
|
||||
func (dao *TSimCardInfoDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
model := dao.DB().Model(dao.table)
|
||||
for _, handler := range dao.handlers {
|
||||
model = handler(model)
|
||||
}
|
||||
return model.Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rolls back the transaction and returns the error if function f returns a non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note: Do not commit or roll back the transaction in function f,
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *TSimCardInfoDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// TSimChannelTemplateDao is the data access object for the table t_sim_channel_template.
|
||||
type TSimChannelTemplateDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of the current DAO.
|
||||
columns TSimChannelTemplateColumns // columns contains all the column names of Table for convenient usage.
|
||||
handlers []gdb.ModelHandler // handlers for customized model modification.
|
||||
}
|
||||
|
||||
// TSimChannelTemplateColumns defines and stores column names for the table t_sim_channel_template.
|
||||
type TSimChannelTemplateColumns struct {
|
||||
Id string // ID
|
||||
TempKey string // 模板标识
|
||||
TempName string // 模板名称
|
||||
TempModel string // 模板模型
|
||||
TempConfig string // 模板配置
|
||||
TempStatus string // 模板状态(0未启用,1启用)
|
||||
TenantId string // 租户ID
|
||||
CreatedDept string // 创建部门
|
||||
CreatedBy string // 创建者
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedBy string // 更新者
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// tSimChannelTemplateColumns holds the columns for the table t_sim_channel_template.
|
||||
var tSimChannelTemplateColumns = TSimChannelTemplateColumns{
|
||||
Id: "id",
|
||||
TempKey: "temp_key",
|
||||
TempName: "temp_name",
|
||||
TempModel: "temp_model",
|
||||
TempConfig: "temp_config",
|
||||
TempStatus: "temp_status",
|
||||
TenantId: "tenant_id",
|
||||
CreatedDept: "created_dept",
|
||||
CreatedBy: "created_by",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedBy: "updated_by",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewTSimChannelTemplateDao creates and returns a new DAO object for table data access.
|
||||
func NewTSimChannelTemplateDao(handlers ...gdb.ModelHandler) *TSimChannelTemplateDao {
|
||||
return &TSimChannelTemplateDao{
|
||||
group: "default",
|
||||
table: "t_sim_channel_template",
|
||||
columns: tSimChannelTemplateColumns,
|
||||
handlers: handlers,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of the current DAO.
|
||||
func (dao *TSimChannelTemplateDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of the current DAO.
|
||||
func (dao *TSimChannelTemplateDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of the current DAO.
|
||||
func (dao *TSimChannelTemplateDao) Columns() TSimChannelTemplateColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the database configuration group name of the current DAO.
|
||||
func (dao *TSimChannelTemplateDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
|
||||
func (dao *TSimChannelTemplateDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
model := dao.DB().Model(dao.table)
|
||||
for _, handler := range dao.handlers {
|
||||
model = handler(model)
|
||||
}
|
||||
return model.Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rolls back the transaction and returns the error if function f returns a non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note: Do not commit or roll back the transaction in function f,
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *TSimChannelTemplateDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// TSimChannelsDao is the data access object for the table t_sim_channels.
|
||||
type TSimChannelsDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of the current DAO.
|
||||
columns TSimChannelsColumns // columns contains all the column names of Table for convenient usage.
|
||||
handlers []gdb.ModelHandler // handlers for customized model modification.
|
||||
}
|
||||
|
||||
// TSimChannelsColumns defines and stores column names for the table t_sim_channels.
|
||||
type TSimChannelsColumns struct {
|
||||
Id string // ID
|
||||
TempKey string // 模板标识
|
||||
ChanKey string // 通道编号
|
||||
ChanName string // 通道名称
|
||||
ChanConfig string // 通道配置
|
||||
ChanStatus string // 通道状态(0未启用,1启用)
|
||||
ChanAlias string // 通道别名
|
||||
RegionCode string // 通道行政区域代码(省市)
|
||||
AppKey string // 应用标识
|
||||
AppSecret string // 应用密钥
|
||||
AccessToken string // 接口调用凭证
|
||||
AccessTokenCreated string // 凭证申请时间
|
||||
AccessTokenExpire string // 凭证过期时间
|
||||
RefreshToken string // 刷新凭证
|
||||
TenantId string // 租户ID
|
||||
CreatedDept string // 创建部门
|
||||
CreatedBy string // 创建者
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedBy string // 更新者
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// tSimChannelsColumns holds the columns for the table t_sim_channels.
|
||||
var tSimChannelsColumns = TSimChannelsColumns{
|
||||
Id: "id",
|
||||
TempKey: "temp_key",
|
||||
ChanKey: "chan_key",
|
||||
ChanName: "chan_name",
|
||||
ChanConfig: "chan_config",
|
||||
ChanStatus: "chan_status",
|
||||
ChanAlias: "chan_alias",
|
||||
RegionCode: "region_code",
|
||||
AppKey: "app_key",
|
||||
AppSecret: "app_secret",
|
||||
AccessToken: "access_token",
|
||||
AccessTokenCreated: "access_token_created",
|
||||
AccessTokenExpire: "access_token_expire",
|
||||
RefreshToken: "refresh_token",
|
||||
TenantId: "tenant_id",
|
||||
CreatedDept: "created_dept",
|
||||
CreatedBy: "created_by",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedBy: "updated_by",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewTSimChannelsDao creates and returns a new DAO object for table data access.
|
||||
func NewTSimChannelsDao(handlers ...gdb.ModelHandler) *TSimChannelsDao {
|
||||
return &TSimChannelsDao{
|
||||
group: "default",
|
||||
table: "t_sim_channels",
|
||||
columns: tSimChannelsColumns,
|
||||
handlers: handlers,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of the current DAO.
|
||||
func (dao *TSimChannelsDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of the current DAO.
|
||||
func (dao *TSimChannelsDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of the current DAO.
|
||||
func (dao *TSimChannelsDao) Columns() TSimChannelsColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the database configuration group name of the current DAO.
|
||||
func (dao *TSimChannelsDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
|
||||
func (dao *TSimChannelsDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
model := dao.DB().Model(dao.table)
|
||||
for _, handler := range dao.handlers {
|
||||
model = handler(model)
|
||||
}
|
||||
return model.Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rolls back the transaction and returns the error if function f returns a non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note: Do not commit or roll back the transaction in function f,
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *TSimChannelsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/dao/internal"
|
||||
)
|
||||
|
||||
// tSimCardInfoDao is the data access object for the table t_sim_card_info.
|
||||
// You can define custom methods on it to extend its functionality as needed.
|
||||
type tSimCardInfoDao struct {
|
||||
*internal.TSimCardInfoDao
|
||||
}
|
||||
|
||||
var (
|
||||
// TSimCardInfo is a globally accessible object for table t_sim_card_info operations.
|
||||
TSimCardInfo = tSimCardInfoDao{internal.NewTSimCardInfoDao()}
|
||||
)
|
||||
|
||||
// Add your custom methods and functionality below.
|
||||
@@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/dao/internal"
|
||||
)
|
||||
|
||||
// tSimChannelTemplateDao is the data access object for the table t_sim_channel_template.
|
||||
// You can define custom methods on it to extend its functionality as needed.
|
||||
type tSimChannelTemplateDao struct {
|
||||
*internal.TSimChannelTemplateDao
|
||||
}
|
||||
|
||||
var (
|
||||
// TSimChannelTemplate is a globally accessible object for table t_sim_channel_template operations.
|
||||
TSimChannelTemplate = tSimChannelTemplateDao{internal.NewTSimChannelTemplateDao()}
|
||||
)
|
||||
|
||||
// Add your custom methods and functionality below.
|
||||
@@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/dao/internal"
|
||||
)
|
||||
|
||||
// tSimChannelsDao is the data access object for the table t_sim_channels.
|
||||
// You can define custom methods on it to extend its functionality as needed.
|
||||
type tSimChannelsDao struct {
|
||||
*internal.TSimChannelsDao
|
||||
}
|
||||
|
||||
var (
|
||||
// TSimChannels is a globally accessible object for table t_sim_channels operations.
|
||||
TSimChannels = tSimChannelsDao{internal.NewTSimChannelsDao()}
|
||||
)
|
||||
|
||||
// Add your custom methods and functionality below.
|
||||
@@ -0,0 +1,259 @@
|
||||
package channelconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strings"
|
||||
|
||||
"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"
|
||||
|
||||
"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"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// channelConfigRow extends the generated entity without losing SQL NULL values.
|
||||
type channelConfigRow struct {
|
||||
entity.TSimChannels
|
||||
IsNormal *int `json:"isNormal" orm:"is_normal"`
|
||||
}
|
||||
|
||||
type sChannelConfig struct {
|
||||
sync.RWMutex
|
||||
channelCache map[string]*model.SimChannelConfigItemCache
|
||||
loadVersion uint8
|
||||
chgLogMaxId int64
|
||||
running bool
|
||||
}
|
||||
|
||||
func NewChannelConfig() *sChannelConfig {
|
||||
return &sChannelConfig{
|
||||
channelCache: make(map[string]*model.SimChannelConfigItemCache),
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterChannelConfig(NewChannelConfig())
|
||||
}
|
||||
|
||||
func (s *sChannelConfig) Start(ctx context.Context) error {
|
||||
err := s.LoadAllChannelConfig(ctx)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "ChannelConfig Start err %+v", err)
|
||||
return err
|
||||
}
|
||||
s.running = true
|
||||
err = s.Loop(ctx)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "ChannelConfig Start err %+v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sChannelConfig) Stop(ctx context.Context) error {
|
||||
s.running = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sChannelConfig) Loop(ctx context.Context) error {
|
||||
g.Log().Infof(ctx, "ChannelConfig loop begin.")
|
||||
lastLoadAllChannelConfigTime := int64(0)
|
||||
go func() {
|
||||
for s.running {
|
||||
now := time.Now().Unix()
|
||||
loadAllInterval := g.Cfg().MustGet(ctx, "channel.load_all_interval", 2*60*60).Int64()
|
||||
if now-lastLoadAllChannelConfigTime >= loadAllInterval {
|
||||
lastLoadAllChannelConfigTime = now
|
||||
s.LoadAllChannelConfig(ctx)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}()
|
||||
g.Log().Infof(ctx, "ChannelConfig loop background goroutine started.")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sChannelConfig) LoadAllChannelConfig(ctx context.Context) error {
|
||||
s.loadVersion++
|
||||
const warnRowThreshold = 1000
|
||||
|
||||
dbSimChannels := make([]*channelConfigRow, 0)
|
||||
err := dao.TSimChannels.Ctx(ctx).
|
||||
OrderAsc(dao.TSimChannels.Columns().Id).
|
||||
Scan(&dbSimChannels)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
if len(dbSimChannels) >= warnRowThreshold {
|
||||
g.Log().Warningf(ctx, "LoadAllChannelConfig TSimChannels row count %d >= %d, confirm small-table assumption or add pagination",
|
||||
len(dbSimChannels), warnRowThreshold)
|
||||
}
|
||||
|
||||
dbSimChannelTemplates := make([]*entity.TSimChannelTemplate, 0)
|
||||
err = dao.TSimChannelTemplate.Ctx(ctx).
|
||||
OrderAsc(dao.TSimChannelTemplate.Columns().Id).
|
||||
Scan(&dbSimChannelTemplates)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
if len(dbSimChannelTemplates) >= warnRowThreshold {
|
||||
g.Log().Warningf(ctx, "LoadAllChannelConfig TSimChannelTemplate row count %d >= %d, confirm small-table assumption or add pagination",
|
||||
len(dbSimChannelTemplates), warnRowThreshold)
|
||||
}
|
||||
|
||||
templateByKey := make(map[string]*entity.TSimChannelTemplate, len(dbSimChannelTemplates))
|
||||
for _, tpl := range dbSimChannelTemplates {
|
||||
if tpl != nil {
|
||||
templateByKey[tpl.TempKey] = tpl
|
||||
}
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
for _, dbSimChannel := range dbSimChannels {
|
||||
if dbSimChannel == nil {
|
||||
continue
|
||||
}
|
||||
cache := &model.SimChannelConfigItemCache{
|
||||
Channel: &dbSimChannel.TSimChannels,
|
||||
IsNormal: dbSimChannel.IsNormal,
|
||||
Version: s.getChanVersion(ctx, dbSimChannel),
|
||||
}
|
||||
oldChannelCache, _ := s.channelCache[dbSimChannel.ChanKey]
|
||||
if cache.CanCreateInstance() {
|
||||
template, ok := templateByKey[dbSimChannel.TempKey]
|
||||
if !ok {
|
||||
g.Log().Warningf(ctx, "LoadAllChannelConfig no template for tempKey=%s chanKey=%s", dbSimChannel.TempKey, dbSimChannel.ChanKey)
|
||||
continue
|
||||
}
|
||||
cache.Template = template
|
||||
cache.Version += s.getTemplateVersion(ctx, template)
|
||||
}
|
||||
|
||||
if oldChannelCache != nil && oldChannelCache.Version == cache.Version {
|
||||
continue
|
||||
}
|
||||
s.channelCache[dbSimChannel.ChanKey] = cache
|
||||
}
|
||||
s.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sChannelConfig) RefreshChannel(ctx context.Context, chanKey string) error {
|
||||
if chanKey == "" {
|
||||
return gerror.New("chanKey is required")
|
||||
}
|
||||
channel := new(channelConfigRow)
|
||||
if err := dao.TSimChannels.Ctx(ctx).Where(dao.TSimChannels.Columns().ChanKey, chanKey).Scan(channel); err != nil {
|
||||
return err
|
||||
}
|
||||
if channel.ChanKey == "" {
|
||||
return gerror.Newf("channel not found: %s", chanKey)
|
||||
}
|
||||
cache := &model.SimChannelConfigItemCache{
|
||||
Channel: &channel.TSimChannels,
|
||||
IsNormal: channel.IsNormal,
|
||||
Version: s.getChanVersion(ctx, channel),
|
||||
}
|
||||
// Ineligible channels refresh successfully even while their template is incomplete.
|
||||
if cache.CanCreateInstance() {
|
||||
template := new(entity.TSimChannelTemplate)
|
||||
if err := dao.TSimChannelTemplate.Ctx(ctx).Where(dao.TSimChannelTemplate.Columns().TempKey, channel.TempKey).Scan(template); err != nil {
|
||||
return err
|
||||
}
|
||||
if template.TempKey == "" {
|
||||
return gerror.Newf("channel template not found: %s", channel.TempKey)
|
||||
}
|
||||
cache.Template = template
|
||||
cache.Version += s.getTemplateVersion(ctx, template)
|
||||
}
|
||||
s.Lock()
|
||||
s.channelCache[chanKey] = cache
|
||||
s.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveChannel removes a channel configuration cache. Missing keys are
|
||||
// intentionally treated as success so rename retries remain idempotent.
|
||||
func (s *sChannelConfig) RemoveChannel(ctx context.Context, chanKey string) error {
|
||||
chanKey = strings.TrimSpace(chanKey)
|
||||
if chanKey == "" {
|
||||
return gerror.New("chanKey is required")
|
||||
}
|
||||
s.Lock()
|
||||
delete(s.channelCache, chanKey)
|
||||
s.Unlock()
|
||||
g.Log().Infof(ctx, "channel config removed, chanKey: %s", chanKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
// get alarm cache by id
|
||||
func (s *sChannelConfig) GetChannel(chanKey string) (*model.SimChannelConfigItemCache, bool) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
channelCache, ok := s.channelCache[chanKey]
|
||||
return channelCache, ok
|
||||
}
|
||||
|
||||
func (s *sChannelConfig) GetAllChannel(ctx context.Context) ([]*model.SimChannelConfigItemCache, error) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
channels := make([]*model.SimChannelConfigItemCache, 0)
|
||||
for _, channelCache := range s.channelCache {
|
||||
channels = append(channels, channelCache)
|
||||
}
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
func (s *sChannelConfig) getChanVersion(ctx context.Context, channel *channelConfigRow) string {
|
||||
chanKey := channel.ChanKey
|
||||
|
||||
channelNew := &channelConfigRow{
|
||||
IsNormal: channel.IsNormal,
|
||||
TSimChannels: entity.TSimChannels{
|
||||
TempKey: channel.TempKey,
|
||||
ChanKey: channel.ChanKey,
|
||||
ChanName: channel.ChanName,
|
||||
ChanConfig: channel.ChanConfig,
|
||||
ChanStatus: channel.ChanStatus,
|
||||
ChanAlias: channel.ChanAlias,
|
||||
RegionCode: channel.RegionCode,
|
||||
AppKey: channel.AppKey,
|
||||
AppSecret: channel.AppSecret,
|
||||
AccessToken: channel.AccessToken,
|
||||
RefreshToken: channel.RefreshToken,
|
||||
},
|
||||
}
|
||||
chanVersion, err := gmd5.EncryptString(gjson.MustEncodeString(channelNew))
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "sChannelConfig.getChanVersion encrypt error %+v, chanKey %s", err, chanKey)
|
||||
return ""
|
||||
}
|
||||
g.Log().Debugf(ctx, "sChannelConfig.getChanVersion chanVersion=%s chanKey=%s", chanVersion, chanKey)
|
||||
return chanVersion
|
||||
}
|
||||
|
||||
func (s *sChannelConfig) getTemplateVersion(ctx context.Context, template *entity.TSimChannelTemplate) string {
|
||||
templateKey := template.TempKey
|
||||
templateNew := &entity.TSimChannelTemplate{
|
||||
TempKey: template.TempKey,
|
||||
TempName: template.TempName,
|
||||
TempModel: template.TempModel,
|
||||
TempConfig: template.TempConfig,
|
||||
TempStatus: template.TempStatus,
|
||||
}
|
||||
templateVersion, err := gmd5.EncryptString(gjson.MustEncodeString(templateNew))
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "sChannelConfig.getTemplateVersion encrypt error %+v, templateKey %s, templateNew %+v", err, templateKey, templateNew)
|
||||
return ""
|
||||
}
|
||||
g.Log().Debugf(ctx, "sChannelConfig.getTemplateVersion templateVersion=%s templateKey=%s", templateVersion, templateKey)
|
||||
return templateVersion
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package channelconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model/entity"
|
||||
)
|
||||
|
||||
func TestChannelVersionDetectsCredentialChanges(t *testing.T) {
|
||||
normal := 0
|
||||
row := &channelConfigRow{IsNormal: &normal, TSimChannels: entity.TSimChannels{
|
||||
ChanKey: "telecom-test", TempKey: "sim_dx_v1", AppKey: "key", AppSecret: "secret",
|
||||
AccessToken: "token", RefreshToken: "refresh",
|
||||
}}
|
||||
config := NewChannelConfig()
|
||||
before := config.getChanVersion(context.Background(), row)
|
||||
for _, field := range []string{"appKey", "appSecret", "accessToken", "refreshToken", "tempKey"} {
|
||||
t.Run(field, func(t *testing.T) {
|
||||
changed := *row
|
||||
switch field {
|
||||
case "appKey":
|
||||
changed.AppKey = "new-key"
|
||||
case "appSecret":
|
||||
changed.AppSecret = "new-secret"
|
||||
case "accessToken":
|
||||
changed.AccessToken = "new-token"
|
||||
case "refreshToken":
|
||||
changed.RefreshToken = "new-refresh"
|
||||
case "tempKey":
|
||||
changed.TempKey = "sim_dx_v3"
|
||||
}
|
||||
if got := config.getChanVersion(context.Background(), &changed); got == before {
|
||||
t.Fatalf("%s change did not invalidate runtime version", field)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package channelconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type sChannelUpdate struct{}
|
||||
|
||||
func NewChannelUpdate() *sChannelUpdate {
|
||||
return &sChannelUpdate{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterChannelUpdate(NewChannelUpdate())
|
||||
}
|
||||
|
||||
func (s *sChannelUpdate) UpdateAccessToken(ctx context.Context, input *model.UpdateAccessTokenInput) error {
|
||||
_, err := dao.TSimChannels.Ctx(ctx).Where(dao.TSimChannels.Columns().ChanKey, input.ChanKey).Update(g.Map{
|
||||
dao.TSimChannels.Columns().AccessToken: input.AccessToken,
|
||||
dao.TSimChannels.Columns().AccessTokenCreated: input.AccessTokenCreated,
|
||||
dao.TSimChannels.Columns().AccessTokenExpire: input.AccessTokenExpire,
|
||||
dao.TSimChannels.Columns().RefreshToken: input.RefreshToken,
|
||||
})
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package logic
|
||||
|
||||
import (
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/logic/channelconfig"
|
||||
_ "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"
|
||||
)
|
||||
@@ -0,0 +1,193 @@
|
||||
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"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type sSimKeyFill struct {
|
||||
}
|
||||
|
||||
func NewSimKeyFill() *sSimKeyFill {
|
||||
return &sSimKeyFill{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterSimKeyFill(NewSimKeyFill())
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if len(simKeys) == 0 {
|
||||
g.Log().Debug(ctx, "SimKeyFill.batchGetSimKey, simKeys is empty, input %+v", input)
|
||||
return nil, gerror.New("simKeys is empty")
|
||||
}
|
||||
input.SimKeys = simKeys
|
||||
output, err = service.UpstreamAPI().SimBase(ctx, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sSimKeyFill) batchGetSimKey(ctx context.Context, inputs []*model.SimKey) ([]*model.SimKey, error) {
|
||||
queryICCIDKey := "sim:code:iccid:"
|
||||
queryMSISDNKey := "sim:code:msisdn:"
|
||||
queryIMSIKey := "sim:code:imsi:"
|
||||
if len(inputs) == 0 {
|
||||
g.Log().Debugf(ctx, "SimKeyFill.batchGetSimKey, The parameter is empty, inputs %+v", inputs)
|
||||
return nil, gerror.New("参数不能为空")
|
||||
}
|
||||
|
||||
var redisKeys []string
|
||||
var dbKeys []string
|
||||
simKeys := []*model.SimKey{}
|
||||
|
||||
// 设置Redis查询Key
|
||||
for _, in := range inputs {
|
||||
switch {
|
||||
case in.ICCID != "":
|
||||
key := queryICCIDKey + in.ICCID
|
||||
redisKeys = append(redisKeys, key)
|
||||
case in.MSISDN != "":
|
||||
key := queryMSISDNKey + in.MSISDN
|
||||
redisKeys = append(redisKeys, key)
|
||||
case in.IMSI != "":
|
||||
key := queryIMSIKey + in.IMSI
|
||||
redisKeys = append(redisKeys, key)
|
||||
default:
|
||||
g.Log().Debugf(ctx, "SimKeyFill.batchGetSimKey, The parameter is empty, inputs %+v", inputs)
|
||||
return nil, gerror.New("iccid/msisdn/imsi至少一个不能为空")
|
||||
}
|
||||
}
|
||||
|
||||
// 查询Redis数据
|
||||
g.Log().Info(ctx, "SimKeyFill.batchGetSimKey, query redis")
|
||||
vals, err := g.Redis().MGet(ctx, redisKeys...)
|
||||
if err != nil {
|
||||
g.Log().Debug(ctx, "SimKeyFill.batchGetSimKey, query redis error %+v, redisKeys %+v, inputs %+v", err, redisKeys, inputs)
|
||||
} else {
|
||||
// 解析Redis数据
|
||||
for _, key := range redisKeys {
|
||||
simKey := new(model.SimKey)
|
||||
err := vals[key].Struct(&simKey)
|
||||
if err != nil {
|
||||
g.Log().Debug(ctx, "SimKeyFill.batchGetSimKey, unmarshalValue error %+v, key %s, inputs %+v", err, key, inputs)
|
||||
dbKeys = append(dbKeys, key)
|
||||
continue
|
||||
}
|
||||
simKeys = append(simKeys, simKey)
|
||||
}
|
||||
}
|
||||
|
||||
g.Log().Info(ctx, "SimKeyFill.batchGetSimKey, query db")
|
||||
if len(dbKeys) > 0 {
|
||||
// 解析数据库查询Key
|
||||
var dbIccid []string
|
||||
var dbMsisdn []string
|
||||
var dbImsi []string
|
||||
for _, key := range dbKeys {
|
||||
keySplit := strings.Split(key, ":")
|
||||
if len(keySplit) != 4 {
|
||||
g.Log().Debug(ctx, "SimKeyFill.batchGetSimKey, Error in splicing data, key %s, keySplit %v", key, keySplit)
|
||||
continue
|
||||
}
|
||||
switch keySplit[2] {
|
||||
case "iccid":
|
||||
dbIccid = append(dbIccid, keySplit[3])
|
||||
case "msisdn":
|
||||
dbMsisdn = append(dbMsisdn, keySplit[3])
|
||||
case "imsi":
|
||||
dbImsi = append(dbImsi, keySplit[3])
|
||||
}
|
||||
}
|
||||
|
||||
mod := dao.TSimCardInfo.Ctx(ctx)
|
||||
|
||||
if len(dbIccid) > 0 {
|
||||
mod = mod.WhereOrIn(dao.TSimCardInfo.Columns().Iccid, dbIccid)
|
||||
}
|
||||
if len(dbMsisdn) > 0 {
|
||||
mod = mod.WhereOrIn(dao.TSimCardInfo.Columns().Msisdn, dbMsisdn)
|
||||
}
|
||||
if len(dbImsi) > 0 {
|
||||
mod = mod.WhereOrIn(dao.TSimCardInfo.Columns().Imsi, dbImsi)
|
||||
}
|
||||
|
||||
// 查询数据库数据
|
||||
var simInfos []*entity.TSimCardInfo
|
||||
err = mod.Scan(&simInfos)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "SimKeyFill.batchGetSimKey, query db error %+v, dbKeys %+v, inputs %+v", err, dbKeys, inputs)
|
||||
return nil, gerror.New("查询数据库数据失败")
|
||||
}
|
||||
if len(simInfos) == 0 {
|
||||
g.Log().Debug(ctx, "SimKeyFill.batchGetSimKey, simInfos is empty, dbKeys %+v, inputs %+v", dbKeys, inputs)
|
||||
return nil, gerror.New("卡信息不存在")
|
||||
}
|
||||
|
||||
// 整理卡信息
|
||||
simInfoMap := make(map[string]*model.SimKey)
|
||||
for _, SimInfo := range simInfos {
|
||||
simInfoMap[queryICCIDKey+SimInfo.Iccid] = &model.SimKey{
|
||||
ICCID: SimInfo.Iccid,
|
||||
MSISDN: SimInfo.Msisdn,
|
||||
IMSI: SimInfo.Imsi,
|
||||
}
|
||||
simInfoMap[queryMSISDNKey+SimInfo.Msisdn] = &model.SimKey{
|
||||
MSISDN: SimInfo.Msisdn,
|
||||
IMSI: SimInfo.Imsi,
|
||||
ICCID: SimInfo.Iccid,
|
||||
}
|
||||
simInfoMap[queryIMSIKey+SimInfo.Imsi] = &model.SimKey{
|
||||
IMSI: SimInfo.Imsi,
|
||||
ICCID: SimInfo.Iccid,
|
||||
MSISDN: SimInfo.Msisdn,
|
||||
}
|
||||
}
|
||||
|
||||
// 新建一个线程,进行Redis数据存储
|
||||
go s.SetRedis(ctx, simInfoMap)
|
||||
// 解析数据库数据
|
||||
for _, info := range dbKeys {
|
||||
simKeys = append(simKeys, simInfoMap[info])
|
||||
}
|
||||
}
|
||||
return simKeys, nil
|
||||
}
|
||||
|
||||
func (s *sSimKeyFill) SetRedis(ctx context.Context, simInfoMap map[string]*model.SimKey) {
|
||||
for key, simKey := range simInfoMap {
|
||||
_, err := g.Redis().Set(ctx, key, *simKey)
|
||||
if err != nil {
|
||||
g.Log().Debugf(ctx, "SimKeyFill.batchGetSimKey, Set error %+v, key %s, simKey %+v", err, key, simKey)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package upstreamapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
)
|
||||
|
||||
type errCodeTestChannel struct {
|
||||
response model.SimBaseResJson
|
||||
}
|
||||
|
||||
func (f *errCodeTestChannel) SimBase(context.Context, *model.SimBaseReqJson) (model.SimBaseResJson, error) {
|
||||
return f.response, nil
|
||||
}
|
||||
|
||||
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":"8986000000000000002"},"resData":{}}]}`
|
||||
|
||||
var upstream model.SimResponseData[model.SimBaseResJson]
|
||||
if err := json.Unmarshal([]byte(payload), &upstream); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(upstream.Data) != 1 {
|
||||
t.Fatalf("decoded results = %d, want 1", len(upstream.Data))
|
||||
}
|
||||
if upstream.Data[0].ErrCode != "S00004" {
|
||||
t.Fatalf("decoded errCode = %q, want S00004", upstream.Data[0].ErrCode)
|
||||
}
|
||||
|
||||
api := NewUpstreamAPI()
|
||||
api.RegisterChan("channel_003", "test", &model.SimCardChannelCache{
|
||||
Instance: &errCodeTestChannel{response: upstream.Data},
|
||||
})
|
||||
output, err := api.SimBase(context.Background(), &model.SimBaseReqJson{
|
||||
SimKeys: []*model.SimKey{{
|
||||
ChanKey: "channel_003",
|
||||
ICCID: "8986000000000000002",
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(output) != 1 {
|
||||
t.Fatalf("proxied results = %d, want 1", len(output))
|
||||
}
|
||||
if output[0].ErrCode != "S00004" {
|
||||
t.Fatalf("proxied errCode = %q, want S00004", output[0].ErrCode)
|
||||
}
|
||||
|
||||
encoded, err := json.Marshal(output)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(encoded), `"errCode":"S00004"`) {
|
||||
t.Fatalf("serialized response dropped errCode: %s", encoded)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package upstreamapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/logic/channelconfig"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/service"
|
||||
|
||||
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type normalGateTestChannel struct {
|
||||
model.SimCardChannelI
|
||||
}
|
||||
|
||||
type normalGateTestTemplate struct {
|
||||
calls int
|
||||
lastConfig *model.SimChannelConfigItemCache
|
||||
}
|
||||
|
||||
func (f *normalGateTestTemplate) NewTemp(_ context.Context, cfg *model.SimChannelConfigItemCache) model.SimCardChannelI {
|
||||
f.calls++
|
||||
f.lastConfig = cfg
|
||||
return &normalGateTestChannel{}
|
||||
}
|
||||
|
||||
// Exercise real ORM decoding and config versioning as well as both creation paths.
|
||||
// All SQL runs against a temporary SQLite file, never a configured environment DB.
|
||||
func TestUnregisterChanIsIdempotent(t *testing.T) {
|
||||
api := NewUpstreamAPI()
|
||||
api.RegisterChan("missing", "v1", &model.SimCardChannelCache{})
|
||||
api.UnregisterChan("missing")
|
||||
api.UnregisterChan("missing")
|
||||
if _, ok := api.GetChan("missing"); ok {
|
||||
t.Fatal("channel still registered after repeated unregister")
|
||||
}
|
||||
}
|
||||
|
||||
func TestChannelNormalCreationGate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
if err := gdb.SetConfigGroup("default", gdb.ConfigGroup{{
|
||||
Type: "sqlite", Name: filepath.Join(t.TempDir(), "channels.db"),
|
||||
}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
db := g.DB()
|
||||
t.Cleanup(func() { _ = db.Close(ctx) })
|
||||
execSQL := func(query string, args ...any) {
|
||||
t.Helper()
|
||||
if _, err := db.Exec(ctx, query, args...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
execSQL("CREATE TABLE t_sim_channels (id INTEGER PRIMARY KEY, chan_key TEXT, temp_key TEXT, chan_name TEXT, is_normal INTEGER NULL)")
|
||||
execSQL("CREATE TABLE t_sim_channel_template (id INTEGER PRIMARY KEY, temp_key TEXT, temp_model TEXT)")
|
||||
execSQL("INSERT INTO t_sim_channel_template (id, temp_key, temp_model) VALUES (1, 'gate_test', 'direct')")
|
||||
|
||||
oldConfig := service.ChannelConfig()
|
||||
t.Cleanup(func() { service.RegisterChannelConfig(oldConfig) })
|
||||
|
||||
for _, path := range []string{"loop", "refresh"} {
|
||||
t.Run(path, func(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
value any
|
||||
eligible bool
|
||||
}{
|
||||
{"yes_is_zero", 0, true},
|
||||
{"no_is_one", 1, false},
|
||||
{"null", nil, false},
|
||||
{"unexpected", 2, false},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
execSQL("DELETE FROM t_sim_channels")
|
||||
execSQL("INSERT INTO t_sim_channels (id, chan_key, temp_key, is_normal) VALUES (1, 'gate_channel', 'gate_test', ?)", tc.value)
|
||||
config := channelconfig.NewChannelConfig()
|
||||
service.RegisterChannelConfig(config)
|
||||
api := NewUpstreamAPI()
|
||||
factory := &normalGateTestTemplate{}
|
||||
api.RegisterTemp("gate_test", factory)
|
||||
reload := func() {
|
||||
t.Helper()
|
||||
var err error
|
||||
if path == "loop" {
|
||||
err = config.LoadAllChannelConfig(ctx)
|
||||
if err == nil {
|
||||
err = api.loop(ctx)
|
||||
}
|
||||
} else {
|
||||
err = api.RefreshChannel(ctx, "gate_channel")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("refresh must succeed: %v", err)
|
||||
}
|
||||
}
|
||||
reload()
|
||||
cfg, ok := config.GetChannel("gate_channel")
|
||||
if !ok || cfg.CanCreateInstance() != tc.eligible {
|
||||
t.Fatalf("wrong eligibility after ORM scan: %+v", cfg)
|
||||
}
|
||||
if tc.value == nil && cfg.IsNormal != nil {
|
||||
t.Fatalf("SQL NULL decoded as non-nil: %v", *cfg.IsNormal)
|
||||
}
|
||||
if cfg.Channel.ChanKey != "gate_channel" {
|
||||
t.Fatal("embedded channel fields were not scanned")
|
||||
}
|
||||
_, exists := api.GetChan("gate_channel")
|
||||
if exists != tc.eligible || (factory.calls == 1) != tc.eligible {
|
||||
t.Fatalf("instance exists=%v factory calls=%d eligible=%v", exists, factory.calls, tc.eligible)
|
||||
}
|
||||
initialVersion := cfg.Version
|
||||
|
||||
// Only is_normal changes: the configuration cache must notice it.
|
||||
execSQL("UPDATE t_sim_channels SET is_normal=0")
|
||||
reload()
|
||||
current, ok := api.GetChan("gate_channel")
|
||||
if !ok || current.Instance == nil {
|
||||
t.Fatal("eligible channel was not instantiated")
|
||||
}
|
||||
cfg, _ = config.GetChannel("gate_channel")
|
||||
if !tc.eligible && cfg.Version == initialVersion {
|
||||
t.Fatal("changing only is_normal did not change config version")
|
||||
}
|
||||
oldCalls := factory.calls
|
||||
|
||||
// Changing only is_normal must evict the old runtime instance.
|
||||
execSQL("UPDATE t_sim_channels SET is_normal=1")
|
||||
reload()
|
||||
if _, exists := api.GetChan("gate_channel"); exists || factory.calls != oldCalls {
|
||||
t.Fatal("ineligible channel retained or recreated its runtime instance")
|
||||
}
|
||||
cfg, _ = config.GetChannel("gate_channel")
|
||||
if cfg.CanCreateInstance() || cfg.Version == current.Version {
|
||||
t.Fatal("ineligible configuration was not cached with a new version")
|
||||
}
|
||||
// Disabled refreshes remain successful even if the template disappears.
|
||||
execSQL("UPDATE t_sim_channels SET chan_name='changed while disabled', temp_key='missing_template'")
|
||||
reload()
|
||||
reload()
|
||||
if _, exists := api.GetChan("gate_channel"); exists || factory.calls != oldCalls {
|
||||
t.Fatal("repeated ineligible refresh was not an idempotent removal")
|
||||
}
|
||||
|
||||
// A process restart cannot recreate the disabled instance.
|
||||
|
||||
restarted := NewUpstreamAPI()
|
||||
restarted.RegisterTemp("gate_test", factory)
|
||||
if err := restarted.loop(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := restarted.GetChan("gate_channel"); ok {
|
||||
t.Fatal("reload recreated disabled instance")
|
||||
}
|
||||
|
||||
execSQL("UPDATE t_sim_channels SET is_normal=0, temp_key='gate_test'")
|
||||
reload()
|
||||
restored, exists := api.GetChan("gate_channel")
|
||||
if !exists || restored == current || factory.calls != oldCalls+1 ||
|
||||
factory.lastConfig.Channel.ChanName != "changed while disabled" {
|
||||
t.Fatal("restored channel did not rebuild using the latest configuration")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
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"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
var REDIS_KEY = "sim:chan:iccid:"
|
||||
|
||||
type sUpstreamAPI struct {
|
||||
tempMap map[string]model.SimCardTempI
|
||||
chanMap map[string]*model.SimCardChannelCache
|
||||
channelMux sync.Mutex
|
||||
channelOps map[string]*sync.Mutex
|
||||
sync.RWMutex
|
||||
running bool
|
||||
}
|
||||
|
||||
func NewUpstreamAPI() *sUpstreamAPI {
|
||||
return &sUpstreamAPI{
|
||||
chanMap: make(map[string]*model.SimCardChannelCache),
|
||||
tempMap: make(map[string]model.SimCardTempI),
|
||||
channelOps: make(map[string]*sync.Mutex),
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterUpstreamAPI(NewUpstreamAPI())
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) Start(ctx context.Context) error {
|
||||
u.running = true
|
||||
lastReloadTime := int64(0)
|
||||
go func() {
|
||||
for u.running {
|
||||
now := time.Now().Unix()
|
||||
reloadInterval := g.Cfg().MustGet(ctx, "upstreamapi.reload_interval", 60).Int64()
|
||||
if now-lastReloadTime >= reloadInterval {
|
||||
lastReloadTime = now
|
||||
err := u.loop(ctx)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "sUpstreamAPI loop err %+v", err)
|
||||
}
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}()
|
||||
g.Log().Infof(ctx, "sUpstreamAPI Start success")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) Stop(ctx context.Context) error {
|
||||
u.running = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) RefreshChannel(ctx context.Context, chanKey string) error {
|
||||
unlock := u.lockChannel(chanKey)
|
||||
defer unlock()
|
||||
return u.refreshChannelLocked(ctx, chanKey)
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) refreshChannelLocked(ctx context.Context, chanKey string) error {
|
||||
if err := service.ChannelConfig().RefreshChannel(ctx, chanKey); err != nil {
|
||||
return err
|
||||
}
|
||||
channelConf, ok := service.ChannelConfig().GetChannel(chanKey)
|
||||
if !ok || channelConf == nil {
|
||||
return gerror.Newf("channel config not found: %s", chanKey)
|
||||
}
|
||||
if !channelConf.CanCreateInstance() {
|
||||
u.UnregisterChan(chanKey)
|
||||
g.Log().Infof(ctx, "channel instance removed because is_normal is not 0, chanKey: %s", chanKey)
|
||||
return nil
|
||||
}
|
||||
temp, ok := u.GetTemp(channelConf.Template.TempKey)
|
||||
if !ok || temp == nil {
|
||||
return gerror.Newf("channel template not registered: %s", channelConf.Template.TempKey)
|
||||
}
|
||||
instance := temp.NewTemp(ctx, channelConf)
|
||||
if instance == nil {
|
||||
return gerror.Newf("create channel instance failed: %s", chanKey)
|
||||
}
|
||||
u.RegisterChan(chanKey, channelConf.Version, &model.SimCardChannelCache{
|
||||
Instance: instance,
|
||||
Version: channelConf.Version,
|
||||
})
|
||||
g.Log().Infof(ctx, "channel refreshed, chanKey: %s, version: %s", chanKey, channelConf.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveChannel drops the cached configuration and runtime instance for a
|
||||
// channel. Deleting an already absent key is a successful no-op.
|
||||
func (u *sUpstreamAPI) RemoveChannel(ctx context.Context, chanKey string) error {
|
||||
chanKey = strings.TrimSpace(chanKey)
|
||||
if chanKey == "" {
|
||||
return gerror.New("chanKey is required")
|
||||
}
|
||||
unlock := u.lockChannel(chanKey)
|
||||
defer unlock()
|
||||
if err := service.ChannelConfig().RemoveChannel(ctx, chanKey); err != nil {
|
||||
return err
|
||||
}
|
||||
u.UnregisterChan(chanKey)
|
||||
g.Log().Infof(ctx, "channel removed, chanKey: %s", chanKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) loop(ctx context.Context) error {
|
||||
channelConfigs, err := service.ChannelConfig().GetAllChannel(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, snapshot := range channelConfigs {
|
||||
if snapshot == nil || snapshot.Channel == nil {
|
||||
continue
|
||||
}
|
||||
chanKey := snapshot.Channel.ChanKey
|
||||
func() {
|
||||
unlock := u.lockChannel(chanKey)
|
||||
defer unlock()
|
||||
if err := service.ChannelConfig().RefreshChannel(ctx, chanKey); err != nil {
|
||||
g.Log().Errorf(ctx, "reload channel config failed, chanKey: %s, err: %+v", chanKey, err)
|
||||
return
|
||||
}
|
||||
channelConf, ok := service.ChannelConfig().GetChannel(chanKey)
|
||||
if !ok || channelConf == nil {
|
||||
return
|
||||
}
|
||||
if !channelConf.CanCreateInstance() {
|
||||
u.UnregisterChan(chanKey)
|
||||
return
|
||||
}
|
||||
tempKey := channelConf.Template.TempKey
|
||||
channelCache, ok := u.GetChan(chanKey)
|
||||
if ok && channelCache != nil && channelCache.Version == channelConf.Version {
|
||||
return
|
||||
}
|
||||
|
||||
isNew := !ok || channelCache == nil
|
||||
g.Log().Infof(ctx, "Create channel instance begin, chanKey: %s, isNew: %v", chanKey, isNew)
|
||||
temp, ok := u.GetTemp(tempKey)
|
||||
if !ok || temp == nil {
|
||||
g.Log().Errorf(ctx, "Create channel instance failed, Temp not found, tempKey: %s", tempKey)
|
||||
return
|
||||
}
|
||||
instance := temp.NewTemp(ctx, channelConf)
|
||||
if instance == nil {
|
||||
g.Log().Errorf(ctx, "Create channel instance failed, Temp new instance failed, tempKey: %s", tempKey)
|
||||
return
|
||||
}
|
||||
channelCache = &model.SimCardChannelCache{Instance: instance, Version: channelConf.Version}
|
||||
u.RegisterChan(chanKey, channelConf.Version, channelCache)
|
||||
g.Log().Infof(ctx, "Create channel instance success, chanKey: %s, version: %s", chanKey, channelConf.Version)
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) lockChannel(chanKey string) func() {
|
||||
u.channelMux.Lock()
|
||||
lock := u.channelOps[chanKey]
|
||||
if lock == nil {
|
||||
lock = &sync.Mutex{}
|
||||
u.channelOps[chanKey] = lock
|
||||
}
|
||||
u.channelMux.Unlock()
|
||||
lock.Lock()
|
||||
return lock.Unlock
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) UnregisterChan(chanKey string) {
|
||||
u.Lock()
|
||||
delete(u.chanMap, chanKey)
|
||||
u.Unlock()
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) RegisterChan(chanKey string, version string, channel *model.SimCardChannelCache) {
|
||||
u.Lock()
|
||||
defer u.Unlock()
|
||||
u.chanMap[chanKey] = channel
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) removeChan(chanKey string) {
|
||||
u.Lock()
|
||||
defer u.Unlock()
|
||||
delete(u.chanMap, chanKey)
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) RegisterTemp(tempKey string, channel model.SimCardTempI) {
|
||||
u.Lock()
|
||||
defer u.Unlock()
|
||||
u.tempMap[tempKey] = channel
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) GetTemp(tempKey string) (model.SimCardTempI, bool) {
|
||||
u.RLock()
|
||||
defer u.RUnlock()
|
||||
temp, ok := u.tempMap[tempKey]
|
||||
return temp, ok
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) GetChan(chanKey string) (*model.SimCardChannelCache, bool) {
|
||||
u.RLock()
|
||||
defer u.RUnlock()
|
||||
channel, ok := u.chanMap[chanKey]
|
||||
return channel, ok
|
||||
}
|
||||
|
||||
func (u *sUpstreamAPI) packChanKey(ctx context.Context, simKeys []*model.SimKey) (map[string][]*model.SimKey, error) {
|
||||
chanKeyMap := make(map[string][]*model.SimKey)
|
||||
simKeyMap := make(map[string]*model.SimKey, len(simKeys))
|
||||
unknownChanKeyIccids := make([]string, 0)
|
||||
queryRedisIccidKeys := make([]string, 0)
|
||||
queryDbIccids := make([]string, 0)
|
||||
// 检查通道id是都携带
|
||||
for _, simKey := range simKeys {
|
||||
simKeyMap[simKey.ICCID] = simKey
|
||||
if simKey.ChanKey == "" {
|
||||
unknownChanKeyIccids = append(unknownChanKeyIccids, simKey.ICCID)
|
||||
queryRedisIccidKeys = append(queryRedisIccidKeys, REDIS_KEY+simKey.ICCID)
|
||||
} else {
|
||||
chanKeyMap[simKey.ChanKey] = append(chanKeyMap[simKey.ChanKey], simKey)
|
||||
}
|
||||
}
|
||||
if len(unknownChanKeyIccids) == 0 {
|
||||
return chanKeyMap, nil
|
||||
}
|
||||
|
||||
allIccid := make(map[string]bool)
|
||||
for _, iccid := range unknownChanKeyIccids {
|
||||
allIccid[iccid] = false
|
||||
}
|
||||
// TODO: 临时数据库查询,后面添加内存缓存和Redis缓存
|
||||
// 从Redis中查询通道id
|
||||
redisChanKeys, err := g.Redis().MGet(ctx, queryRedisIccidKeys...)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "sUpstreamAPI.packChanKey, query redis error %+v, queryRedisIccidKeys %+v", err, queryRedisIccidKeys)
|
||||
return nil, gerror.New("查询Redis通道id失败")
|
||||
}
|
||||
for iccidKey, chanKey := range redisChanKeys {
|
||||
iccidSplit := strings.Split(iccidKey, ":")
|
||||
if len(iccidSplit) != 4 {
|
||||
g.Log().Debug(ctx, "sUpstreamAPI.packChanKey, iccidKey format error, iccidKey:%s", iccidKey)
|
||||
continue
|
||||
}
|
||||
iccid := iccidSplit[3]
|
||||
chanKeyStr := chanKey.String()
|
||||
if chanKeyStr == "" {
|
||||
// 查询redis为空
|
||||
g.Log().Debug(ctx, "sUpstreamAPI.packChanKey, query redis empty, iccid:%s, simKeys:%v", iccid, simKeys)
|
||||
queryDbIccids = append(queryDbIccids, iccid)
|
||||
continue
|
||||
}
|
||||
allIccid[iccid] = true
|
||||
simKey := simKeyMap[iccid]
|
||||
if simKey == nil {
|
||||
g.Log().Debug(ctx, "sUpstreamAPI.packChanKey, simKey not found, iccid:%s, simKeys:%v", iccid, simKeys)
|
||||
continue
|
||||
}
|
||||
chanKeyMap[chanKeyStr] = append(chanKeyMap[chanKeyStr], &model.SimKey{
|
||||
ChanKey: chanKeyStr,
|
||||
ICCID: iccid,
|
||||
IMSI: simKey.IMSI,
|
||||
MSISDN: simKey.MSISDN,
|
||||
})
|
||||
}
|
||||
if len(queryDbIccids) == 0 {
|
||||
return chanKeyMap, nil
|
||||
}
|
||||
|
||||
var simCardInfos []*entity.TSimCardInfo
|
||||
g.Log().Info(ctx, "sUpstreamAPI.packChanKey, query db, %v", queryDbIccids)
|
||||
err = dao.TSimCardInfo.Ctx(ctx).
|
||||
Fields(dao.TSimCardInfo.Columns().ChanKey, dao.TSimCardInfo.Columns().Iccid).
|
||||
WhereIn(dao.TSimCardInfo.Columns().Iccid, queryDbIccids).Scan(&simCardInfos)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "sUpstreamAPI.packChanKey, query db error %+v, queryDbIccids %+v, simKeys %+v", err, queryDbIccids, simKeys)
|
||||
return nil, gerror.New("查询数据库数据失败")
|
||||
}
|
||||
|
||||
for _, simCardInfo := range simCardInfos {
|
||||
allIccid[simCardInfo.Iccid] = true
|
||||
simKey, _ := simKeyMap[simCardInfo.Iccid]
|
||||
chanKeyMap[simCardInfo.ChanKey] = append(chanKeyMap[simCardInfo.ChanKey], &model.SimKey{
|
||||
ChanKey: simCardInfo.ChanKey,
|
||||
ICCID: simCardInfo.Iccid,
|
||||
IMSI: simKey.IMSI,
|
||||
MSISDN: simKey.MSISDN,
|
||||
})
|
||||
}
|
||||
// 异步写入Redis
|
||||
go u.SetRedis(ctx, simCardInfos)
|
||||
for iccid, found := range allIccid {
|
||||
if !found {
|
||||
chanKeyMap[""] = append(chanKeyMap[""], &model.SimKey{
|
||||
ChanKey: "",
|
||||
ICCID: iccid,
|
||||
})
|
||||
}
|
||||
}
|
||||
return chanKeyMap, nil
|
||||
}
|
||||
|
||||
// 物联网卡
|
||||
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
|
||||
}
|
||||
for chanKey, simKeys := range chanKeyMap {
|
||||
inputMap[chanKey] = &model.SimBaseReqJson{
|
||||
SimKeys: simKeys,
|
||||
ReqData: input.ReqData,
|
||||
}
|
||||
}
|
||||
for chanKey, inputNew := range inputMap {
|
||||
if chanKey == "" {
|
||||
for _, simKey := range inputNew.SimKeys {
|
||||
output = append(output, &model.SimBaseRes[json.RawMessage]{
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusError,
|
||||
Message: "通道未配置",
|
||||
ResData: failureResData,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
channel, ok := u.GetChan(chanKey)
|
||||
if !ok || channel.Instance == nil {
|
||||
for _, simKey := range inputNew.SimKeys {
|
||||
output = append(output, &model.SimBaseRes[json.RawMessage]{
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusError,
|
||||
Message: "通道未实例化",
|
||||
ResData: failureResData,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
out, err := channel.Instance.SimBase(ctx, inputNew)
|
||||
if err != nil {
|
||||
for _, simKey := range inputNew.SimKeys {
|
||||
output = append(output, &model.SimBaseRes[json.RawMessage]{
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusError,
|
||||
Message: err.Error(),
|
||||
ResData: failureResData,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
for _, item := range out {
|
||||
output = append(output, &model.SimBaseRes[json.RawMessage]{
|
||||
SimKey: item.SimKey,
|
||||
Code: item.Code,
|
||||
Message: item.Message,
|
||||
ErrCode: item.ErrCode,
|
||||
ResData: item.ResData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// 异步写入redis
|
||||
func (u *sUpstreamAPI) SetRedis(ctx context.Context, simCardInfos []*entity.TSimCardInfo) {
|
||||
for _, simCardInfo := range simCardInfos {
|
||||
_, err := g.Redis().Set(ctx, REDIS_KEY+simCardInfo.Iccid, simCardInfo.ChanKey)
|
||||
if err != nil {
|
||||
g.Log().Debugf(ctx, "sUpstreamAPI.SetRedis, Set Redis error %+v, key %s, simCardInfo %+v", err, REDIS_KEY+simCardInfo.Iccid, simCardInfo)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package upstreamimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestApikaProxyTemplateRegistration(t *testing.T) {
|
||||
template, ok := service.UpstreamAPI().GetTemp("sim_onelink_kedang_v1")
|
||||
if !ok || template == nil {
|
||||
t.Fatal("apika proxy template not registered")
|
||||
}
|
||||
config := &model.SimChannelConfigItemCache{
|
||||
Template: &entity.TSimChannelTemplate{TempKey: "sim_onelink_kedang_v1"},
|
||||
Channel: &entity.TSimChannels{ChanKey: "apika-test"},
|
||||
}
|
||||
if instance := template.NewTemp(context.Background(), config); instance == nil {
|
||||
t.Fatal("apika proxy template failed to instantiate")
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package dx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config 网关鉴权与请求配置
|
||||
type Config struct {
|
||||
BaseURL string // 默认 https://cmp-api.ctwing.cn:20164
|
||||
AppKey string
|
||||
AppSecret string
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// Client API 客户端
|
||||
type Client struct {
|
||||
baseURL string
|
||||
appKey string
|
||||
appSecret string
|
||||
http *http.Client
|
||||
}
|
||||
|
||||
// New 创建客户端
|
||||
func NewClient(cfg Config) *Client {
|
||||
base := cfg.BaseURL
|
||||
if base == "" {
|
||||
base = DefaultBaseURL
|
||||
}
|
||||
timeout := cfg.Timeout
|
||||
if timeout == 0 {
|
||||
timeout = 10 * time.Second
|
||||
}
|
||||
return &Client{
|
||||
baseURL: strings.TrimSuffix(base, "/"),
|
||||
appKey: cfg.AppKey,
|
||||
appSecret: cfg.AppSecret,
|
||||
http: &http.Client{
|
||||
Timeout: timeout,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DoGetRequest 通用GET请求(自动处理签名)
|
||||
// endpoint: API路径,如 "/api/v1/openbill/queryTraffic"
|
||||
// params: 查询参数,需调用方自行构建
|
||||
func (c *Client) DoGetRequest(ctx context.Context, endpoint string, params url.Values) ([]byte, error) {
|
||||
req, err := c.doGetRequest(ctx, endpoint, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.doRequest(req)
|
||||
}
|
||||
|
||||
// doGetRequest 封装通用的 GET 请求构建逻辑
|
||||
func (c *Client) doGetRequest(ctx context.Context, endpoint string, params url.Values) (*http.Request, error) {
|
||||
queryString := params.Encode()
|
||||
timestamp := GetTimestampGMT()
|
||||
signStr, err := BuildSign(queryString, "", c.appSecret, timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqURL := c.baseURL + endpoint + "?" + queryString
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("AppKey", c.appKey)
|
||||
req.Header.Set("Sign", signStr)
|
||||
req.Header.Set("Timestamp", timestamp)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// doRequest 执行HTTP请求
|
||||
func (c *Client) doRequest(req *http.Request) ([]byte, error) {
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("http status %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package dx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultBaseURL 电信API基础地址
|
||||
DefaultBaseURL = "https://cmp-api.ctwing.cn:20164"
|
||||
)
|
||||
|
||||
// GetTimestampGMT 返回 GMT 时区的 yyyyMMddHHmmss 格式时间戳
|
||||
func GetTimestampGMT() string {
|
||||
return time.Now().UTC().Format("20060102150405")
|
||||
}
|
||||
|
||||
// OrderParams 将 URL params 按 key 字典序排序
|
||||
// 输入如 "b=1&c=2&a=1",输出 "a=1&b=1&c=2"
|
||||
func OrderParams(params string) (string, error) {
|
||||
if params == "" {
|
||||
return "", nil
|
||||
}
|
||||
kvs := strings.Split(params, "&")
|
||||
m := make(map[string]string, len(kvs))
|
||||
for _, kv := range kvs {
|
||||
idx := strings.Index(kv, "=")
|
||||
if idx < 0 {
|
||||
continue
|
||||
}
|
||||
m[kv[:idx]] = kv[idx+1:]
|
||||
}
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
var parts []string
|
||||
for _, k := range keys {
|
||||
parts = append(parts, k+"="+m[k])
|
||||
}
|
||||
return strings.Join(parts, "&"), nil
|
||||
}
|
||||
|
||||
// SignMD5 对 reqStr 做 MD5 加密,返回小写十六进制字符串
|
||||
func SignMD5(reqStr string) string {
|
||||
h := md5.Sum([]byte(reqStr))
|
||||
return strings.ToLower(hex.EncodeToString(h[:]))
|
||||
}
|
||||
|
||||
// BuildSign 构造签名:params 排序后拼接 params+body+secretKey+timestamp 再 MD5
|
||||
// 注意:与参考项目一致,对 MD5 结果再做一次 hex 编码
|
||||
func BuildSign(params, body, secretKey, timestamp string) (string, error) {
|
||||
ordered, err := OrderParams(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
reqStr := ordered + body + secretKey + timestamp
|
||||
md5Str := SignMD5(reqStr)
|
||||
// 对 MD5 结果再做一次 hex 编码(与参考项目一致)
|
||||
hexStr := hex.EncodeToString([]byte(md5Str))
|
||||
return hexStr, nil
|
||||
}
|
||||
|
||||
// BuildSignWithDebug 构造签名并输出调试信息
|
||||
func BuildSignWithDebug(ctx context.Context, params, body, secretKey, timestamp, appKey string) (string, error) {
|
||||
ordered, err := OrderParams(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
reqStr := ordered + body + secretKey + timestamp
|
||||
|
||||
maskedSecret := secretKey
|
||||
|
||||
g.Log().Debugf(ctx, "[签名调试] AppKey: %s", appKey)
|
||||
g.Log().Debugf(ctx, "[签名调试] SecretKey: %s", maskedSecret)
|
||||
g.Log().Debugf(ctx, "[签名调试] Timestamp: %s", timestamp)
|
||||
g.Log().Debugf(ctx, "[签名调试] 排序后参数: %s", ordered)
|
||||
g.Log().Debugf(ctx, "[签名调试] Body: '%s'", body)
|
||||
g.Log().Debugf(ctx, "[签名调试] 签名原串: %s%s[SecretKey]%s", ordered, body, timestamp)
|
||||
|
||||
md5Str := SignMD5(reqStr)
|
||||
g.Log().Debugf(ctx, "[签名调试] MD5结果: %s", md5Str)
|
||||
|
||||
// 对 MD5 结果再做一次 hex 编码
|
||||
hexStr := hex.EncodeToString([]byte(md5Str))
|
||||
g.Log().Debugf(ctx, "[签名调试] 最终签名(hex编码后): %s", hexStr)
|
||||
|
||||
return hexStr, nil
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package upstreamimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"fmt"
|
||||
"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()
|
||||
var output struct {
|
||||
Code *int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data model.SimBaseResJson `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &output); err != nil {
|
||||
return nil, gerror.Wrap(err, "解析网关响应失败")
|
||||
}
|
||||
if response.StatusCode < 200 || response.StatusCode >= 300 || output.Code == nil || *output.Code != 0 {
|
||||
message := strings.TrimSpace(output.Message)
|
||||
if message == "" {
|
||||
message = fmt.Sprintf("网关响应无效,HTTP状态码:%d", response.StatusCode)
|
||||
}
|
||||
return nil, gerror.New(message)
|
||||
}
|
||||
return output.Data, nil
|
||||
}
|
||||
@@ -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("响应头预算不一致")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package upstreamimpl_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestMingqianProxyTemplate(t *testing.T) {
|
||||
template, ok := service.UpstreamAPI().GetTemp("sim_mingqian_v3")
|
||||
if !ok || template == nil {
|
||||
t.Fatal("mingqian proxy template missing")
|
||||
}
|
||||
instance := template.NewTemp(context.Background(), &model.SimChannelConfigItemCache{Template: &entity.TSimChannelTemplate{TempKey: "sim_mingqian_v3"}, Channel: &entity.TSimChannels{ChanKey: "mingqian-test"}})
|
||||
if instance == nil {
|
||||
t.Fatal("mingqian proxy instance missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMingqianProxyPreservesFlowFields(t *testing.T) {
|
||||
const response = `{"code":0,"data":[{"code":0,"message":"","simKey":{"chanKey":"mingqian-test","iccid":"A"},"resData":{"dataUsage":1,"packageFlow":{"totalFlow":10240,"dataUsage":8192,"remainingFlow":2048}}},{"code":0,"message":"package flow unavailable","simKey":{"chanKey":"mingqian-test","iccid":"B"},"resData":{"dataUsage":2,"packageFlowError":"mingqian: business code 500"}},{"code":1,"message":"monthly usage unavailable","simKey":{"chanKey":"mingqian-test","iccid":"C"},"resData":{"dataUsage":0,"packageFlow":{"totalFlow":10,"dataUsage":8,"remainingFlow":2}}}]}`
|
||||
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
if request.Method != http.MethodPost || request.URL.Path != "/sim/query/sim-datausage" {
|
||||
t.Errorf("wrong gateway route: %s %s", request.Method, request.URL.Path)
|
||||
}
|
||||
var input model.SimBaseReqJson
|
||||
if err := request.ParseForm(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := json.Unmarshal([]byte(request.Form.Get("simKeys")), &input.SimKeys); err != nil || len(input.SimKeys) != 3 || input.SimKeys[0].ICCID != "A" {
|
||||
t.Errorf("request changed: %+v %v", input, err)
|
||||
}
|
||||
writer.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprint(writer, response)
|
||||
}))
|
||||
t.Cleanup(server.Close)
|
||||
config, err := gcfg.NewAdapterContent(fmt.Sprintf(`{"gateway":{"address":%q,"timeout":"1s"}}`, strings.TrimPrefix(server.URL, "http://")))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
original := g.Cfg().GetAdapter()
|
||||
g.Cfg().SetAdapter(config)
|
||||
t.Cleanup(func() { g.Cfg().SetAdapter(original) })
|
||||
template, ok := service.UpstreamAPI().GetTemp("sim_mingqian_v3")
|
||||
if !ok {
|
||||
t.Fatal("missing Mingqian registration")
|
||||
}
|
||||
instance := template.NewTemp(context.Background(), &model.SimChannelConfigItemCache{Template: &entity.TSimChannelTemplate{TempKey: "sim_mingqian_v3"}, Channel: &entity.TSimChannels{ChanKey: "mingqian-test"}})
|
||||
request := &ghttp.Request{Request: httptest.NewRequest(http.MethodPost, "/sim/query/sim-datausage", nil)}
|
||||
output, err := instance.SimBase(request.Context(), &model.SimBaseReqJson{
|
||||
SimKeys: []*model.SimKey{{ChanKey: "mingqian-test", ICCID: "A"}, {ChanKey: "mingqian-test", ICCID: "B"}, {ChanKey: "mingqian-test", ICCID: "C"}},
|
||||
ReqData: json.RawMessage(`{}`),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var expected model.SimResponseData[model.SimBaseResJson]
|
||||
if err := json.Unmarshal([]byte(response), &expected); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(output, expected.Data) {
|
||||
t.Fatalf("proxy dropped package fields or changed failure status: %+v", output)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package upstreamimpl_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
_ "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"
|
||||
)
|
||||
|
||||
func TestMobilePublicProxyTemplateRegistration(t *testing.T) {
|
||||
for _, templateKey := range []string{
|
||||
"sim_onelink_daliuliang_v1",
|
||||
"sim__daliuliang_v1",
|
||||
"sim_onelink_mobile_public_v1",
|
||||
} {
|
||||
t.Run(templateKey, func(t *testing.T) {
|
||||
template, ok := service.UpstreamAPI().GetTemp(templateKey)
|
||||
if !ok || template == nil {
|
||||
t.Fatal("mobile public proxy template not registered")
|
||||
}
|
||||
config := &model.SimChannelConfigItemCache{
|
||||
Template: &entity.TSimChannelTemplate{TempKey: templateKey},
|
||||
Channel: &entity.TSimChannels{ChanKey: "daliuliang-test"},
|
||||
}
|
||||
if instance := template.NewTemp(context.Background(), config); instance == nil {
|
||||
t.Fatal("mobile public proxy failed to instantiate")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
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"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
// XML命名空间正则
|
||||
var xmlNamespaceRegex = regexp.MustCompile(`xmlns[^=]*="[^"]*"\s*|:web:`)
|
||||
|
||||
type sSimDX struct {
|
||||
channelConfig *model.SimChannelConfigItemCache
|
||||
client *dx.Client
|
||||
}
|
||||
|
||||
func NewSimDX() *sSimDX {
|
||||
return &sSimDX{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
s := NewSimDX()
|
||||
service.UpstreamAPI().RegisterTemp("sim_dx_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_dx_v3", s)
|
||||
service.RegisterSimDX(s)
|
||||
}
|
||||
|
||||
func (s *sSimDX) NewTemp(ctx context.Context, channelConfig *model.SimChannelConfigItemCache) model.SimCardChannelI {
|
||||
client := dx.NewClient(dx.Config{
|
||||
BaseURL: dx.DefaultBaseURL,
|
||||
AppKey: channelConfig.Channel.AppKey,
|
||||
AppSecret: channelConfig.Channel.AppSecret,
|
||||
})
|
||||
return &sSimDX{
|
||||
channelConfig: channelConfig,
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sSimDX) getUpstreamUrl(ctx context.Context, serviceUrl string) (string, error) {
|
||||
address, err := g.Cfg().Get(ctx, "gateway.address")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("http://%s%s", address, serviceUrl), nil
|
||||
// return fmt.Sprintf("http://%s%s", "127.0.0.1:8110", serviceUrl), nil
|
||||
|
||||
}
|
||||
|
||||
func (s *sSimDX) getUpstreamTimeout(ctx context.Context) time.Duration {
|
||||
timeout, _ := g.Cfg().Get(ctx, "gateway.timeout")
|
||||
if timeout == nil {
|
||||
return 10 * time.Second
|
||||
}
|
||||
if d := timeout.Duration(); d > 0 {
|
||||
return d
|
||||
}
|
||||
if seconds := timeout.Int(); seconds > 0 {
|
||||
return time.Duration(seconds) * time.Second
|
||||
}
|
||||
return 10 * time.Second
|
||||
}
|
||||
|
||||
func (s *sSimDX) SimBase(ctx context.Context, input *model.SimBaseReqJson) (model.SimBaseResJson, error) {
|
||||
r := g.RequestFromCtx(ctx)
|
||||
if r.Method != "POST" {
|
||||
return nil, gerror.New("method not allowed")
|
||||
}
|
||||
path := r.URL.Path
|
||||
if path == "" {
|
||||
return nil, gerror.New("path is required")
|
||||
}
|
||||
url, err := s.getUpstreamUrl(ctx, path)
|
||||
if err != nil {
|
||||
g.Log().Debugf(ctx, "SimBase getUpstreamUrl error %+v, ", err)
|
||||
return nil, err
|
||||
}
|
||||
client := g.Client()
|
||||
client.SetDiscovery(gsvc.GetRegistry())
|
||||
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)
|
||||
return nil, err
|
||||
}
|
||||
return readGatewayResponse(resp)
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package upstreamimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"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"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
const (
|
||||
gUrlBase = "https://api.iot.10086.cn/v5/"
|
||||
)
|
||||
|
||||
type sSimYD struct {
|
||||
channelConfig *model.SimChannelConfigItemCache
|
||||
seqId atomic.Int64
|
||||
tokenFlight singleflight.Group
|
||||
}
|
||||
|
||||
func NewSimYD() *sSimYD {
|
||||
return &sSimYD{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
s := NewSimYD()
|
||||
service.UpstreamAPI().RegisterTemp("sim_yd_v5", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_yd_mock_v5", s)
|
||||
// These channel implementations live in the upstream gateway. The proxy
|
||||
// forwards their API calls through the same generic gateway route, so any
|
||||
// template registered in iotlcm-upstream-chan must be registered here too:
|
||||
// channel refresh fails with "channel template not registered" otherwise.
|
||||
// sSimYD has no template-specific logic, so an alias per template suffices.
|
||||
service.UpstreamAPI().RegisterTemp("sim_sdtywl_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_tengyu_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_xuzhou_mobile_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_lelian_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_qianxun_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_henan_xinjing_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_henan_xinjing_direct_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_zibo_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_tibiot_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_qianxun_v3", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_yunda_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_mingqian_v3", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_daihe_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_daihe_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_daliuliang_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim__daliuliang_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_mobile_public_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_kedang_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("lanshang_8003", s)
|
||||
service.UpstreamAPI().RegisterTemp("lanshang_8000", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_yunze_v1", s)
|
||||
// 江苏倍信(jsbxkj)共享 Token。协议实现在 chan 的 beixin_token_provider.go;
|
||||
// proxy 只负责把业务 API 转发到 gateway,与腾宇/澜数同一形态。
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_beixin_v1", s)
|
||||
service.UpstreamAPI().RegisterTemp("sim_onelink_lanshu_v1", s)
|
||||
service.RegisterSimYD(s)
|
||||
}
|
||||
|
||||
func (s *sSimYD) NewTemp(ctx context.Context, channelConfig *model.SimChannelConfigItemCache) model.SimCardChannelI {
|
||||
return &sSimYD{
|
||||
channelConfig: channelConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sSimYD) getUpstreamUrl(ctx context.Context, serviceUrl string) string {
|
||||
address, _ := g.Cfg().Get(ctx, "gateway.address")
|
||||
return fmt.Sprintf("http://%s%s", address, serviceUrl)
|
||||
// return fmt.Sprintf("http://%s%s", "127.0.0.1:8110", serviceUrl)
|
||||
}
|
||||
|
||||
func (s *sSimYD) getUpstreamTimeout(ctx context.Context) time.Duration {
|
||||
timeout, _ := g.Cfg().Get(ctx, "gateway.timeout")
|
||||
if timeout == nil {
|
||||
return 10 * time.Second
|
||||
}
|
||||
if d := timeout.Duration(); d > 0 {
|
||||
return d
|
||||
}
|
||||
if seconds := timeout.Int(); seconds > 0 {
|
||||
return time.Duration(seconds) * time.Second
|
||||
}
|
||||
return 10 * time.Second
|
||||
}
|
||||
|
||||
func (s *sSimYD) SimBase(ctx context.Context, input *model.SimBaseReqJson) (model.SimBaseResJson, error) {
|
||||
r := g.RequestFromCtx(ctx)
|
||||
if r.Method != "POST" {
|
||||
g.Log().Errorf(ctx, "SimYD.SimBase, method not allowed, method %s, input %+v", r.Method, input)
|
||||
return nil, gerror.New("方法调用错误")
|
||||
}
|
||||
path := r.URL.Path
|
||||
if path == "" {
|
||||
g.Log().Errorf(ctx, "SimYD.SimBase, path is required, input %+v", input)
|
||||
return nil, gerror.New("路径不能为空")
|
||||
}
|
||||
url := s.getUpstreamUrl(ctx, path)
|
||||
g.Log().Debugf(ctx, "SimYD.SimBase, url %s", url)
|
||||
client := g.Client()
|
||||
client.SetDiscovery(gsvc.GetRegistry())
|
||||
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.Wrap(err, "请求通道失败")
|
||||
}
|
||||
return readGatewayResponse(resp)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package upstreamimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// chanTemplateKeys lists every template iotlcm-upstream-chan registers in its
|
||||
// own upstreamimpl init() functions. Source of truth:
|
||||
//
|
||||
// iotlcm-upstream-chan/internal/logic/upstreamimpl/sim_onelink_shared.go:18-29 (shared token family)
|
||||
// iotlcm-upstream-chan/internal/logic/upstreamimpl/sim_daihe.go:17
|
||||
// iotlcm-upstream-chan/internal/logic/upstreamimpl/sim_henan_xinjing_direct.go:18
|
||||
// iotlcm-upstream-chan/internal/logic/upstreamimpl/sim_qianxun.go:25
|
||||
// iotlcm-upstream-chan/internal/logic/upstreamimpl/sim_yunda.go:19
|
||||
// iotlcm-upstream-chan/internal/logic/upstreamimpl/sim_recharge.go:19
|
||||
// iotlcm-upstream-chan/internal/logic/upstreamimpl/sim_yd.go (sim_yd_v5)
|
||||
// iotlcm-upstream-chan/internal/logic/upstreamimpl/sim_yd_mock.go:21
|
||||
// iotlcm-upstream-chan/internal/service/mingqian/adapter.go:16
|
||||
//
|
||||
// Keep this list in sync when a template is added on the chan side: a template
|
||||
// missing here is exactly the failure mode where channel refresh returns
|
||||
// "channel template not registered".
|
||||
var chanTemplateKeys = []string{
|
||||
// 共享 Token 族
|
||||
"sim_onelink_tengyu_v1",
|
||||
"sim_onelink_xuzhou_mobile_v1",
|
||||
"sim_onelink_lelian_v1",
|
||||
"sim_onelink_qianxun_v1",
|
||||
"sim_onelink_henan_xinjing_v1",
|
||||
"sim_onelink_daihe_v1",
|
||||
"sim_onelink_daliuliang_v1",
|
||||
"sim__daliuliang_v1",
|
||||
"sim_onelink_mobile_public_v1",
|
||||
"sim_onelink_kedang_v1",
|
||||
"sim_onelink_yunze_v1",
|
||||
"sim_onelink_lanshu_v1",
|
||||
"sim_onelink_beixin_v1",
|
||||
// 非共享 Token 族
|
||||
"sim_yd_v5",
|
||||
"sim_yd_mock_v5",
|
||||
"sim_sdtywl_v1",
|
||||
"sim_daihe_v1",
|
||||
"sim_henan_xinjing_direct_v1",
|
||||
"sim_qianxun_v3",
|
||||
"sim_yunda_v1",
|
||||
"sim_mingqian_v3",
|
||||
"sim_tibiot_v1",
|
||||
"sim_dx_v1",
|
||||
"sim_dx_v3",
|
||||
}
|
||||
|
||||
// TestUpstreamTemplateParity guards the proxy/gateway template registration
|
||||
// contract: the proxy only forwards to the gateway, so every template the
|
||||
// gateway registers must also be registered here or RefreshChannel fails before
|
||||
// any request is made.
|
||||
func TestUpstreamTemplateParity(t *testing.T) {
|
||||
for _, tempKey := range chanTemplateKeys {
|
||||
tempKey := tempKey
|
||||
t.Run(tempKey, func(t *testing.T) {
|
||||
temp, ok := service.UpstreamAPI().GetTemp(tempKey)
|
||||
if !ok || temp == nil {
|
||||
t.Fatalf("template not registered in proxy: %s", tempKey)
|
||||
}
|
||||
config := &model.SimChannelConfigItemCache{
|
||||
Template: &entity.TSimChannelTemplate{TempKey: tempKey},
|
||||
Channel: &entity.TSimChannels{ChanKey: "parity-test"},
|
||||
}
|
||||
if instance := temp.NewTemp(context.Background(), config); instance == nil {
|
||||
t.Fatalf("template failed to instantiate: %s", tempKey)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TApi is the golang structure of table t_api for DAO operations like Where/Data.
|
||||
type TApi struct {
|
||||
g.Meta `orm:"table:t_api, do:true"`
|
||||
Id any // ID
|
||||
AppKey any // APPKey
|
||||
AppSecret any // APPSecret
|
||||
RateLimitPeriod any // 限流周期(秒,0:不限流)
|
||||
RateLimitCount any // 限流次数
|
||||
DeptId any // 所属机构
|
||||
TenantId any // 租户ID
|
||||
CreatedDept any // 创建部门
|
||||
CreatedBy any // 创建者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedBy any // 更新者
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TCustomer is the golang structure of table t_customer for DAO operations like Where/Data.
|
||||
type TCustomer struct {
|
||||
g.Meta `orm:"table:t_customer, do:true"`
|
||||
Id any // ID
|
||||
CKey any // 客户编号
|
||||
CType any // 客户类型(0:企业,1:个人)
|
||||
CName any // 客户名称
|
||||
CShortName any // 客户简称
|
||||
ContactUserName any // 联系人
|
||||
ContactPhone any // 联系电话
|
||||
LicenseNumber any // 统一社会信用代码
|
||||
RegionCode any // 行政区域代码
|
||||
Address any // 地址
|
||||
DepositAmount any // 预存金额
|
||||
CreditAmountTotal any // 已授信额度
|
||||
CreditAmountUsed any // 已使用授信额度
|
||||
DeptId any // 所属机构
|
||||
TenantId any // 租户ID
|
||||
CreatedDept any // 创建部门
|
||||
CreatedBy any // 创建者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedBy any // 更新者
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimAgentPackage is the golang structure of table t_sim_agent_package for DAO operations like Where/Data.
|
||||
type TSimAgentPackage struct {
|
||||
g.Meta `orm:"table:t_sim_agent_package, do:true"`
|
||||
Id any // ID
|
||||
PackageKey any // 套餐分类编码
|
||||
PackageName any // 套餐分类名称
|
||||
ParentPackageKey any // 上级套餐分类编码
|
||||
PackageStatus any // 是否启用(0:未启用,1启用)
|
||||
BillingMethod any // 计费方式(0:月,1:季,2:年)
|
||||
ChannelPrice any // 渠道价格
|
||||
MonthlyFee any // 月租费
|
||||
PackageDataMb any // 套餐流量(MB)
|
||||
PackageDataGb any // 套餐流量(GB)
|
||||
ValidityPeriod any // 有效期
|
||||
Description any // 描述信息
|
||||
OrderNum any // 排序
|
||||
TenantId any // 租户ID
|
||||
CreatedDept any // 创建部门
|
||||
CreatedBy any // 创建者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedBy any // 更新者
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimAgentPacket is the golang structure of table t_sim_agent_packet for DAO operations like Where/Data.
|
||||
type TSimAgentPacket struct {
|
||||
g.Meta `orm:"table:t_sim_agent_packet, do:true"`
|
||||
Id any // ID
|
||||
PackageKey any // 套餐分类编码
|
||||
PacketKey any // 套餐编码
|
||||
PacketName any // 套餐名称
|
||||
ValidityPeriod any // 套餐有效期(月份)
|
||||
PacketStatus any // 是否启用(0:未启用,1启用)
|
||||
DiscountPercent any // 折扣率(百分比)
|
||||
Description any // 描述信息
|
||||
TenantId any // 租户ID
|
||||
CreatedDept any // 创建部门
|
||||
CreatedBy any // 创建者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedBy any // 更新者
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimCardInfo is the golang structure of table t_sim_card_info for DAO operations like Where/Data.
|
||||
type TSimCardInfo struct {
|
||||
g.Meta `orm:"table:t_sim_card_info, do:true"`
|
||||
Id any // ID
|
||||
Msisdn any // SIM号码
|
||||
Iccid any // SIM卡号
|
||||
Imsi any // SIM识别码
|
||||
Imei any // IMEI
|
||||
OpenDate *gtime.Time // 开卡日期(运营商)
|
||||
ActivateDate *gtime.Time // 激活时间(运营商)
|
||||
AllocationBatch any // 划拨批次
|
||||
AllocationDate *gtime.Time // 划拨日期
|
||||
ChanKey any // 通道编号
|
||||
IsPool any // 是否流量池(0:否,1:是)
|
||||
PoolKey any // 流量池编号
|
||||
BatchKey any // 入库批次
|
||||
BatchDate *gtime.Time // 入库日期
|
||||
PackageKey any // 套餐分类编码
|
||||
CurrPacketKey any // 当前套餐编码
|
||||
AllowPacketChange any // 是否允许更改套餐(0:否 1:是)
|
||||
CardStatus any // 卡状态
|
||||
ValidityPeriod any // 有效期(月份)
|
||||
ExpiryDate *gtime.Time // 套餐到期日期
|
||||
UpstreamExpiryDate *gtime.Time // 上游到期时间(运营商)
|
||||
IpType any // IP版本(人工录入)
|
||||
NetModel any // 网络模式(人工录入)
|
||||
RegionCode any // 行政区域代码(省市)
|
||||
HasOffNet any // 是否开启达量断网
|
||||
OffNetQuota any // 达量断网阈值(MB)
|
||||
OffNetExpiryDate *gtime.Time // 达量断网过期时间
|
||||
AgentShowField any // 客户展示字段设置
|
||||
AgentShowValue any // 客户展示字段数据
|
||||
HasTestPeriod any // 是否有测试期(0:无,1:有)
|
||||
TestPeriod any // 测试期(天)
|
||||
TestPeriodExpiryDate *gtime.Time // 测试期过期日期
|
||||
HasSilentPeriod any // 是否有沉默期(0:无,1:有)
|
||||
SilentPeriod any // 沉默期(月)
|
||||
SilentPeriodExpiryDate *gtime.Time // 沉默期过期日期
|
||||
HasAdditional any // 是否有附加费用(0:无 1:有)
|
||||
AdditionalMultiplier any // 附加费用倍数
|
||||
AdditionalAmount any // 附加金额
|
||||
DataService any // 数据服务(0:关闭 1:开启)
|
||||
DataTotalAmount any // 套餐流量(MB)
|
||||
DataUseAmount any // 已用流量(MB)
|
||||
SmsService any // 短信服务(0:关闭 1:开启)
|
||||
SmsTotalAmount any // 套餐短信数量
|
||||
SmsUseAmount any // 已用短信数量
|
||||
VoiceService any // 语音服务(0:关闭 1:开启)
|
||||
VoiceTotalAmount any // 套餐通话分钟数
|
||||
VoiceUseAmount any // 已用通话分钟数
|
||||
IntlRoamingService any // 国际漫游服务(0:关闭 1:开启)
|
||||
IntlRoamingTotalAmount any // 套餐国际漫游流量(MB)
|
||||
IntlRoamingUseAmount any // 已用国际漫游流量(MB)
|
||||
Description any // 描述信息
|
||||
DeptId any // 所属机构
|
||||
TenantId any // 租户ID
|
||||
CreatedDept any // 创建部门
|
||||
CreatedBy any // 创建者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedBy any // 更新者
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimChannelTemplate is the golang structure of table t_sim_channel_template for DAO operations like Where/Data.
|
||||
type TSimChannelTemplate struct {
|
||||
g.Meta `orm:"table:t_sim_channel_template, do:true"`
|
||||
Id any // ID
|
||||
TempKey any // 模板标识
|
||||
TempName any // 模板名称
|
||||
TempModel any // 模板模型
|
||||
TempConfig any // 模板配置
|
||||
TempStatus any // 模板状态(0未启用,1启用)
|
||||
TenantId any // 租户ID
|
||||
CreatedDept any // 创建部门
|
||||
CreatedBy any // 创建者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedBy any // 更新者
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimChannels is the golang structure of table t_sim_channels for DAO operations like Where/Data.
|
||||
type TSimChannels struct {
|
||||
g.Meta `orm:"table:t_sim_channels, do:true"`
|
||||
Id any // ID
|
||||
TempKey any // 模板标识
|
||||
ChanKey any // 通道编号
|
||||
ChanName any // 通道名称
|
||||
ChanConfig any // 通道配置
|
||||
ChanStatus any // 通道状态(0未启用,1启用)
|
||||
ChanAlias any // 通道别名
|
||||
RegionCode any // 通道行政区域代码(省市)
|
||||
AppKey any // 应用标识
|
||||
AppSecret any // 应用密钥
|
||||
AccessToken any // 接口调用凭证
|
||||
AccessTokenCreated *gtime.Time // 凭证申请时间
|
||||
AccessTokenExpire *gtime.Time // 凭证过期时间
|
||||
RefreshToken any // 刷新凭证
|
||||
TenantId any // 租户ID
|
||||
CreatedDept any // 创建部门
|
||||
CreatedBy any // 创建者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedBy any // 更新者
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TApi is the golang structure for table t_api.
|
||||
type TApi struct {
|
||||
Id int64 `json:"id" orm:"id" description:"ID"`
|
||||
AppKey string `json:"appKey" orm:"app_key" description:"APPKey"`
|
||||
AppSecret string `json:"appSecret" orm:"app_secret" description:"APPSecret"`
|
||||
RateLimitPeriod int `json:"rateLimitPeriod" orm:"rate_limit_period" description:"限流周期(秒,0:不限流)"`
|
||||
RateLimitCount int `json:"rateLimitCount" orm:"rate_limit_count" description:"限流次数"`
|
||||
DeptId int64 `json:"deptId" orm:"dept_id" description:"所属机构"`
|
||||
TenantId string `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
CreatedDept int64 `json:"createdDept" orm:"created_dept" description:"创建部门"`
|
||||
CreatedBy int64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TCustomer is the golang structure for table t_customer.
|
||||
type TCustomer struct {
|
||||
Id int64 `json:"id" orm:"id" description:"ID"`
|
||||
CKey string `json:"cKey" orm:"c_key" description:"客户编号"`
|
||||
CType int `json:"cType" orm:"c_type" description:"客户类型(0:企业,1:个人)"`
|
||||
CName string `json:"cName" orm:"c_name" description:"客户名称"`
|
||||
CShortName string `json:"cShortName" orm:"c_short_name" description:"客户简称"`
|
||||
ContactUserName string `json:"contactUserName" orm:"contact_user_name" description:"联系人"`
|
||||
ContactPhone string `json:"contactPhone" orm:"contact_phone" description:"联系电话"`
|
||||
LicenseNumber string `json:"licenseNumber" orm:"license_number" description:"统一社会信用代码"`
|
||||
RegionCode string `json:"regionCode" orm:"region_code" description:"行政区域代码"`
|
||||
Address string `json:"address" orm:"address" description:"地址"`
|
||||
DepositAmount float64 `json:"depositAmount" orm:"deposit_amount" description:"预存金额"`
|
||||
CreditAmountTotal float64 `json:"creditAmountTotal" orm:"credit_amount_total" description:"已授信额度"`
|
||||
CreditAmountUsed float64 `json:"creditAmountUsed" orm:"credit_amount_used" description:"已使用授信额度"`
|
||||
DeptId int64 `json:"deptId" orm:"dept_id" description:"所属机构"`
|
||||
TenantId string `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
CreatedDept int64 `json:"createdDept" orm:"created_dept" description:"创建部门"`
|
||||
CreatedBy int64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimAgentPackage is the golang structure for table t_sim_agent_package.
|
||||
type TSimAgentPackage struct {
|
||||
Id int64 `json:"id" orm:"id" description:"ID"`
|
||||
PackageKey string `json:"packageKey" orm:"package_key" description:"套餐分类编码"`
|
||||
PackageName string `json:"packageName" orm:"package_name" description:"套餐分类名称"`
|
||||
ParentPackageKey string `json:"parentPackageKey" orm:"parent_package_key" description:"上级套餐分类编码"`
|
||||
PackageStatus int `json:"packageStatus" orm:"package_status" description:"是否启用(0:未启用,1启用)"`
|
||||
BillingMethod int `json:"billingMethod" orm:"billing_method" description:"计费方式(0:月,1:季,2:年)"`
|
||||
ChannelPrice float64 `json:"channelPrice" orm:"channel_price" description:"渠道价格"`
|
||||
MonthlyFee float64 `json:"monthlyFee" orm:"monthly_fee" description:"月租费"`
|
||||
PackageDataMb float64 `json:"packageDataMb" orm:"package_data_mb" description:"套餐流量(MB)"`
|
||||
PackageDataGb float64 `json:"packageDataGb" orm:"package_data_gb" description:"套餐流量(GB)"`
|
||||
ValidityPeriod string `json:"validityPeriod" orm:"validity_period" description:"有效期"`
|
||||
Description string `json:"description" orm:"description" description:"描述信息"`
|
||||
OrderNum int `json:"orderNum" orm:"order_num" description:"排序"`
|
||||
TenantId string `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
CreatedDept int64 `json:"createdDept" orm:"created_dept" description:"创建部门"`
|
||||
CreatedBy int64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimAgentPacket is the golang structure for table t_sim_agent_packet.
|
||||
type TSimAgentPacket struct {
|
||||
Id int64 `json:"id" orm:"id" description:"ID"`
|
||||
PackageKey string `json:"packageKey" orm:"package_key" description:"套餐分类编码"`
|
||||
PacketKey string `json:"packetKey" orm:"packet_key" description:"套餐编码"`
|
||||
PacketName string `json:"packetName" orm:"packet_name" description:"套餐名称"`
|
||||
ValidityPeriod int `json:"validityPeriod" orm:"validity_period" description:"套餐有效期(月份)"`
|
||||
PacketStatus int `json:"packetStatus" orm:"packet_status" description:"是否启用(0:未启用,1启用)"`
|
||||
DiscountPercent int `json:"discountPercent" orm:"discount_percent" description:"折扣率(百分比)"`
|
||||
Description string `json:"description" orm:"description" description:"描述信息"`
|
||||
TenantId string `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
CreatedDept int64 `json:"createdDept" orm:"created_dept" description:"创建部门"`
|
||||
CreatedBy int64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimCardInfo is the golang structure for table t_sim_card_info.
|
||||
type TSimCardInfo struct {
|
||||
Id int64 `json:"id" orm:"id" description:"ID"`
|
||||
Msisdn string `json:"msisdn" orm:"msisdn" description:"SIM号码"`
|
||||
Iccid string `json:"iccid" orm:"iccid" description:"SIM卡号"`
|
||||
Imsi string `json:"imsi" orm:"imsi" description:"SIM识别码"`
|
||||
Imei string `json:"imei" orm:"imei" description:"IMEI"`
|
||||
OpenDate *gtime.Time `json:"openDate" orm:"open_date" description:"开卡日期(运营商)"`
|
||||
ActivateDate *gtime.Time `json:"activateDate" orm:"activate_date" description:"激活时间(运营商)"`
|
||||
AllocationBatch string `json:"allocationBatch" orm:"allocation_batch" description:"划拨批次"`
|
||||
AllocationDate *gtime.Time `json:"allocationDate" orm:"allocation_date" description:"划拨日期"`
|
||||
ChanKey string `json:"chanKey" orm:"chan_key" description:"通道编号"`
|
||||
IsPool int `json:"isPool" orm:"is_pool" description:"是否流量池(0:否,1:是)"`
|
||||
PoolKey string `json:"poolKey" orm:"pool_key" description:"流量池编号"`
|
||||
BatchKey string `json:"batchKey" orm:"batch_key" description:"入库批次"`
|
||||
BatchDate *gtime.Time `json:"batchDate" orm:"batch_date" description:"入库日期"`
|
||||
PackageKey string `json:"packageKey" orm:"package_key" description:"套餐分类编码"`
|
||||
CurrPacketKey string `json:"currPacketKey" orm:"curr_packet_key" description:"当前套餐编码"`
|
||||
AllowPacketChange int `json:"allowPacketChange" orm:"allow_packet_change" description:"是否允许更改套餐(0:否 1:是)"`
|
||||
CardStatus int `json:"cardStatus" orm:"card_status" description:"卡状态"`
|
||||
ValidityPeriod int `json:"validityPeriod" orm:"validity_period" description:"有效期(月份)"`
|
||||
ExpiryDate *gtime.Time `json:"expiryDate" orm:"expiry_date" description:"套餐到期日期"`
|
||||
UpstreamExpiryDate *gtime.Time `json:"upstreamExpiryDate" orm:"upstream_expiry_date" description:"上游到期时间(运营商)"`
|
||||
IpType string `json:"ipType" orm:"ip_type" description:"IP版本(人工录入)"`
|
||||
NetModel string `json:"netModel" orm:"net_model" description:"网络模式(人工录入)"`
|
||||
RegionCode string `json:"regionCode" orm:"region_code" description:"行政区域代码(省市)"`
|
||||
HasOffNet int `json:"hasOffNet" orm:"has_off_net" description:"是否开启达量断网"`
|
||||
OffNetQuota float64 `json:"offNetQuota" orm:"off_net_quota" description:"达量断网阈值(MB)"`
|
||||
OffNetExpiryDate *gtime.Time `json:"offNetExpiryDate" orm:"off_net_expiry_date" description:"达量断网过期时间"`
|
||||
AgentShowField string `json:"agentShowField" orm:"agent_show_field" description:"客户展示字段设置"`
|
||||
AgentShowValue string `json:"agentShowValue" orm:"agent_show_value" description:"客户展示字段数据"`
|
||||
HasTestPeriod int `json:"hasTestPeriod" orm:"has_test_period" description:"是否有测试期(0:无,1:有)"`
|
||||
TestPeriod int `json:"testPeriod" orm:"test_period" description:"测试期(天)"`
|
||||
TestPeriodExpiryDate *gtime.Time `json:"testPeriodExpiryDate" orm:"test_period_expiry_date" description:"测试期过期日期"`
|
||||
HasSilentPeriod int `json:"hasSilentPeriod" orm:"has_silent_period" description:"是否有沉默期(0:无,1:有)"`
|
||||
SilentPeriod int `json:"silentPeriod" orm:"silent_period" description:"沉默期(月)"`
|
||||
SilentPeriodExpiryDate *gtime.Time `json:"silentPeriodExpiryDate" orm:"silent_period_expiry_date" description:"沉默期过期日期"`
|
||||
HasAdditional int `json:"hasAdditional" orm:"has_additional" description:"是否有附加费用(0:无 1:有)"`
|
||||
AdditionalMultiplier float64 `json:"additionalMultiplier" orm:"additional_multiplier" description:"附加费用倍数"`
|
||||
AdditionalAmount float64 `json:"additionalAmount" orm:"additional_amount" description:"附加金额"`
|
||||
DataService int `json:"dataService" orm:"data_service" description:"数据服务(0:关闭 1:开启)"`
|
||||
DataTotalAmount float64 `json:"dataTotalAmount" orm:"data_total_amount" description:"套餐流量(MB)"`
|
||||
DataUseAmount float64 `json:"dataUseAmount" orm:"data_use_amount" description:"已用流量(MB)"`
|
||||
SmsService int `json:"smsService" orm:"sms_service" description:"短信服务(0:关闭 1:开启)"`
|
||||
SmsTotalAmount float64 `json:"smsTotalAmount" orm:"sms_total_amount" description:"套餐短信数量"`
|
||||
SmsUseAmount float64 `json:"smsUseAmount" orm:"sms_use_amount" description:"已用短信数量"`
|
||||
VoiceService int `json:"voiceService" orm:"voice_service" description:"语音服务(0:关闭 1:开启)"`
|
||||
VoiceTotalAmount float64 `json:"voiceTotalAmount" orm:"voice_total_amount" description:"套餐通话分钟数"`
|
||||
VoiceUseAmount float64 `json:"voiceUseAmount" orm:"voice_use_amount" description:"已用通话分钟数"`
|
||||
IntlRoamingService int `json:"intlRoamingService" orm:"intl_roaming_service" description:"国际漫游服务(0:关闭 1:开启)"`
|
||||
IntlRoamingTotalAmount float64 `json:"intlRoamingTotalAmount" orm:"intl_roaming_total_amount" description:"套餐国际漫游流量(MB)"`
|
||||
IntlRoamingUseAmount float64 `json:"intlRoamingUseAmount" orm:"intl_roaming_use_amount" description:"已用国际漫游流量(MB)"`
|
||||
Description string `json:"description" orm:"description" description:"描述信息"`
|
||||
DeptId int64 `json:"deptId" orm:"dept_id" description:"所属机构"`
|
||||
TenantId string `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
CreatedDept int64 `json:"createdDept" orm:"created_dept" description:"创建部门"`
|
||||
CreatedBy int64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimChannelTemplate is the golang structure for table t_sim_channel_template.
|
||||
type TSimChannelTemplate struct {
|
||||
Id int64 `json:"id" orm:"id" description:"ID"`
|
||||
TempKey string `json:"tempKey" orm:"temp_key" description:"模板标识"`
|
||||
TempName string `json:"tempName" orm:"temp_name" description:"模板名称"`
|
||||
TempModel string `json:"tempModel" orm:"temp_model" description:"模板模型"`
|
||||
TempConfig string `json:"tempConfig" orm:"temp_config" description:"模板配置"`
|
||||
TempStatus int `json:"tempStatus" orm:"temp_status" description:"模板状态(0未启用,1启用)"`
|
||||
TenantId string `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
CreatedDept int64 `json:"createdDept" orm:"created_dept" description:"创建部门"`
|
||||
CreatedBy int64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TSimChannels is the golang structure for table t_sim_channels.
|
||||
type TSimChannels struct {
|
||||
Id int64 `json:"id" orm:"id" description:"ID"`
|
||||
TempKey string `json:"tempKey" orm:"temp_key" description:"模板标识"`
|
||||
ChanKey string `json:"chanKey" orm:"chan_key" description:"通道编号"`
|
||||
ChanName string `json:"chanName" orm:"chan_name" description:"通道名称"`
|
||||
ChanConfig string `json:"chanConfig" orm:"chan_config" description:"通道配置"`
|
||||
ChanStatus int `json:"chanStatus" orm:"chan_status" description:"通道状态(0未启用,1启用)"`
|
||||
ChanAlias string `json:"chanAlias" orm:"chan_alias" description:"通道别名"`
|
||||
RegionCode string `json:"regionCode" orm:"region_code" description:"通道行政区域代码(省市)"`
|
||||
AppKey string `json:"appKey" orm:"app_key" description:"应用标识"`
|
||||
AppSecret string `json:"appSecret" orm:"app_secret" description:"应用密钥"`
|
||||
AccessToken string `json:"accessToken" orm:"access_token" description:"接口调用凭证"`
|
||||
AccessTokenCreated *gtime.Time `json:"accessTokenCreated" orm:"access_token_created" description:"凭证申请时间"`
|
||||
AccessTokenExpire *gtime.Time `json:"accessTokenExpire" orm:"access_token_expire" description:"凭证过期时间"`
|
||||
RefreshToken string `json:"refreshToken" orm:"refresh_token" description:"刷新凭证"`
|
||||
TenantId string `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
CreatedDept int64 `json:"createdDept" orm:"created_dept" description:"创建部门"`
|
||||
CreatedBy int64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type SimChannelConfigItemCache struct {
|
||||
Template *entity.TSimChannelTemplate
|
||||
Channel *entity.TSimChannels
|
||||
IsNormal *int // global_yes_or_no: 0=yes, 1=no; NULL is not eligible.
|
||||
Version string
|
||||
}
|
||||
|
||||
// CanCreateInstance determines whether a channel may have a runtime instance.
|
||||
func (c *SimChannelConfigItemCache) CanCreateInstance() bool {
|
||||
return c != nil && c.Channel != nil && c.IsNormal != nil && *c.IsNormal == 0
|
||||
}
|
||||
|
||||
type SimCardTempI interface {
|
||||
NewTemp(ctx context.Context, channelConfig *SimChannelConfigItemCache) SimCardChannelI
|
||||
}
|
||||
|
||||
// 接口定义
|
||||
type SimCardChannelI interface {
|
||||
SimBase(ctx context.Context, input *SimBaseReqJson) (SimBaseResJson, error)
|
||||
}
|
||||
|
||||
type SimCardChannelCache struct {
|
||||
Instance SimCardChannelI
|
||||
Version string
|
||||
}
|
||||
|
||||
type UpdateAccessTokenInput struct {
|
||||
ChanKey string
|
||||
AccessToken string
|
||||
AccessTokenCreated *gtime.Time
|
||||
AccessTokenExpire *gtime.Time
|
||||
RefreshToken string
|
||||
RefreshTokenExpire *gtime.Time
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package model
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// 物联网卡标识
|
||||
type SimKey struct {
|
||||
ChanKey string `json:"chanKey" dc:"通道标识"`
|
||||
ICCID string `json:"iccid" dc:"联网卡集成电路卡识别码20位"`
|
||||
IMSI string `json:"imsi" dc:"国际移动用户识别码"`
|
||||
MSISDN string `json:"msisdn" dc:"移动用户识别码"`
|
||||
}
|
||||
|
||||
// 物联网卡基础请求参数
|
||||
type SimBaseReq[T any] struct {
|
||||
SimKeys []*SimKey `json:"simKeys" dc:"SIM卡标识列表"`
|
||||
ReqData T `json:"reqData" dc:"请求数据"`
|
||||
}
|
||||
|
||||
// 响应数据参数
|
||||
type SimResponseData[T any] struct {
|
||||
Code int `json:"code" dc:"状态码"`
|
||||
Message string `json:"message" dc:"消息"`
|
||||
Data T `json:"data" dc:"数据"`
|
||||
}
|
||||
|
||||
// 物联网卡基础响应参数
|
||||
type SimBaseRes[T any] struct {
|
||||
Code int `json:"code" dc:"状态码"`
|
||||
Message string `json:"message" dc:"消息"`
|
||||
ErrCode string `json:"errCode" dc:"运营商原始错误码"`
|
||||
SimKey *SimKey `json:"simKey" dc:"SIM卡标识"`
|
||||
ResData T `json:"resData" dc:"响应数据"`
|
||||
}
|
||||
|
||||
type SimBaseReqJson = SimBaseReq[json.RawMessage]
|
||||
type SimBaseResJson = []*SimBaseRes[json.RawMessage]
|
||||
@@ -0,0 +1 @@
|
||||
package packed
|
||||
@@ -0,0 +1,206 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.29.3
|
||||
// source: common.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type HeadReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
RouterId int64 `protobuf:"varint,1,opt,name=router_id,json=routerId,proto3" json:"router_id,omitempty" dc:"路由id json:'router_id'"` // 路由id json:"router_id"
|
||||
TraceId string `protobuf:"bytes,2,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty" dc:"追踪id json:'trace_id'"` // 追踪id json:"trace_id"
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *HeadReq) Reset() {
|
||||
*x = HeadReq{}
|
||||
mi := &file_common_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *HeadReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HeadReq) ProtoMessage() {}
|
||||
|
||||
func (x *HeadReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HeadReq.ProtoReflect.Descriptor instead.
|
||||
func (*HeadReq) Descriptor() ([]byte, []int) {
|
||||
return file_common_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *HeadReq) GetRouterId() int64 {
|
||||
if x != nil {
|
||||
return x.RouterId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HeadReq) GetTraceId() string {
|
||||
if x != nil {
|
||||
return x.TraceId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type HeadRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty" dc:"错误码 json:'code'"` // 错误码 json:"code"
|
||||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty" dc:"错误信息 json:'message'"` // 错误信息 json:"message"
|
||||
RouterId int64 `protobuf:"varint,3,opt,name=router_id,json=routerId,proto3" json:"router_id,omitempty" dc:"路由id json:'router_id'"` // 路由id json:"router_id"
|
||||
TraceId string `protobuf:"bytes,4,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty" dc:"追踪id json:'trace_id'"` // 追踪id json:"trace_id"
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *HeadRes) Reset() {
|
||||
*x = HeadRes{}
|
||||
mi := &file_common_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *HeadRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HeadRes) ProtoMessage() {}
|
||||
|
||||
func (x *HeadRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HeadRes.ProtoReflect.Descriptor instead.
|
||||
func (*HeadRes) Descriptor() ([]byte, []int) {
|
||||
return file_common_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *HeadRes) GetCode() int32 {
|
||||
if x != nil {
|
||||
return x.Code
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HeadRes) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HeadRes) GetRouterId() int64 {
|
||||
if x != nil {
|
||||
return x.RouterId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HeadRes) GetTraceId() string {
|
||||
if x != nil {
|
||||
return x.TraceId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_common_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_common_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\fcommon.proto\x12\bPbCommon\"A\n" +
|
||||
"\aHeadReq\x12\x1b\n" +
|
||||
"\trouter_id\x18\x01 \x01(\x03R\brouterId\x12\x19\n" +
|
||||
"\btrace_id\x18\x02 \x01(\tR\atraceId\"o\n" +
|
||||
"\aHeadRes\x12\x12\n" +
|
||||
"\x04code\x18\x01 \x01(\x05R\x04code\x12\x18\n" +
|
||||
"\amessage\x18\x02 \x01(\tR\amessage\x12\x1b\n" +
|
||||
"\trouter_id\x18\x03 \x01(\x03R\brouterId\x12\x19\n" +
|
||||
"\btrace_id\x18\x04 \x01(\tR\atraceIdB\x05Z\x03pb/b\x06proto3"
|
||||
|
||||
var (
|
||||
file_common_proto_rawDescOnce sync.Once
|
||||
file_common_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_common_proto_rawDescGZIP() []byte {
|
||||
file_common_proto_rawDescOnce.Do(func() {
|
||||
file_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_common_proto_rawDesc), len(file_common_proto_rawDesc)))
|
||||
})
|
||||
return file_common_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_common_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_common_proto_goTypes = []any{
|
||||
(*HeadReq)(nil), // 0: PbCommon.HeadReq
|
||||
(*HeadRes)(nil), // 1: PbCommon.HeadRes
|
||||
}
|
||||
var file_common_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_common_proto_init() }
|
||||
func file_common_proto_init() {
|
||||
if File_common_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_common_proto_rawDesc), len(file_common_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_common_proto_goTypes,
|
||||
DependencyIndexes: file_common_proto_depIdxs,
|
||||
MessageInfos: file_common_proto_msgTypes,
|
||||
}.Build()
|
||||
File_common_proto = out.File
|
||||
file_common_proto_goTypes = nil
|
||||
file_common_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.29.3
|
||||
// source: info.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type InfoReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Head *HeadReq `protobuf:"bytes,1,opt,name=head,proto3" json:"head,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *InfoReq) Reset() {
|
||||
*x = InfoReq{}
|
||||
mi := &file_info_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *InfoReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*InfoReq) ProtoMessage() {}
|
||||
|
||||
func (x *InfoReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_info_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use InfoReq.ProtoReflect.Descriptor instead.
|
||||
func (*InfoReq) Descriptor() ([]byte, []int) {
|
||||
return file_info_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *InfoReq) GetHead() *HeadReq {
|
||||
if x != nil {
|
||||
return x.Head
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type InfoRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Head *HeadRes `protobuf:"bytes,1,opt,name=head,proto3" json:"head,omitempty"`
|
||||
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"`
|
||||
Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"`
|
||||
Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Build string `protobuf:"bytes,7,opt,name=build,proto3" json:"build,omitempty"`
|
||||
Commit string `protobuf:"bytes,8,opt,name=commit,proto3" json:"commit,omitempty"`
|
||||
Data map[string]string `protobuf:"bytes,9,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *InfoRes) Reset() {
|
||||
*x = InfoRes{}
|
||||
mi := &file_info_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *InfoRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*InfoRes) ProtoMessage() {}
|
||||
|
||||
func (x *InfoRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_info_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use InfoRes.ProtoReflect.Descriptor instead.
|
||||
func (*InfoRes) Descriptor() ([]byte, []int) {
|
||||
return file_info_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetHead() *HeadRes {
|
||||
if x != nil {
|
||||
return x.Head
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetTitle() string {
|
||||
if x != nil {
|
||||
return x.Title
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetDescription() string {
|
||||
if x != nil {
|
||||
return x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetVersion() string {
|
||||
if x != nil {
|
||||
return x.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetBuild() string {
|
||||
if x != nil {
|
||||
return x.Build
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetCommit() string {
|
||||
if x != nil {
|
||||
return x.Commit
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *InfoRes) GetData() map[string]string {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_info_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_info_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"info.proto\x12\x06PbInfo\x1a\fcommon.proto\"0\n" +
|
||||
"\aInfoReq\x12%\n" +
|
||||
"\x04head\x18\x01 \x01(\v2\x11.PbCommon.HeadReqR\x04head\"\xc0\x02\n" +
|
||||
"\aInfoRes\x12%\n" +
|
||||
"\x04head\x18\x01 \x01(\v2\x11.PbCommon.HeadResR\x04head\x12\x12\n" +
|
||||
"\x04type\x18\x02 \x01(\tR\x04type\x12\x12\n" +
|
||||
"\x04name\x18\x03 \x01(\tR\x04name\x12\x14\n" +
|
||||
"\x05title\x18\x04 \x01(\tR\x05title\x12 \n" +
|
||||
"\vdescription\x18\x05 \x01(\tR\vdescription\x12\x18\n" +
|
||||
"\aversion\x18\x06 \x01(\tR\aversion\x12\x14\n" +
|
||||
"\x05build\x18\a \x01(\tR\x05build\x12\x16\n" +
|
||||
"\x06commit\x18\b \x01(\tR\x06commit\x12-\n" +
|
||||
"\x04data\x18\t \x03(\v2\x19.PbInfo.InfoRes.DataEntryR\x04data\x1a7\n" +
|
||||
"\tDataEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x0122\n" +
|
||||
"\x04Info\x12*\n" +
|
||||
"\x04Info\x12\x0f.PbInfo.InfoReq\x1a\x0f.PbInfo.InfoRes\"\x00B\x05Z\x03pb/b\x06proto3"
|
||||
|
||||
var (
|
||||
file_info_proto_rawDescOnce sync.Once
|
||||
file_info_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_info_proto_rawDescGZIP() []byte {
|
||||
file_info_proto_rawDescOnce.Do(func() {
|
||||
file_info_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_info_proto_rawDesc), len(file_info_proto_rawDesc)))
|
||||
})
|
||||
return file_info_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_info_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_info_proto_goTypes = []any{
|
||||
(*InfoReq)(nil), // 0: PbInfo.InfoReq
|
||||
(*InfoRes)(nil), // 1: PbInfo.InfoRes
|
||||
nil, // 2: PbInfo.InfoRes.DataEntry
|
||||
(*HeadReq)(nil), // 3: PbCommon.HeadReq
|
||||
(*HeadRes)(nil), // 4: PbCommon.HeadRes
|
||||
}
|
||||
var file_info_proto_depIdxs = []int32{
|
||||
3, // 0: PbInfo.InfoReq.head:type_name -> PbCommon.HeadReq
|
||||
4, // 1: PbInfo.InfoRes.head:type_name -> PbCommon.HeadRes
|
||||
2, // 2: PbInfo.InfoRes.data:type_name -> PbInfo.InfoRes.DataEntry
|
||||
0, // 3: PbInfo.Info.Info:input_type -> PbInfo.InfoReq
|
||||
1, // 4: PbInfo.Info.Info:output_type -> PbInfo.InfoRes
|
||||
4, // [4:5] is the sub-list for method output_type
|
||||
3, // [3:4] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_info_proto_init() }
|
||||
func file_info_proto_init() {
|
||||
if File_info_proto != nil {
|
||||
return
|
||||
}
|
||||
file_common_proto_init()
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_info_proto_rawDesc), len(file_info_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_info_proto_goTypes,
|
||||
DependencyIndexes: file_info_proto_depIdxs,
|
||||
MessageInfos: file_info_proto_msgTypes,
|
||||
}.Build()
|
||||
File_info_proto = out.File
|
||||
file_info_proto_goTypes = nil
|
||||
file_info_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc v5.29.3
|
||||
// source: info.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Info_Info_FullMethodName = "/PbInfo.Info/Info"
|
||||
)
|
||||
|
||||
// InfoClient is the client API for Info service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type InfoClient interface {
|
||||
Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*InfoRes, error)
|
||||
}
|
||||
|
||||
type infoClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewInfoClient(cc grpc.ClientConnInterface) InfoClient {
|
||||
return &infoClient{cc}
|
||||
}
|
||||
|
||||
func (c *infoClient) Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*InfoRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(InfoRes)
|
||||
err := c.cc.Invoke(ctx, Info_Info_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// InfoServer is the server API for Info service.
|
||||
// All implementations must embed UnimplementedInfoServer
|
||||
// for forward compatibility.
|
||||
type InfoServer interface {
|
||||
Info(context.Context, *InfoReq) (*InfoRes, error)
|
||||
mustEmbedUnimplementedInfoServer()
|
||||
}
|
||||
|
||||
// UnimplementedInfoServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedInfoServer struct{}
|
||||
|
||||
func (UnimplementedInfoServer) Info(context.Context, *InfoReq) (*InfoRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Info not implemented")
|
||||
}
|
||||
func (UnimplementedInfoServer) mustEmbedUnimplementedInfoServer() {}
|
||||
func (UnimplementedInfoServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeInfoServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to InfoServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeInfoServer interface {
|
||||
mustEmbedUnimplementedInfoServer()
|
||||
}
|
||||
|
||||
func RegisterInfoServer(s grpc.ServiceRegistrar, srv InfoServer) {
|
||||
// If the following call panics, it indicates UnimplementedInfoServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Info_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Info_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(InfoReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InfoServer).Info(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Info_Info_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InfoServer).Info(ctx, req.(*InfoReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Info_ServiceDesc is the grpc.ServiceDesc for Info service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Info_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "PbInfo.Info",
|
||||
HandlerType: (*InfoServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Info",
|
||||
Handler: _Info_Info_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "info.proto",
|
||||
}
|
||||
@@ -0,0 +1,632 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.29.3
|
||||
// source: msgbus.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type EnumMsgType int32
|
||||
|
||||
const (
|
||||
EnumMsgType_MsgTypeNone EnumMsgType = 0 // 未知消息类型
|
||||
EnumMsgType_MsgTypeLogin EnumMsgType = 1 // 客户端长连接登录包
|
||||
EnumMsgType_MsgTypeLogout EnumMsgType = 2 // 客户端长连接登出包
|
||||
EnumMsgType_MsgTypeConnect EnumMsgType = 3 // 新建链接消息
|
||||
EnumMsgType_MsgTypeDisconnect EnumMsgType = 4 // 关闭链接消息
|
||||
EnumMsgType_MsgTypeData EnumMsgType = 5 // 消息透传转发
|
||||
)
|
||||
|
||||
// Enum value maps for EnumMsgType.
|
||||
var (
|
||||
EnumMsgType_name = map[int32]string{
|
||||
0: "MsgTypeNone",
|
||||
1: "MsgTypeLogin",
|
||||
2: "MsgTypeLogout",
|
||||
3: "MsgTypeConnect",
|
||||
4: "MsgTypeDisconnect",
|
||||
5: "MsgTypeData",
|
||||
}
|
||||
EnumMsgType_value = map[string]int32{
|
||||
"MsgTypeNone": 0,
|
||||
"MsgTypeLogin": 1,
|
||||
"MsgTypeLogout": 2,
|
||||
"MsgTypeConnect": 3,
|
||||
"MsgTypeDisconnect": 4,
|
||||
"MsgTypeData": 5,
|
||||
}
|
||||
)
|
||||
|
||||
func (x EnumMsgType) Enum() *EnumMsgType {
|
||||
p := new(EnumMsgType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x EnumMsgType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (EnumMsgType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_msgbus_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (EnumMsgType) Type() protoreflect.EnumType {
|
||||
return &file_msgbus_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x EnumMsgType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use EnumMsgType.Descriptor instead.
|
||||
func (EnumMsgType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_msgbus_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
// 渠道类型
|
||||
type EnumChannelType int32
|
||||
|
||||
const (
|
||||
EnumChannelType_ChannelTypeNone EnumChannelType = 0
|
||||
EnumChannelType_ChannelTypeMqtt EnumChannelType = 1 // 1-MQTT服务器
|
||||
EnumChannelType_ChannelTypeTcp EnumChannelType = 2 // 2-TCP服务器
|
||||
EnumChannelType_ChannelTypeUdp EnumChannelType = 3 // 3-UDP服务器
|
||||
EnumChannelType_ChannelTypeHttp EnumChannelType = 4 // 4-HTTP服务
|
||||
EnumChannelType_ChannelTypeWs EnumChannelType = 5 // 5-WebSocket服务
|
||||
EnumChannelType_ChannelTypeDb EnumChannelType = 6 // 6-数据库服务
|
||||
EnumChannelType_ChannelTypeInner EnumChannelType = 100 // 100-内网流转通道
|
||||
)
|
||||
|
||||
// Enum value maps for EnumChannelType.
|
||||
var (
|
||||
EnumChannelType_name = map[int32]string{
|
||||
0: "ChannelTypeNone",
|
||||
1: "ChannelTypeMqtt",
|
||||
2: "ChannelTypeTcp",
|
||||
3: "ChannelTypeUdp",
|
||||
4: "ChannelTypeHttp",
|
||||
5: "ChannelTypeWs",
|
||||
6: "ChannelTypeDb",
|
||||
100: "ChannelTypeInner",
|
||||
}
|
||||
EnumChannelType_value = map[string]int32{
|
||||
"ChannelTypeNone": 0,
|
||||
"ChannelTypeMqtt": 1,
|
||||
"ChannelTypeTcp": 2,
|
||||
"ChannelTypeUdp": 3,
|
||||
"ChannelTypeHttp": 4,
|
||||
"ChannelTypeWs": 5,
|
||||
"ChannelTypeDb": 6,
|
||||
"ChannelTypeInner": 100,
|
||||
}
|
||||
)
|
||||
|
||||
func (x EnumChannelType) Enum() *EnumChannelType {
|
||||
p := new(EnumChannelType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x EnumChannelType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (EnumChannelType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_msgbus_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (EnumChannelType) Type() protoreflect.EnumType {
|
||||
return &file_msgbus_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x EnumChannelType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use EnumChannelType.Descriptor instead.
|
||||
func (EnumChannelType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_msgbus_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
// 渠道信息
|
||||
type Channel struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ChannelId int64 `protobuf:"varint,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" dc:"渠道ID"` // 渠道ID
|
||||
ChannelType int32 `protobuf:"varint,2,opt,name=channel_type,json=channelType,proto3" json:"channel_type,omitempty" dc:"渠道类型 EnumChannelType"` // 渠道类型 EnumChannelType
|
||||
ServerId int64 `protobuf:"varint,3,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty" dc:"服务ID"` // 服务ID
|
||||
CreateTime int64 `protobuf:"varint,4,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" dc:"启动时间戳(秒)"` // 启动时间戳(秒)
|
||||
TenantId string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty" dc:"租户ID"` // 租户ID
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Channel) Reset() {
|
||||
*x = Channel{}
|
||||
mi := &file_msgbus_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Channel) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Channel) ProtoMessage() {}
|
||||
|
||||
func (x *Channel) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_msgbus_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Channel.ProtoReflect.Descriptor instead.
|
||||
func (*Channel) Descriptor() ([]byte, []int) {
|
||||
return file_msgbus_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Channel) GetChannelId() int64 {
|
||||
if x != nil {
|
||||
return x.ChannelId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Channel) GetChannelType() int32 {
|
||||
if x != nil {
|
||||
return x.ChannelType
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Channel) GetServerId() int64 {
|
||||
if x != nil {
|
||||
return x.ServerId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Channel) GetCreateTime() int64 {
|
||||
if x != nil {
|
||||
return x.CreateTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Channel) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 链接信息
|
||||
type Conn struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ConnId int64 `protobuf:"varint,1,opt,name=conn_id,json=connId,proto3" json:"conn_id,omitempty" dc:"链接ID"` // 链接ID
|
||||
CreateTime int64 `protobuf:"varint,2,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" dc:"链接时间戳(秒)"` // 链接时间戳(秒)
|
||||
LastRecvTime int64 `protobuf:"varint,3,opt,name=last_recv_time,json=lastRecvTime,proto3" json:"last_recv_time,omitempty" dc:"最后接收时间戳(秒)"` // 最后接收时间戳(秒)
|
||||
LastSendTime int64 `protobuf:"varint,4,opt,name=last_send_time,json=lastSendTime,proto3" json:"last_send_time,omitempty" dc:"最后发送时间戳(秒)"` // 最后发送时间戳(秒)
|
||||
ClientId string `protobuf:"bytes,5,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" dc:"客户端ID"` // 客户端ID
|
||||
UserName string `protobuf:"bytes,6,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty" dc:"客户端登录名称"` // 客户端登录名称
|
||||
UserPass string `protobuf:"bytes,7,opt,name=user_pass,json=userPass,proto3" json:"user_pass,omitempty" dc:"客户端登录密码"` // 客户端登录密码
|
||||
ProductKey string `protobuf:"bytes,8,opt,name=product_key,json=productKey,proto3" json:"product_key,omitempty" dc:"绑定主产品KEY"` // 绑定主产品KEY
|
||||
DeviceKey string `protobuf:"bytes,9,opt,name=device_key,json=deviceKey,proto3" json:"device_key,omitempty" dc:"绑定主设备KEY"` // 绑定主设备KEY
|
||||
RemoteAddr string `protobuf:"bytes,10,opt,name=remote_addr,json=remoteAddr,proto3" json:"remote_addr,omitempty"`
|
||||
LocalAddr string `protobuf:"bytes,11,opt,name=local_addr,json=localAddr,proto3" json:"local_addr,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Conn) Reset() {
|
||||
*x = Conn{}
|
||||
mi := &file_msgbus_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Conn) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Conn) ProtoMessage() {}
|
||||
|
||||
func (x *Conn) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_msgbus_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Conn.ProtoReflect.Descriptor instead.
|
||||
func (*Conn) Descriptor() ([]byte, []int) {
|
||||
return file_msgbus_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Conn) GetConnId() int64 {
|
||||
if x != nil {
|
||||
return x.ConnId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Conn) GetCreateTime() int64 {
|
||||
if x != nil {
|
||||
return x.CreateTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Conn) GetLastRecvTime() int64 {
|
||||
if x != nil {
|
||||
return x.LastRecvTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Conn) GetLastSendTime() int64 {
|
||||
if x != nil {
|
||||
return x.LastSendTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Conn) GetClientId() string {
|
||||
if x != nil {
|
||||
return x.ClientId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Conn) GetUserName() string {
|
||||
if x != nil {
|
||||
return x.UserName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Conn) GetUserPass() string {
|
||||
if x != nil {
|
||||
return x.UserPass
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Conn) GetProductKey() string {
|
||||
if x != nil {
|
||||
return x.ProductKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Conn) GetDeviceKey() string {
|
||||
if x != nil {
|
||||
return x.DeviceKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Conn) GetRemoteAddr() string {
|
||||
if x != nil {
|
||||
return x.RemoteAddr
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Conn) GetLocalAddr() string {
|
||||
if x != nil {
|
||||
return x.LocalAddr
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SendMsgReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Head *HeadReq `protobuf:"bytes,1,opt,name=head,proto3" json:"head,omitempty"`
|
||||
Channel *Channel `protobuf:"bytes,2,opt,name=channel,proto3" json:"channel,omitempty" dc:"渠道信息"` // 渠道信息
|
||||
Conn *Conn `protobuf:"bytes,3,opt,name=conn,proto3" json:"conn,omitempty" dc:"链接信息"` // 链接信息
|
||||
MsgType int32 `protobuf:"varint,4,opt,name=msg_type,json=msgType,proto3" json:"msg_type,omitempty" dc:"消息类型"` // 消息类型
|
||||
Topic string `protobuf:"bytes,5,opt,name=topic,proto3" json:"topic,omitempty"`
|
||||
Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SendMsgReq) Reset() {
|
||||
*x = SendMsgReq{}
|
||||
mi := &file_msgbus_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SendMsgReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SendMsgReq) ProtoMessage() {}
|
||||
|
||||
func (x *SendMsgReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_msgbus_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SendMsgReq.ProtoReflect.Descriptor instead.
|
||||
func (*SendMsgReq) Descriptor() ([]byte, []int) {
|
||||
return file_msgbus_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *SendMsgReq) GetHead() *HeadReq {
|
||||
if x != nil {
|
||||
return x.Head
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SendMsgReq) GetChannel() *Channel {
|
||||
if x != nil {
|
||||
return x.Channel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SendMsgReq) GetConn() *Conn {
|
||||
if x != nil {
|
||||
return x.Conn
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SendMsgReq) GetMsgType() int32 {
|
||||
if x != nil {
|
||||
return x.MsgType
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SendMsgReq) GetTopic() string {
|
||||
if x != nil {
|
||||
return x.Topic
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SendMsgReq) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SendMsgRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Head *HeadRes `protobuf:"bytes,1,opt,name=head,proto3" json:"head,omitempty"`
|
||||
Conn *Conn `protobuf:"bytes,2,opt,name=conn,proto3" json:"conn,omitempty"`
|
||||
Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"`
|
||||
Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SendMsgRes) Reset() {
|
||||
*x = SendMsgRes{}
|
||||
mi := &file_msgbus_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SendMsgRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SendMsgRes) ProtoMessage() {}
|
||||
|
||||
func (x *SendMsgRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_msgbus_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SendMsgRes.ProtoReflect.Descriptor instead.
|
||||
func (*SendMsgRes) Descriptor() ([]byte, []int) {
|
||||
return file_msgbus_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *SendMsgRes) GetHead() *HeadRes {
|
||||
if x != nil {
|
||||
return x.Head
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SendMsgRes) GetConn() *Conn {
|
||||
if x != nil {
|
||||
return x.Conn
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SendMsgRes) GetTopic() string {
|
||||
if x != nil {
|
||||
return x.Topic
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SendMsgRes) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_msgbus_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_msgbus_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\fmsgbus.proto\x12\bPbMsgBus\x1a\fcommon.proto\"\xa6\x01\n" +
|
||||
"\aChannel\x12\x1d\n" +
|
||||
"\n" +
|
||||
"channel_id\x18\x01 \x01(\x03R\tchannelId\x12!\n" +
|
||||
"\fchannel_type\x18\x02 \x01(\x05R\vchannelType\x12\x1b\n" +
|
||||
"\tserver_id\x18\x03 \x01(\x03R\bserverId\x12\x1f\n" +
|
||||
"\vcreate_time\x18\x04 \x01(\x03R\n" +
|
||||
"createTime\x12\x1b\n" +
|
||||
"\ttenant_id\x18\x05 \x01(\tR\btenantId\"\xe3\x02\n" +
|
||||
"\x04Conn\x12\x17\n" +
|
||||
"\aconn_id\x18\x01 \x01(\x03R\x06connId\x12\x1f\n" +
|
||||
"\vcreate_time\x18\x02 \x01(\x03R\n" +
|
||||
"createTime\x12$\n" +
|
||||
"\x0elast_recv_time\x18\x03 \x01(\x03R\flastRecvTime\x12$\n" +
|
||||
"\x0elast_send_time\x18\x04 \x01(\x03R\flastSendTime\x12\x1b\n" +
|
||||
"\tclient_id\x18\x05 \x01(\tR\bclientId\x12\x1b\n" +
|
||||
"\tuser_name\x18\x06 \x01(\tR\buserName\x12\x1b\n" +
|
||||
"\tuser_pass\x18\a \x01(\tR\buserPass\x12\x1f\n" +
|
||||
"\vproduct_key\x18\b \x01(\tR\n" +
|
||||
"productKey\x12\x1d\n" +
|
||||
"\n" +
|
||||
"device_key\x18\t \x01(\tR\tdeviceKey\x12\x1f\n" +
|
||||
"\vremote_addr\x18\n" +
|
||||
" \x01(\tR\n" +
|
||||
"remoteAddr\x12\x1d\n" +
|
||||
"\n" +
|
||||
"local_addr\x18\v \x01(\tR\tlocalAddr\"\xc9\x01\n" +
|
||||
"\n" +
|
||||
"SendMsgReq\x12%\n" +
|
||||
"\x04head\x18\x01 \x01(\v2\x11.PbCommon.HeadReqR\x04head\x12+\n" +
|
||||
"\achannel\x18\x02 \x01(\v2\x11.PbMsgBus.ChannelR\achannel\x12\"\n" +
|
||||
"\x04conn\x18\x03 \x01(\v2\x0e.PbMsgBus.ConnR\x04conn\x12\x19\n" +
|
||||
"\bmsg_type\x18\x04 \x01(\x05R\amsgType\x12\x14\n" +
|
||||
"\x05topic\x18\x05 \x01(\tR\x05topic\x12\x12\n" +
|
||||
"\x04data\x18\x06 \x01(\fR\x04data\"\x81\x01\n" +
|
||||
"\n" +
|
||||
"SendMsgRes\x12%\n" +
|
||||
"\x04head\x18\x01 \x01(\v2\x11.PbCommon.HeadResR\x04head\x12\"\n" +
|
||||
"\x04conn\x18\x02 \x01(\v2\x0e.PbMsgBus.ConnR\x04conn\x12\x14\n" +
|
||||
"\x05topic\x18\x03 \x01(\tR\x05topic\x12\x12\n" +
|
||||
"\x04data\x18\x04 \x01(\fR\x04data*\x7f\n" +
|
||||
"\vEnumMsgType\x12\x0f\n" +
|
||||
"\vMsgTypeNone\x10\x00\x12\x10\n" +
|
||||
"\fMsgTypeLogin\x10\x01\x12\x11\n" +
|
||||
"\rMsgTypeLogout\x10\x02\x12\x12\n" +
|
||||
"\x0eMsgTypeConnect\x10\x03\x12\x15\n" +
|
||||
"\x11MsgTypeDisconnect\x10\x04\x12\x0f\n" +
|
||||
"\vMsgTypeData\x10\x05*\xb4\x01\n" +
|
||||
"\x0fEnumChannelType\x12\x13\n" +
|
||||
"\x0fChannelTypeNone\x10\x00\x12\x13\n" +
|
||||
"\x0fChannelTypeMqtt\x10\x01\x12\x12\n" +
|
||||
"\x0eChannelTypeTcp\x10\x02\x12\x12\n" +
|
||||
"\x0eChannelTypeUdp\x10\x03\x12\x13\n" +
|
||||
"\x0fChannelTypeHttp\x10\x04\x12\x11\n" +
|
||||
"\rChannelTypeWs\x10\x05\x12\x11\n" +
|
||||
"\rChannelTypeDb\x10\x06\x12\x14\n" +
|
||||
"\x10ChannelTypeInner\x10d2x\n" +
|
||||
"\x06MsgBus\x122\n" +
|
||||
"\x04Send\x12\x14.PbMsgBus.SendMsgReq\x1a\x14.PbMsgBus.SendMsgRes\x12:\n" +
|
||||
"\bLongSend\x12\x14.PbMsgBus.SendMsgReq\x1a\x14.PbMsgBus.SendMsgRes(\x010\x01B\x05Z\x03pb/b\x06proto3"
|
||||
|
||||
var (
|
||||
file_msgbus_proto_rawDescOnce sync.Once
|
||||
file_msgbus_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_msgbus_proto_rawDescGZIP() []byte {
|
||||
file_msgbus_proto_rawDescOnce.Do(func() {
|
||||
file_msgbus_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_msgbus_proto_rawDesc), len(file_msgbus_proto_rawDesc)))
|
||||
})
|
||||
return file_msgbus_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_msgbus_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_msgbus_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_msgbus_proto_goTypes = []any{
|
||||
(EnumMsgType)(0), // 0: PbMsgBus.EnumMsgType
|
||||
(EnumChannelType)(0), // 1: PbMsgBus.EnumChannelType
|
||||
(*Channel)(nil), // 2: PbMsgBus.Channel
|
||||
(*Conn)(nil), // 3: PbMsgBus.Conn
|
||||
(*SendMsgReq)(nil), // 4: PbMsgBus.SendMsgReq
|
||||
(*SendMsgRes)(nil), // 5: PbMsgBus.SendMsgRes
|
||||
(*HeadReq)(nil), // 6: PbCommon.HeadReq
|
||||
(*HeadRes)(nil), // 7: PbCommon.HeadRes
|
||||
}
|
||||
var file_msgbus_proto_depIdxs = []int32{
|
||||
6, // 0: PbMsgBus.SendMsgReq.head:type_name -> PbCommon.HeadReq
|
||||
2, // 1: PbMsgBus.SendMsgReq.channel:type_name -> PbMsgBus.Channel
|
||||
3, // 2: PbMsgBus.SendMsgReq.conn:type_name -> PbMsgBus.Conn
|
||||
7, // 3: PbMsgBus.SendMsgRes.head:type_name -> PbCommon.HeadRes
|
||||
3, // 4: PbMsgBus.SendMsgRes.conn:type_name -> PbMsgBus.Conn
|
||||
4, // 5: PbMsgBus.MsgBus.Send:input_type -> PbMsgBus.SendMsgReq
|
||||
4, // 6: PbMsgBus.MsgBus.LongSend:input_type -> PbMsgBus.SendMsgReq
|
||||
5, // 7: PbMsgBus.MsgBus.Send:output_type -> PbMsgBus.SendMsgRes
|
||||
5, // 8: PbMsgBus.MsgBus.LongSend:output_type -> PbMsgBus.SendMsgRes
|
||||
7, // [7:9] is the sub-list for method output_type
|
||||
5, // [5:7] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
5, // [5:5] is the sub-list for extension extendee
|
||||
0, // [0:5] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_msgbus_proto_init() }
|
||||
func file_msgbus_proto_init() {
|
||||
if File_msgbus_proto != nil {
|
||||
return
|
||||
}
|
||||
file_common_proto_init()
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_msgbus_proto_rawDesc), len(file_msgbus_proto_rawDesc)),
|
||||
NumEnums: 2,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_msgbus_proto_goTypes,
|
||||
DependencyIndexes: file_msgbus_proto_depIdxs,
|
||||
EnumInfos: file_msgbus_proto_enumTypes,
|
||||
MessageInfos: file_msgbus_proto_msgTypes,
|
||||
}.Build()
|
||||
File_msgbus_proto = out.File
|
||||
file_msgbus_proto_goTypes = nil
|
||||
file_msgbus_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc v5.29.3
|
||||
// source: msgbus.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
MsgBus_Send_FullMethodName = "/PbMsgBus.MsgBus/Send"
|
||||
MsgBus_LongSend_FullMethodName = "/PbMsgBus.MsgBus/LongSend"
|
||||
)
|
||||
|
||||
// MsgBusClient is the client API for MsgBus service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type MsgBusClient interface {
|
||||
Send(ctx context.Context, in *SendMsgReq, opts ...grpc.CallOption) (*SendMsgRes, error)
|
||||
LongSend(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[SendMsgReq, SendMsgRes], error)
|
||||
}
|
||||
|
||||
type msgBusClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewMsgBusClient(cc grpc.ClientConnInterface) MsgBusClient {
|
||||
return &msgBusClient{cc}
|
||||
}
|
||||
|
||||
func (c *msgBusClient) Send(ctx context.Context, in *SendMsgReq, opts ...grpc.CallOption) (*SendMsgRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SendMsgRes)
|
||||
err := c.cc.Invoke(ctx, MsgBus_Send_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *msgBusClient) LongSend(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[SendMsgReq, SendMsgRes], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &MsgBus_ServiceDesc.Streams[0], MsgBus_LongSend_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[SendMsgReq, SendMsgRes]{ClientStream: stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type MsgBus_LongSendClient = grpc.BidiStreamingClient[SendMsgReq, SendMsgRes]
|
||||
|
||||
// MsgBusServer is the server API for MsgBus service.
|
||||
// All implementations must embed UnimplementedMsgBusServer
|
||||
// for forward compatibility.
|
||||
type MsgBusServer interface {
|
||||
Send(context.Context, *SendMsgReq) (*SendMsgRes, error)
|
||||
LongSend(grpc.BidiStreamingServer[SendMsgReq, SendMsgRes]) error
|
||||
mustEmbedUnimplementedMsgBusServer()
|
||||
}
|
||||
|
||||
// UnimplementedMsgBusServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedMsgBusServer struct{}
|
||||
|
||||
func (UnimplementedMsgBusServer) Send(context.Context, *SendMsgReq) (*SendMsgRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Send not implemented")
|
||||
}
|
||||
func (UnimplementedMsgBusServer) LongSend(grpc.BidiStreamingServer[SendMsgReq, SendMsgRes]) error {
|
||||
return status.Error(codes.Unimplemented, "method LongSend not implemented")
|
||||
}
|
||||
func (UnimplementedMsgBusServer) mustEmbedUnimplementedMsgBusServer() {}
|
||||
func (UnimplementedMsgBusServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeMsgBusServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to MsgBusServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeMsgBusServer interface {
|
||||
mustEmbedUnimplementedMsgBusServer()
|
||||
}
|
||||
|
||||
func RegisterMsgBusServer(s grpc.ServiceRegistrar, srv MsgBusServer) {
|
||||
// If the following call panics, it indicates UnimplementedMsgBusServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&MsgBus_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _MsgBus_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SendMsgReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(MsgBusServer).Send(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: MsgBus_Send_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MsgBusServer).Send(ctx, req.(*SendMsgReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _MsgBus_LongSend_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(MsgBusServer).LongSend(&grpc.GenericServerStream[SendMsgReq, SendMsgRes]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type MsgBus_LongSendServer = grpc.BidiStreamingServer[SendMsgReq, SendMsgRes]
|
||||
|
||||
// MsgBus_ServiceDesc is the grpc.ServiceDesc for MsgBus service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var MsgBus_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "PbMsgBus.MsgBus",
|
||||
HandlerType: (*MsgBusServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Send",
|
||||
Handler: _MsgBus_Send_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "LongSend",
|
||||
Handler: _MsgBus_LongSend_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "msgbus.proto",
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.29.3
|
||||
// source: msgcall.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type MsgReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Head *HeadReq `protobuf:"bytes,1,opt,name=head,proto3" json:"head,omitempty"`
|
||||
Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
|
||||
Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
|
||||
Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *MsgReq) Reset() {
|
||||
*x = MsgReq{}
|
||||
mi := &file_msgcall_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *MsgReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*MsgReq) ProtoMessage() {}
|
||||
|
||||
func (x *MsgReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_msgcall_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MsgReq.ProtoReflect.Descriptor instead.
|
||||
func (*MsgReq) Descriptor() ([]byte, []int) {
|
||||
return file_msgcall_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *MsgReq) GetHead() *HeadReq {
|
||||
if x != nil {
|
||||
return x.Head
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *MsgReq) GetService() string {
|
||||
if x != nil {
|
||||
return x.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MsgReq) GetMethod() string {
|
||||
if x != nil {
|
||||
return x.Method
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MsgReq) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type MsgRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Head *HeadRes `protobuf:"bytes,1,opt,name=head,proto3" json:"head,omitempty"`
|
||||
Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
|
||||
Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
|
||||
Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *MsgRes) Reset() {
|
||||
*x = MsgRes{}
|
||||
mi := &file_msgcall_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *MsgRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*MsgRes) ProtoMessage() {}
|
||||
|
||||
func (x *MsgRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_msgcall_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MsgRes.ProtoReflect.Descriptor instead.
|
||||
func (*MsgRes) Descriptor() ([]byte, []int) {
|
||||
return file_msgcall_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *MsgRes) GetHead() *HeadRes {
|
||||
if x != nil {
|
||||
return x.Head
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *MsgRes) GetService() string {
|
||||
if x != nil {
|
||||
return x.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MsgRes) GetMethod() string {
|
||||
if x != nil {
|
||||
return x.Method
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MsgRes) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_msgcall_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_msgcall_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\rmsgcall.proto\x12\tPbMsgCall\x1a\fcommon.proto\"u\n" +
|
||||
"\x06MsgReq\x12%\n" +
|
||||
"\x04head\x18\x01 \x01(\v2\x11.PbCommon.HeadReqR\x04head\x12\x18\n" +
|
||||
"\aservice\x18\x02 \x01(\tR\aservice\x12\x16\n" +
|
||||
"\x06method\x18\x03 \x01(\tR\x06method\x12\x12\n" +
|
||||
"\x04data\x18\x04 \x01(\fR\x04data\"u\n" +
|
||||
"\x06MsgRes\x12%\n" +
|
||||
"\x04head\x18\x01 \x01(\v2\x11.PbCommon.HeadResR\x04head\x12\x18\n" +
|
||||
"\aservice\x18\x02 \x01(\tR\aservice\x12\x16\n" +
|
||||
"\x06method\x18\x03 \x01(\tR\x06method\x12\x12\n" +
|
||||
"\x04data\x18\x04 \x01(\fR\x04data2r\n" +
|
||||
"\aMsgCall\x12/\n" +
|
||||
"\aOneCall\x12\x11.PbMsgCall.MsgReq\x1a\x11.PbMsgCall.MsgRes\x126\n" +
|
||||
"\n" +
|
||||
"StreamCall\x12\x11.PbMsgCall.MsgReq\x1a\x11.PbMsgCall.MsgRes(\x010\x01B\x05Z\x03pb/b\x06proto3"
|
||||
|
||||
var (
|
||||
file_msgcall_proto_rawDescOnce sync.Once
|
||||
file_msgcall_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_msgcall_proto_rawDescGZIP() []byte {
|
||||
file_msgcall_proto_rawDescOnce.Do(func() {
|
||||
file_msgcall_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_msgcall_proto_rawDesc), len(file_msgcall_proto_rawDesc)))
|
||||
})
|
||||
return file_msgcall_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_msgcall_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_msgcall_proto_goTypes = []any{
|
||||
(*MsgReq)(nil), // 0: PbMsgCall.MsgReq
|
||||
(*MsgRes)(nil), // 1: PbMsgCall.MsgRes
|
||||
(*HeadReq)(nil), // 2: PbCommon.HeadReq
|
||||
(*HeadRes)(nil), // 3: PbCommon.HeadRes
|
||||
}
|
||||
var file_msgcall_proto_depIdxs = []int32{
|
||||
2, // 0: PbMsgCall.MsgReq.head:type_name -> PbCommon.HeadReq
|
||||
3, // 1: PbMsgCall.MsgRes.head:type_name -> PbCommon.HeadRes
|
||||
0, // 2: PbMsgCall.MsgCall.OneCall:input_type -> PbMsgCall.MsgReq
|
||||
0, // 3: PbMsgCall.MsgCall.StreamCall:input_type -> PbMsgCall.MsgReq
|
||||
1, // 4: PbMsgCall.MsgCall.OneCall:output_type -> PbMsgCall.MsgRes
|
||||
1, // 5: PbMsgCall.MsgCall.StreamCall:output_type -> PbMsgCall.MsgRes
|
||||
4, // [4:6] is the sub-list for method output_type
|
||||
2, // [2:4] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_msgcall_proto_init() }
|
||||
func file_msgcall_proto_init() {
|
||||
if File_msgcall_proto != nil {
|
||||
return
|
||||
}
|
||||
file_common_proto_init()
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_msgcall_proto_rawDesc), len(file_msgcall_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_msgcall_proto_goTypes,
|
||||
DependencyIndexes: file_msgcall_proto_depIdxs,
|
||||
MessageInfos: file_msgcall_proto_msgTypes,
|
||||
}.Build()
|
||||
File_msgcall_proto = out.File
|
||||
file_msgcall_proto_goTypes = nil
|
||||
file_msgcall_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc v5.29.3
|
||||
// source: msgcall.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
MsgCall_OneCall_FullMethodName = "/PbMsgCall.MsgCall/OneCall"
|
||||
MsgCall_StreamCall_FullMethodName = "/PbMsgCall.MsgCall/StreamCall"
|
||||
)
|
||||
|
||||
// MsgCallClient is the client API for MsgCall service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type MsgCallClient interface {
|
||||
OneCall(ctx context.Context, in *MsgReq, opts ...grpc.CallOption) (*MsgRes, error)
|
||||
StreamCall(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[MsgReq, MsgRes], error)
|
||||
}
|
||||
|
||||
type msgCallClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewMsgCallClient(cc grpc.ClientConnInterface) MsgCallClient {
|
||||
return &msgCallClient{cc}
|
||||
}
|
||||
|
||||
func (c *msgCallClient) OneCall(ctx context.Context, in *MsgReq, opts ...grpc.CallOption) (*MsgRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(MsgRes)
|
||||
err := c.cc.Invoke(ctx, MsgCall_OneCall_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *msgCallClient) StreamCall(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[MsgReq, MsgRes], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &MsgCall_ServiceDesc.Streams[0], MsgCall_StreamCall_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[MsgReq, MsgRes]{ClientStream: stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type MsgCall_StreamCallClient = grpc.BidiStreamingClient[MsgReq, MsgRes]
|
||||
|
||||
// MsgCallServer is the server API for MsgCall service.
|
||||
// All implementations must embed UnimplementedMsgCallServer
|
||||
// for forward compatibility.
|
||||
type MsgCallServer interface {
|
||||
OneCall(context.Context, *MsgReq) (*MsgRes, error)
|
||||
StreamCall(grpc.BidiStreamingServer[MsgReq, MsgRes]) error
|
||||
mustEmbedUnimplementedMsgCallServer()
|
||||
}
|
||||
|
||||
// UnimplementedMsgCallServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedMsgCallServer struct{}
|
||||
|
||||
func (UnimplementedMsgCallServer) OneCall(context.Context, *MsgReq) (*MsgRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method OneCall not implemented")
|
||||
}
|
||||
func (UnimplementedMsgCallServer) StreamCall(grpc.BidiStreamingServer[MsgReq, MsgRes]) error {
|
||||
return status.Error(codes.Unimplemented, "method StreamCall not implemented")
|
||||
}
|
||||
func (UnimplementedMsgCallServer) mustEmbedUnimplementedMsgCallServer() {}
|
||||
func (UnimplementedMsgCallServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeMsgCallServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to MsgCallServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeMsgCallServer interface {
|
||||
mustEmbedUnimplementedMsgCallServer()
|
||||
}
|
||||
|
||||
func RegisterMsgCallServer(s grpc.ServiceRegistrar, srv MsgCallServer) {
|
||||
// If the following call panics, it indicates UnimplementedMsgCallServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&MsgCall_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _MsgCall_OneCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(MsgReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(MsgCallServer).OneCall(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: MsgCall_OneCall_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MsgCallServer).OneCall(ctx, req.(*MsgReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _MsgCall_StreamCall_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(MsgCallServer).StreamCall(&grpc.GenericServerStream[MsgReq, MsgRes]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type MsgCall_StreamCallServer = grpc.BidiStreamingServer[MsgReq, MsgRes]
|
||||
|
||||
// MsgCall_ServiceDesc is the grpc.ServiceDesc for MsgCall service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var MsgCall_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "PbMsgCall.MsgCall",
|
||||
HandlerType: (*MsgCallServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "OneCall",
|
||||
Handler: _MsgCall_OneCall_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "StreamCall",
|
||||
Handler: _MsgCall_StreamCall_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "msgcall.proto",
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.29.3
|
||||
// source: notice.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type SendReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Head *HeadReq `protobuf:"bytes,1,opt,name=head,proto3" json:"head,omitempty"`
|
||||
Config []byte `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
|
||||
Params []byte `protobuf:"bytes,3,opt,name=params,proto3" json:"params,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SendReq) Reset() {
|
||||
*x = SendReq{}
|
||||
mi := &file_notice_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SendReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SendReq) ProtoMessage() {}
|
||||
|
||||
func (x *SendReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_notice_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SendReq.ProtoReflect.Descriptor instead.
|
||||
func (*SendReq) Descriptor() ([]byte, []int) {
|
||||
return file_notice_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *SendReq) GetHead() *HeadReq {
|
||||
if x != nil {
|
||||
return x.Head
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SendReq) GetConfig() []byte {
|
||||
if x != nil {
|
||||
return x.Config
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SendReq) GetParams() []byte {
|
||||
if x != nil {
|
||||
return x.Params
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SendRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Head *HeadRes `protobuf:"bytes,1,opt,name=head,proto3" json:"head,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SendRes) Reset() {
|
||||
*x = SendRes{}
|
||||
mi := &file_notice_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SendRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SendRes) ProtoMessage() {}
|
||||
|
||||
func (x *SendRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_notice_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SendRes.ProtoReflect.Descriptor instead.
|
||||
func (*SendRes) Descriptor() ([]byte, []int) {
|
||||
return file_notice_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *SendRes) GetHead() *HeadRes {
|
||||
if x != nil {
|
||||
return x.Head
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_notice_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_notice_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\fnotice.proto\x12\bPbNotice\x1a\fcommon.proto\"`\n" +
|
||||
"\aSendReq\x12%\n" +
|
||||
"\x04head\x18\x01 \x01(\v2\x11.PbCommon.HeadReqR\x04head\x12\x16\n" +
|
||||
"\x06config\x18\x02 \x01(\fR\x06config\x12\x16\n" +
|
||||
"\x06params\x18\x03 \x01(\fR\x06params\"0\n" +
|
||||
"\aSendRes\x12%\n" +
|
||||
"\x04head\x18\x01 \x01(\v2\x11.PbCommon.HeadResR\x04head28\n" +
|
||||
"\x06Notice\x12.\n" +
|
||||
"\x04Send\x12\x11.PbNotice.SendReq\x1a\x11.PbNotice.SendRes\"\x00B\x05Z\x03pb/b\x06proto3"
|
||||
|
||||
var (
|
||||
file_notice_proto_rawDescOnce sync.Once
|
||||
file_notice_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_notice_proto_rawDescGZIP() []byte {
|
||||
file_notice_proto_rawDescOnce.Do(func() {
|
||||
file_notice_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_notice_proto_rawDesc), len(file_notice_proto_rawDesc)))
|
||||
})
|
||||
return file_notice_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_notice_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_notice_proto_goTypes = []any{
|
||||
(*SendReq)(nil), // 0: PbNotice.SendReq
|
||||
(*SendRes)(nil), // 1: PbNotice.SendRes
|
||||
(*HeadReq)(nil), // 2: PbCommon.HeadReq
|
||||
(*HeadRes)(nil), // 3: PbCommon.HeadRes
|
||||
}
|
||||
var file_notice_proto_depIdxs = []int32{
|
||||
2, // 0: PbNotice.SendReq.head:type_name -> PbCommon.HeadReq
|
||||
3, // 1: PbNotice.SendRes.head:type_name -> PbCommon.HeadRes
|
||||
0, // 2: PbNotice.Notice.Send:input_type -> PbNotice.SendReq
|
||||
1, // 3: PbNotice.Notice.Send:output_type -> PbNotice.SendRes
|
||||
3, // [3:4] is the sub-list for method output_type
|
||||
2, // [2:3] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_notice_proto_init() }
|
||||
func file_notice_proto_init() {
|
||||
if File_notice_proto != nil {
|
||||
return
|
||||
}
|
||||
file_common_proto_init()
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_notice_proto_rawDesc), len(file_notice_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_notice_proto_goTypes,
|
||||
DependencyIndexes: file_notice_proto_depIdxs,
|
||||
MessageInfos: file_notice_proto_msgTypes,
|
||||
}.Build()
|
||||
File_notice_proto = out.File
|
||||
file_notice_proto_goTypes = nil
|
||||
file_notice_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc v5.29.3
|
||||
// source: notice.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Notice_Send_FullMethodName = "/PbNotice.Notice/Send"
|
||||
)
|
||||
|
||||
// NoticeClient is the client API for Notice service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type NoticeClient interface {
|
||||
Send(ctx context.Context, in *SendReq, opts ...grpc.CallOption) (*SendRes, error)
|
||||
}
|
||||
|
||||
type noticeClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewNoticeClient(cc grpc.ClientConnInterface) NoticeClient {
|
||||
return ¬iceClient{cc}
|
||||
}
|
||||
|
||||
func (c *noticeClient) Send(ctx context.Context, in *SendReq, opts ...grpc.CallOption) (*SendRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SendRes)
|
||||
err := c.cc.Invoke(ctx, Notice_Send_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// NoticeServer is the server API for Notice service.
|
||||
// All implementations must embed UnimplementedNoticeServer
|
||||
// for forward compatibility.
|
||||
type NoticeServer interface {
|
||||
Send(context.Context, *SendReq) (*SendRes, error)
|
||||
mustEmbedUnimplementedNoticeServer()
|
||||
}
|
||||
|
||||
// UnimplementedNoticeServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedNoticeServer struct{}
|
||||
|
||||
func (UnimplementedNoticeServer) Send(context.Context, *SendReq) (*SendRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Send not implemented")
|
||||
}
|
||||
func (UnimplementedNoticeServer) mustEmbedUnimplementedNoticeServer() {}
|
||||
func (UnimplementedNoticeServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeNoticeServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to NoticeServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeNoticeServer interface {
|
||||
mustEmbedUnimplementedNoticeServer()
|
||||
}
|
||||
|
||||
func RegisterNoticeServer(s grpc.ServiceRegistrar, srv NoticeServer) {
|
||||
// If the following call panics, it indicates UnimplementedNoticeServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Notice_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Notice_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SendReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NoticeServer).Send(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Notice_Send_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NoticeServer).Send(ctx, req.(*SendReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Notice_ServiceDesc is the grpc.ServiceDesc for Notice service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Notice_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "PbNotice.Notice",
|
||||
HandlerType: (*NoticeServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Send",
|
||||
Handler: _Notice_Send_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "notice.proto",
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package initconsul
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/contrib/registry/consul/v2"
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsel"
|
||||
)
|
||||
|
||||
func InitConsul(ctx context.Context) error {
|
||||
// 初始化consul
|
||||
err := registerConsul(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func registerConsul(ctx context.Context) error {
|
||||
consulAddress := g.Cfg().MustGet(ctx, "registry.address", "127.0.0.1:8500").String()
|
||||
g.Log().Infof(ctx, "consulAddress: %+v", consulAddress)
|
||||
registry, err := consul.New(consul.WithAddress(consulAddress))
|
||||
if err != nil {
|
||||
g.Log().Fatalf(ctx, "consul初始化失败: %+v", err)
|
||||
return err
|
||||
}
|
||||
grpcx.Resolver.Register(registry)
|
||||
gsel.SetBuilder(gsel.NewBuilderRandom())
|
||||
g.Log().Infof(ctx, "consul注册成功")
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// package version
|
||||
// @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
|
||||
package version
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
var (
|
||||
BuildTime string
|
||||
BuildVersion string
|
||||
CommitID string
|
||||
)
|
||||
|
||||
func ShowLogo(ctx context.Context, buildVersion, buildTime, commitID string) {
|
||||
BuildVersion = buildVersion
|
||||
BuildTime = buildTime
|
||||
CommitID = commitID
|
||||
//版本号
|
||||
|
||||
g.Log().Notice(ctx, `
|
||||
|
||||
██╗██╗███████╗ ██╗ ██████╗ ████████╗
|
||||
██║██║██╔════╝ ██║██╔═══██╗╚══██╔══╝
|
||||
██║██║█████╗ ██║██║ ██║ ██║
|
||||
██ ██║██║██╔══╝ ██║██║ ██║ ██║
|
||||
╚█████╔╝██║███████╗ ██║╚██████╔╝ ██║
|
||||
╚════╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝
|
||||
|
||||
`)
|
||||
|
||||
g.Log().Notice(ctx, "Version :", buildVersion)
|
||||
g.Log().Notice(ctx, "BuildTime :", buildTime)
|
||||
g.Log().Notice(ctx, "CommitID :", commitID)
|
||||
g.Log().Notice(ctx, "Copyright:", "2026 The iotLCM Authors")
|
||||
|
||||
fmt.Println("Version :", buildVersion)
|
||||
fmt.Println("BuildTime :", buildTime)
|
||||
fmt.Println("CommitID :", commitID)
|
||||
fmt.Println("Copyright:", "2026 The iotLCM Authors")
|
||||
}
|
||||
|
||||
func AppName(ctx context.Context) string {
|
||||
return g.Cfg().MustGet(ctx, "system.appName", "IotLCM").String()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Package xjpubconsts
|
||||
// @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
|
||||
package xjpubconsts
|
||||
|
||||
const (
|
||||
HTTPContentTypeXml = "text/xml"
|
||||
HTTPContentTypeHtml = "text/html"
|
||||
HTTPContentTypeStream = "text/event-stream"
|
||||
HTTPContentTypeJson = "application/json"
|
||||
HTTPContentTypeExcel = "application/octet-stream"
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
package xjpubconsts
|
||||
|
||||
const (
|
||||
ServiceTypeWeb = "web" // web服务
|
||||
ServiceTypeQueue = "queue" // 队列服务
|
||||
ServiceTypeRedis = "redis" // 缓存类型
|
||||
ServiceTypeNotice = "notice" // 通知服务
|
||||
ServiceTypeTask = "task" // 任务服务
|
||||
ServiceTypeAccess = "access" // 接入服务
|
||||
)
|
||||
|
||||
const (
|
||||
ServiceNameYzAdminWeb = "yzadmin-web-svc" // 后台管理服务
|
||||
ServiceNameYzUpstreamChanSvc = "yzupstreamchan-grpc-svc" // 上游通道服务
|
||||
ServiceNameYzUpstreamProxySvc = "yzupstreamproxy-grpc-svc" // 上游代理服务
|
||||
ServiceNameYzApiHttpSvc = "yzapi-http-svc" // API 服务
|
||||
)
|
||||
@@ -0,0 +1,100 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gclient"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
type sHttpClient struct {
|
||||
client *gclient.Client
|
||||
}
|
||||
|
||||
func NewHttpClient() *sHttpClient {
|
||||
client := g.Client()
|
||||
return &sHttpClient{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterHttpClient(NewHttpClient())
|
||||
}
|
||||
|
||||
func (s *sHttpClient) PostObj(ctx context.Context, serviceName string, path string, req interface{}, res interface{}) (err error) {
|
||||
reqJson, err := gjson.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resJson, err := s.Post(ctx, serviceName, path, reqJson)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = gjson.Unmarshal(resJson, res)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "sHttpClient.PostObj gjson.Unmarshal error: %v, resJson: %s", err, string(resJson))
|
||||
return err
|
||||
}
|
||||
g.Log().Debugf(ctx, "sHttpClient.PostObj res: %+v, resJson: %s", res, string(resJson))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sHttpClient) Post(ctx context.Context, serviceName string, path string, req []byte) (res []byte, err error) {
|
||||
// s.client.SetHeader("Span-Id", "0.0.1")
|
||||
// s.client.SetHeader("Trace-Id", gctx.CtxId(ctx))
|
||||
|
||||
url := "http://" + serviceName + path
|
||||
s.client.SetDiscovery(gsvc.GetRegistry())
|
||||
// g.Log().Debugf(ctx, "sHttpClient.Post url: %s, req: %+v", url, string(req))
|
||||
response, err := s.client.Post(ctx, url, req)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "sHttpClient.Post Post error: %v, url: %s, req: %+v", err, url, string(req))
|
||||
return nil, err
|
||||
}
|
||||
defer response.Close()
|
||||
res = response.ReadAll()
|
||||
g.Log().Debugf(ctx, "sHttpClient.Post url: %s, req: %+v, res: %+v", url, string(req), string(res))
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *sHttpClient) AllServerPost(ctx context.Context, serviceName string, path string, req []byte) (resMap map[string][]byte, err error) {
|
||||
// s.client.SetHeader("Span-Id", "0.0.1")
|
||||
// s.client.SetHeader("Trace-Id", gctx.CtxId(ctx))
|
||||
s.client.SetDiscovery(gsvc.GetRegistry())
|
||||
|
||||
servers, err := gsvc.Search(ctx, gsvc.SearchInput{
|
||||
Name: serviceName,
|
||||
})
|
||||
if len(servers) == 0 {
|
||||
g.Log().Errorf(ctx, "sHttpClient.AllServerPost gsvc.Search(ctx, serviceName) error: %v, serviceName: %s", err, serviceName)
|
||||
return nil, err
|
||||
}
|
||||
// g.Log().Debugf(ctx, "sHttpClient.AllServerPost servers: %+v", servers)
|
||||
endpoints := make([]string, 0)
|
||||
for _, server := range servers {
|
||||
endpoint := server.GetEndpoints()
|
||||
if len(endpoint) == 0 {
|
||||
g.Log().Errorf(ctx, "sHttpClient.AllServerPost server.GetEndpoints() error: %v, serviceName: %s", err, serviceName)
|
||||
continue
|
||||
}
|
||||
endpoints = append(endpoints, endpoint[0].String())
|
||||
}
|
||||
resMap = make(map[string][]byte)
|
||||
for _, e := range endpoints {
|
||||
url := "http://" + e + path
|
||||
res, err := s.Post(ctx, e, path, req)
|
||||
// g.Log().Debugf(ctx, "sHttpClient.AllServerPost Post url: %s, req: %+v res: %+v err: %+v", url, string(req), string(res), err)
|
||||
if err != nil {
|
||||
resMap[e] = nil
|
||||
g.Log().Errorf(ctx, "sHttpClient.AllServerPost Post error: %v, url: %s, req: %+v", err, url, string(req))
|
||||
continue
|
||||
}
|
||||
resMap[e] = res
|
||||
}
|
||||
return resMap, nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubconsts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel/response"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
)
|
||||
|
||||
type sUpstreamProxyClient struct {
|
||||
}
|
||||
|
||||
func NewUpstreamProxyClient() *sUpstreamProxyClient {
|
||||
return &sUpstreamProxyClient{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterUpstreamProxyClient(NewUpstreamProxyClient())
|
||||
}
|
||||
|
||||
// 物联网卡在线信息实时查询
|
||||
func (s *sUpstreamProxyClient) QuerySimSession(ctx context.Context, input *xjpubmodel.SimSessionInput) (output *xjpubmodel.SimSessionOutput, err error) {
|
||||
res := &response.ResponseGeneric[*xjpubmodel.SimSessionOutput]{}
|
||||
err = xjpubservice.HttpClient().PostObj(ctx, xjpubconsts.ServiceNameYzUpstreamChanSvc, "/query/sim-session", input, res)
|
||||
output = res.Data
|
||||
return output, err
|
||||
}
|
||||
|
||||
// 物联网卡卡状态查询
|
||||
func (s *sUpstreamProxyClient) QuerySimCardStatus(ctx context.Context, input *xjpubmodel.SimCardStatusInput) (output *xjpubmodel.SimCardStatusOutput, err error) {
|
||||
res := &response.ResponseGeneric[*xjpubmodel.SimCardStatusOutput]{}
|
||||
err = xjpubservice.HttpClient().PostObj(ctx, xjpubconsts.ServiceNameYzUpstreamChanSvc, "/query/sim-status", input, res)
|
||||
output = res.Data
|
||||
return output, err
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
)
|
||||
|
||||
type sInfo struct {
|
||||
Info xjpubmodel.InfoModel
|
||||
}
|
||||
|
||||
func NewInfo() *sInfo {
|
||||
return &sInfo{
|
||||
Info: xjpubmodel.InfoModel{},
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterInfo(NewInfo())
|
||||
}
|
||||
|
||||
func (s *sInfo) GetInfo() *xjpubmodel.InfoModel {
|
||||
return &s.Info
|
||||
}
|
||||
|
||||
func (s *sInfo) SetInfoName(Type, Name, Title, Description string) {
|
||||
if s.Info.Name == "" {
|
||||
s.Info.Type = Type
|
||||
s.Info.Name = Name
|
||||
s.Info.Title = Title
|
||||
s.Info.Description = Description
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sInfo) SetInfoBuild(buildVersion, buildTime, commitID string) {
|
||||
s.Info.Version = buildVersion
|
||||
s.Info.Build = buildTime
|
||||
s.Info.Commit = commitID
|
||||
}
|
||||
|
||||
func (s *sInfo) SetInfoData(data map[string]interface{}) {
|
||||
s.Info.Data = data
|
||||
}
|
||||
|
||||
func (s *sInfo) GetInfoData() map[string]interface{} {
|
||||
return s.Info.Data
|
||||
}
|
||||
|
||||
func (s *sInfo) AddInfoData(key string, value interface{}) {
|
||||
if s.Info.Data == nil {
|
||||
s.Info.Data = make(map[string]interface{})
|
||||
}
|
||||
s.Info.Data[key] = value
|
||||
}
|
||||
|
||||
func (s *sInfo) DelInfoData(key string) {
|
||||
delete(s.Info.Data, key)
|
||||
}
|
||||
|
||||
func (s *sInfo) GetInfoDataByKey(key string) interface{} {
|
||||
if s.Info.Data == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := s.Info.Data[key]; !ok {
|
||||
return nil
|
||||
}
|
||||
return s.Info.Data[key]
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
)
|
||||
|
||||
type sInfoRpc struct {
|
||||
Info *xjpubmodel.InfoModel
|
||||
}
|
||||
|
||||
func NewInfoRpc() *sInfoRpc {
|
||||
return &sInfoRpc{
|
||||
Info: xjpubmodel.NewInfoModel(),
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterInfoRpc(NewInfoRpc())
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) GetInfo() *xjpubmodel.InfoModel {
|
||||
ctx := context.Background()
|
||||
logLevel := g.Cfg().MustGet(ctx, "logger.level", "").String()
|
||||
if logLevel != "" {
|
||||
g.Log().SetLevelStr(logLevel)
|
||||
}
|
||||
s.AddInfoData("log_level_conf", logLevel)
|
||||
s.AddInfoData("log_level_real", toLogLevelStr(g.Log().GetLevel()))
|
||||
s.AddInfoData("Goroutines", runtime.NumGoroutine())
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
s.AddInfoData("MemAllocKB", m.Alloc/1024)
|
||||
s.AddInfoData("MemTotalAllocKB", m.TotalAlloc/1024)
|
||||
s.AddInfoData("MemSysKB", m.Sys/1024)
|
||||
s.AddInfoData("MemHeapAllocKB", m.HeapAlloc/1024)
|
||||
s.AddInfoData("MemHeapSysKB", m.HeapSys/1024)
|
||||
s.AddInfoData("MemHeapIdleKB", m.HeapIdle/1024)
|
||||
s.AddInfoData("MemHeapInuseKB", m.HeapInuse/1024)
|
||||
s.AddInfoData("MemHeapReleasedKB", m.HeapReleased/1024)
|
||||
s.AddInfoData("MemHeapObjects", m.HeapObjects)
|
||||
s.AddInfoData("MemStackInuseKB", m.StackInuse/1024)
|
||||
s.AddInfoData("MemStackSysKB", m.StackSys/1024)
|
||||
s.AddInfoData("MemNumGC", m.NumGC)
|
||||
return s.Info
|
||||
}
|
||||
|
||||
func toLogLevelStr(level int) string {
|
||||
if level == glog.LEVEL_NONE {
|
||||
return "NONE"
|
||||
}
|
||||
if level == glog.LEVEL_ALL {
|
||||
return "ALL"
|
||||
}
|
||||
if level == glog.LEVEL_DEV {
|
||||
return "DEV"
|
||||
}
|
||||
if level == glog.LEVEL_PROD {
|
||||
return "PROD"
|
||||
}
|
||||
str := ""
|
||||
if level&glog.LEVEL_DEBU != 0 {
|
||||
str += "DEBUG "
|
||||
}
|
||||
if level&glog.LEVEL_INFO != 0 {
|
||||
str += "INFO "
|
||||
}
|
||||
if level&glog.LEVEL_NOTI != 0 {
|
||||
str += "NOTI "
|
||||
}
|
||||
if level&glog.LEVEL_WARN != 0 {
|
||||
str += "WARN "
|
||||
}
|
||||
if level&glog.LEVEL_ERRO != 0 {
|
||||
str += "ERRO "
|
||||
}
|
||||
if level&glog.LEVEL_CRIT != 0 {
|
||||
str += "CRIT "
|
||||
}
|
||||
if level&glog.LEVEL_PANI != 0 {
|
||||
str += "PANI "
|
||||
}
|
||||
if level&glog.LEVEL_FATA != 0 {
|
||||
str += "FATA "
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) SetInfoName(Type, Name, Title, Description string) {
|
||||
if s.Info.Name == "" {
|
||||
s.Info.Type = Type
|
||||
s.Info.Name = Name
|
||||
s.Info.Title = Title
|
||||
s.Info.Description = Description
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) SetInfoBuild(buildVersion, buildTime, commitID string) {
|
||||
s.Info.Version = buildVersion
|
||||
s.Info.Build = buildTime
|
||||
s.Info.Commit = commitID
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) SetInfoData(data map[string]interface{}) {
|
||||
s.Info.Data = data
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) GetInfoData() map[string]interface{} {
|
||||
return s.Info.Data
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) AddInfoData(key string, value interface{}) {
|
||||
s.Info.Data[key] = value
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) DelInfoData(key string) {
|
||||
delete(s.Info.Data, key)
|
||||
}
|
||||
|
||||
func (s *sInfoRpc) GetInfoDataByKey(key string) interface{} {
|
||||
return s.Info.Data[key]
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// package middleware
|
||||
// @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
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"slices"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubconsts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubmodel/response"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpubservice"
|
||||
)
|
||||
|
||||
type sMiddleware struct {
|
||||
}
|
||||
|
||||
func New() *sMiddleware {
|
||||
return &sMiddleware{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
xjpubservice.RegisterMiddleware(New())
|
||||
}
|
||||
|
||||
func getContentType(r *ghttp.Request) (contentType string) {
|
||||
contentType = r.Response.Header().Get("Content-Type")
|
||||
if contentType != "" {
|
||||
return
|
||||
}
|
||||
|
||||
mime := gmeta.Get(r.GetHandlerResponse(), "mime").String()
|
||||
if mime == "" {
|
||||
contentType = xjpubconsts.HTTPContentTypeJson
|
||||
} else {
|
||||
contentType = mime
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 响应处理中间件
|
||||
func (m *sMiddleware) ResponseHandler(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
if r.Response.BufferLength() > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
contentType := getContentType(r)
|
||||
if contentType == xjpubconsts.HTTPContentTypeExcel {
|
||||
r.Response.Status = http.StatusOK
|
||||
return
|
||||
}
|
||||
// g.Log().Infof(r.GetCtx(), "sMiddleware.ResponseHandler,contentType %v", contentType)
|
||||
err := r.GetError()
|
||||
res := r.GetHandlerResponse()
|
||||
var code gcode.Code = gcode.CodeOK
|
||||
|
||||
if err != nil {
|
||||
code = gerror.Code(err)
|
||||
if code == gcode.CodeNil {
|
||||
code = gcode.CodeInternalError
|
||||
}
|
||||
response.JsonExit(r, code.Code(), err.Error())
|
||||
} else {
|
||||
response.Json(r, code.Code(), "", res)
|
||||
}
|
||||
}
|
||||
|
||||
// CORS 跨域处理
|
||||
func (s *sMiddleware) CORS(r *ghttp.Request) {
|
||||
r.SetCtx(r.GetNeverDoneCtx())
|
||||
|
||||
corsOptions := r.Response.DefaultCORSOptions()
|
||||
corsConfig := g.Cfg().MustGet(context.Background(), "server.allowedDomains").Strings()
|
||||
if len(corsConfig) == 0 {
|
||||
r.Response.CORSDefault()
|
||||
} else {
|
||||
corsOptions.AllowDomain = corsConfig
|
||||
r.Response.CORS(corsOptions)
|
||||
}
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
// IsExceptLogin 判断是否需要验证登录
|
||||
func (s *sMiddleware) IsExceptLogin(ctx context.Context, path string) bool {
|
||||
pathList := g.Cfg().MustGet(ctx, "router.exceptLogin").Strings()
|
||||
return slices.Contains(pathList, path)
|
||||
}
|
||||
|
||||
// ResponseHandlerRaw 返回处理中间件
|
||||
func (s *sMiddleware) ResponseHandlerRaw(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
// 如果已经有返回内容,那么该中间件什么也不做
|
||||
if r.Response.BufferLength() > 0 {
|
||||
g.Log().Infof(r.Context(), "ResponseHandler r.Response.BufferLength() %d buf:%s", r.Response.BufferLength(), r.Response.BufferString())
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
err = r.GetError()
|
||||
res = r.GetHandlerResponse()
|
||||
)
|
||||
if err != nil {
|
||||
r.Response.WriteJson(res)
|
||||
r.ExitAll()
|
||||
} else {
|
||||
r.Response.WriteJson(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package xjpublogic
|
||||
|
||||
import (
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpublogic/httpclient"
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpublogic/info"
|
||||
_ "git.5iot.com/iotlcm-public/iotlcm-upstream-proxy/internal/pub/xjpublogic/middleware"
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
package xjpubmodel
|
||||
|
||||
type InfoModel struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
Build string `json:"build"`
|
||||
Commit string `json:"commit"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func NewInfoModel() *InfoModel {
|
||||
return &InfoModel{
|
||||
Data: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// package response
|
||||
// @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
|
||||
package response
|
||||
|
||||
type PageResult struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// package response
|
||||
// @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
|
||||
package response
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// 泛型
|
||||
type ResponseGeneric[T any] struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data T `json:"data"`
|
||||
}
|
||||
|
||||
type JsonResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
Error interface{} `json:"error"`
|
||||
}
|
||||
|
||||
func Json(r *ghttp.Request, code int, message string, data ...interface{}) {
|
||||
var responseData interface{}
|
||||
if len(data) > 0 {
|
||||
responseData = data[0]
|
||||
} else {
|
||||
responseData = g.Map{}
|
||||
}
|
||||
// g.Log().Infof(r.GetCtx(), "response.Json: %v", responseData)
|
||||
r.Response.WriteJson(JsonResponse{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Data: responseData,
|
||||
})
|
||||
}
|
||||
|
||||
func JsonExit(r *ghttp.Request, code int, message string, data ...interface{}) {
|
||||
Json(r, code, message, data...)
|
||||
r.ExitAll()
|
||||
}
|
||||
|
||||
// 向前端返回Excel文件 参数 content 为上面生成的io.ReadSeeker, fileTag 为返回前端的文件名
|
||||
func Excel(r *ghttp.Request, content io.ReadSeeker, fileTag string) {
|
||||
fileName := fmt.Sprintf("%s%s%s.xlsx", gtime.Now().Format("Ymdhis"), `_`, fileTag)
|
||||
r.Response.Header().Set("Content-Type", "application/vnd.ms-excel")
|
||||
r.Response.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
|
||||
http.ServeContent(r.Response.Writer, r.Request, fileTag, time.Now(), content)
|
||||
}
|
||||
|
||||
// 向前端返回Json文件 参数 content 为上面生成的io.ReadSeeker, fileTag 为返回前端的文件名
|
||||
func JsonFile(r *ghttp.Request, content io.ReadSeeker, fileTag string) {
|
||||
fileName := fmt.Sprintf("%s%s%s.json", gtime.Now().Format("Ymdhis"), `_`, fileTag)
|
||||
r.Response.Header().Set("Content-Type", "application/json")
|
||||
r.Response.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
|
||||
http.ServeContent(r.Response.Writer, r.Request, fileTag, time.Now(), content)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package xjpubmodel
|
||||
|
||||
type SimKey struct {
|
||||
ChanKey string `json:"chanKey" dc:"通道标识"`
|
||||
ICCID string `json:"iccid" dc:"联网卡集成电路卡识别码20位"`
|
||||
}
|
||||
|
||||
// 物联网卡在线信息实时查询 请求参数
|
||||
type SimSessionInput struct {
|
||||
SimKeys []*SimKey `json:"simKeys" dc:"SIM卡标识列表"`
|
||||
}
|
||||
|
||||
type SimSessionItem struct {
|
||||
*SimKey
|
||||
ApnId string `json:"apnId" dc:"APN ID"`
|
||||
Rat string `json:"rat" dc:"接入方式"`
|
||||
Ipv4 string `json:"ipv4" dc:"IPV4"`
|
||||
Ipv6 string `json:"ipv6" dc:"IPV6"`
|
||||
Ipv6Prefix string `json:"ipv6Prefix" dc:"IPV6前缀"`
|
||||
Status string `json:"status" dc:"状态(0:用户在线 -1:用户不在线 -2:未查询到会话信息)"`
|
||||
CreateTime string `json:"createTime" dc:"创建时间"`
|
||||
ApiStatus int `json:"apiStatus" dc:"API状态"`
|
||||
ApiMessage string `json:"apiMessage" dc:"API消息"`
|
||||
}
|
||||
|
||||
// 物联网卡在线信息实时查询 响应参数
|
||||
type SimSessionOutput struct {
|
||||
Items []*SimSessionItem `json:"items" dc:"SIM卡会话列表"`
|
||||
}
|
||||
|
||||
// 物联网卡卡状态查询 请求参数
|
||||
type SimCardStatusInput struct {
|
||||
SimKeys []*SimKey `json:"simKeys" dc:"SIM卡标识列表"`
|
||||
}
|
||||
|
||||
// 物联网卡卡状态查询 响应参数
|
||||
type SimCardStatusOutput struct {
|
||||
Items []*SimCardStatusItem `json:"items" dc:"SIM卡状态列表"`
|
||||
}
|
||||
|
||||
// {"cardStatus":"2","lastChangeDate":"2024-05-30 22:05:31"}]
|
||||
type SimCardStatusItem struct {
|
||||
*SimKey
|
||||
CardStatus int `json:"cardStatus" dc:"卡状态"`
|
||||
LastChangeDate string `json:"lastChangeDate" dc:"最后变更时间"`
|
||||
ApiStatus int `json:"apiStatus" dc:"API状态"`
|
||||
ApiMessage string `json:"apiMessage" dc:"API消息"`
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package xjpubmodel
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type MetricItem struct {
|
||||
Name string `json:"name"`
|
||||
Value float64 `json:"value"`
|
||||
Time *gtime.Time `json:"time"`
|
||||
}
|
||||
|
||||
func (m *MetricItem) SetValue(value interface{}) {
|
||||
m.Value = gconv.Float64(value)
|
||||
m.Time = gtime.Now()
|
||||
}
|
||||
func (m *MetricItem) GetValue() float64 {
|
||||
return m.Value
|
||||
}
|
||||
func (m *MetricItem) GetTime() *gtime.Time {
|
||||
return m.Time
|
||||
}
|
||||
func (m *MetricItem) GetName() string {
|
||||
return m.Name
|
||||
}
|
||||
func (m *MetricItem) SetName(name string) {
|
||||
m.Name = name
|
||||
}
|
||||
func (m *MetricItem) AddValue(value interface{}) {
|
||||
m.Value += gconv.Float64(value)
|
||||
m.Time = gtime.Now()
|
||||
}
|
||||
func (m *MetricItem) Inc() {
|
||||
m.Value++
|
||||
m.Time = gtime.Now()
|
||||
}
|
||||
func (m *MetricItem) Dec() {
|
||||
m.Value--
|
||||
m.Time = gtime.Now()
|
||||
}
|
||||
|
||||
type MetricData struct {
|
||||
MetricClientCount MetricItem `json:"clientCount"` // 当前在线数
|
||||
MetricConnectedCounter MetricItem `json:"connectedCounter"` // 连接数
|
||||
MetricDisconnectedCounter MetricItem `json:"disconnectedCounter"` // 断开连接数
|
||||
MetricRecvPkgCount MetricItem `json:"recvPkgCount"` // 接收包数
|
||||
MetricSendPkgCount MetricItem `json:"sendPkgCount"` // 发送包数
|
||||
MetricRecvPkgSize MetricItem `json:"recvPkgSize"` // 接收包大小
|
||||
MetricSendPkgSize MetricItem `json:"sendPkgSize"` // 发送包大小
|
||||
MetricRecvPkgTime MetricItem `json:"recvPkgTime"` // 接收包时间(毫秒)
|
||||
MetricSendPkgTime MetricItem `json:"sendPkgTime"` // 发送包时间(毫秒)
|
||||
MetricSubTopicCount MetricItem `json:"subTopicCount"` // 订阅主题数
|
||||
MetricAuthSuccessCount MetricItem `json:"authSuccessCount"` // 认证成功数
|
||||
MetricAuthFailCount MetricItem `json:"authFailCount"` // 认证失败数
|
||||
MetricAuthCostTime MetricItem `json:"authCostTime"` // 认证耗时
|
||||
MetricUpMsgConnectCostTime MetricItem `json:"upMsgConnectCostTime"` // 上行消息连接耗时(毫秒)
|
||||
MetricUpMsgDataCostTime MetricItem `json:"upMsgDataCostTime"` // 上行消息数据耗时(毫秒)
|
||||
MetricUpMsgDisconnectCostTime MetricItem `json:"upMsgDisconnectCostTime"` // 上行消息断开连接耗时(毫秒)
|
||||
MetricTopicCount MetricItem `json:"topicCount"` // 累计主题数
|
||||
MetricProcessMemSize MetricItem `json:"processMemSize"` // 进程内存大小
|
||||
MetricProcessCpuUsage MetricItem `json:"processCpuUsage"` // 进程CPU使用率
|
||||
MetricProcessThreads MetricItem `json:"processThreads"` // 进程线程数
|
||||
MetricProcessGoroutines MetricItem `json:"processGoroutines"` // 进程协程数
|
||||
MetricSysCpuNum MetricItem `json:"sysCpuNum"` // 系统CPU数量
|
||||
MetricSysCpuCores MetricItem `json:"sysCpuCores"` // 系统CPU核数
|
||||
MetricSysCpuUsage MetricItem `json:"sysCpuUsage"` // 系统CPU使用率
|
||||
MetricSysCpuLoad1 MetricItem `json:"sysCpuLoad1"` // 系统CPU负载1
|
||||
MetricSysCpuLoad5 MetricItem `json:"sysCpuLoad5"` // 系统CPU负载2
|
||||
MetricSysCpuLoad15 MetricItem `json:"sysCpuLoad15"` // 系统CPU负载3
|
||||
MetricSysMemTotal MetricItem `json:"sysMemTotal"` // 系统内存总量
|
||||
MetricSysMemUsage MetricItem `json:"sysMemUsage"` // 系统内存使用率
|
||||
MetricSysDiskTotal MetricItem `json:"sysDiskTotal"` // 系统磁盘总量
|
||||
MetricSysDiskUsage MetricItem `json:"sysDiskUsage"` // 系统磁盘使用率
|
||||
MetricWaitMsgCount MetricItem `json:"waitMsgCount"` // 等待消息数量
|
||||
MetricOneDeviceWaitMsgCount MetricItem `json:"oneDeviceWaitMsgCount"` // 同一个设备等待消息数量
|
||||
MetricRecvMsgFailCount MetricItem `json:"recvMsgFailCount"` // 接收消息处理失败数
|
||||
MetricRecvMsgWaitCostTime MetricItem `json:"recvMsgWaitCostTime"` // 接收消息等待耗时
|
||||
}
|
||||
type XjServerInfo struct {
|
||||
NodeName string `json:"nodeName"`
|
||||
SvrType int `json:"svrType"`
|
||||
SvrCode string `json:"svrCode"` // 服务器编号
|
||||
ShardId int64 `json:"shardId"` // 分片ID
|
||||
StartTime *gtime.Time `json:"startTime"` // 启动时间
|
||||
SysIpLan string `json:"sysIpLan"` // 内网IP
|
||||
SysIpWan string `json:"sysIpWan"` // 外网IP
|
||||
AppVersion string `json:"appVersion"` // 程序版本
|
||||
TenantId string `json:"tenantId"` // 租户ID
|
||||
ReportInterval int64 `json:"reportInterval"` // 上报间隔
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user