Compare commits

...

16 Commits

Author SHA1 Message Date
wolter 7f2aceb5a7 Merge remote-tracking branch 'refs/remotes/origin/prod/prod2.1' into dev/dev 2026-07-30 14:39:32 +08:00
wolter 7607a7118c feat:邮储支付代码完善补充缺失逻辑 2026-07-30 14:37:43 +08:00
wolter 80bdf8b00a feat:邮储支付代码完善补充缺失逻辑 2026-07-29 16:47:49 +08:00
renzhiyuan 6f19814aa1 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 16:49:17 +08:00
renzhiyuan d84f870745 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 16:34:13 +08:00
renzhiyuan 1ae0da11e9 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 16:16:28 +08:00
renzhiyuan 8c2c4bfc20 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 16:04:22 +08:00
renzhiyuan 1011e33ea2 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 15:59:11 +08:00
renzhiyuan f0d430473f <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 15:56:43 +08:00
renzhiyuan 18c62257b4 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 15:51:05 +08:00
renzhiyuan f15f96a570 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 15:49:24 +08:00
renzhiyuan d32fc30bfc <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 15:47:53 +08:00
renzhiyuan a30b92ea68 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 15:35:27 +08:00
renzhiyuan c3d5ed9774 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-28 15:26:16 +08:00
wolter a2202ea200 feat:邮储支付 2026-07-28 09:46:02 +08:00
renzhiyuan aa9effcaf4 <feat>修复支付宝网页支付关闭订单问题
已关闭订单收到支付成功回调加入异常订单
2026-07-16 11:30:47 +08:00
37 changed files with 2493 additions and 264 deletions

443
README.md
View File

@ -1,74 +1,393 @@
## Snow
Snow是一套简单易用的Go语言业务框架整体逻辑设计简洁支持HTTP服务、队列调度和任务调度等常用业务场景模式。
# PaymentCenter 支付中心
## Quick start
一个基于 Go + Gin 的统一支付网关系统,为商户提供下单、退款、查询、收银台等支付能力,底层对接微信支付、支付宝等第三方支付平台。
### Build
sh build/shell/build.sh
> 代码位置:后端接口位于 `app/`,收银台页面模板位于 `front/templates/`
### Run
```shell
1. build/bin/snow -a api #启动Api服务
2. build/bin/snow -a cron #启动Cron定时任务服务
3. build/bin/snow -a job #启动队列调度服务
4. build/bin/snow -a command -m test #执行名称为test的脚本任务
---
## 1. 技术栈
| 组件 | 选型 |
|------|------|
| 语言 | Go |
| Web 框架 | [Gin](https://github.com/gin-gonic/gin) |
| ORM | [xorm](https://xorm.io/) |
| 第三方支付 | [go-pay](https://github.com/go-pay/gopay) |
| JSON | [bytedance/sonic](https://github.com/bytedance/sonic) |
| 参数校验 | go-playground/validator.v9 |
| 缓存/分布式锁 | Redissnow-core/redis |
| 数据库 | MySQL |
| 加密算法 | RSA / SM2 / SM4 / AES / DES3 |
---
## 2. 目录结构
```
PaymentCenter/
├── app/
│ ├── constants/ # 常量定义错误码、公共枚举、pojo
│ │ ├── common/common.go # 订单状态、支付渠道、路由前缀
│ │ └── errorcode/ # 错误码与中文消息
│ ├── http/
│ │ ├── routes/route.go # 路由注册入口
│ │ ├── requestmapping/ # 路由→请求结构体映射
│ │ ├── middlewares/ # 中间件CORS、鉴权、加解密、参数校验
│ │ ├── controllers/
│ │ │ ├── base.go # 公共Success/Error/GenRequest/ApiRes
│ │ │ ├── front/ # C 端:支付 API、收银台、回调
│ │ │ └── backend/ # 管理后台
│ │ └── entities/ # 请求/响应结构体
│ ├── services/
│ │ ├── api_request_valid.go # App 校验 & IP 白名单
│ │ ├── order.go # 订单 CRUD & 状态检查
│ │ ├── pay_page.go # 收银台渠道列表、订单状态检查
│ │ ├── apicrypt/ # RSA/SM2/SM4 加解密实现
│ │ └── thirdpay/ # 第三方支付业务封装
│ │ ├── pay.go # 下单/退款/关闭主流程
│ │ ├── pay_page.go # 收银台业务V2 预下单、查询
│ │ ├── pay_query.go # 三方查询
│ │ ├── do/ # 渠道策略层PayCheck、Pay、PayWay 映射)
│ │ └── thirdpay_notify/ # 回调异步通知处理
│ ├── third/paymentService/ # go-pay 封装(微信/支付宝底层调用)
│ ├── models/ # xorm 实体orders、app、merchant、pay_channel…
│ ├── data/ # Repository 层OrderRepo、PayChannelRepo 等)
│ ├── utils/ # snowflake、JWT、HTTP client、useragent、DES
│ │ └── encrypt/ # AES、RSA、SM2、SM4
│ ├── caches/ # 缓存
│ └── mq/ # 消息队列
└── front/
└── templates/
├── payPage.html # 收银台主页面
├── payTemplateDefault.html # 渠道跳转模板
├── success.html # 支付成功JSAPI 场景)
└── fail.html # 支付失败
```
## Documents
---
- [项目地址](https://github.com/qit-team/snow)
- [中文文档](https://github.com/qit-team/snow/wiki)
- [changelog](https://github.com/qit-team/snow/blob/master/CHANGLOG.md)
- [xorm](http://gobook.io/read/github.com/go-xorm/manual-zh-CN/)
## 3. 架构分层与调用链
##
<!--
```
Gin 路由
MiddlewareCORS → ValidateRequest / ValidatePayRequest → 加解密)
Controllerfront/ 或 backend/
services/(业务编排 + services/thirdpay/
services/thirdpay/do/PayCheck → Pay → PayWay 策略)
third/paymentService/go-pay 底层调用)→ 微信 / 支付宝
data/Repository→ models/xorm ORM→ MySQL
```
// validator的示例
// HandleTestValidator godoc
// @Summary HandleTestValidator的示例
// @Description HandleTestValidator的示例
// @Tags snow
// @Accept json
// @Produce json
// @Param testValidator body entities.TestValidatorRequest true "example of validator"
// @Success 200 {array} entities.TestValidatorRequest
// @Failure 400 {object} controllers.HTTPError
// @Failure 404 {object} controllers.HTTPError
// @Failure 500 {object} controllers.HTTPError
// @Router /test_validator [post]
func HandleTestValidator(c *gin.Context) {
request := new(entities.TestValidatorRequest)
err := GenRequest(c, request)
if err != nil {
Error(c, errorcode.ParamError)
return
}
- **控制器层**:只做 HTTP 层的事(绑定请求、调用 service、封装返回
- **服务层**:核心业务(状态机、幂等、分布式锁、渠道路由)
- **Repositorydata/**:只做数据库 CRUD不包含业务逻辑
Success(c, request)
return
---
## 4. C 端接口清单
> 接口前缀:`/pay/front/api/v1` 或 `/pay/front/api/v2`
| 方法 | 路由 | 中间件 | 功能 |
|------|------|--------|------|
| POST | `/notify/wx/:payChannelId` | - | 微信支付回调 |
| POST | `/notify/ali/:payChannelId` | - | 支付宝支付回调 |
| POST | `/pay/url` (V1) | ValidatePayRequest | 下单,同步返回支付 URL / JsInfo |
| POST | `/pay/url` (V2) | ValidatePayRequest | 预下单,仅创建订单,返回收银台 URL |
| POST | `/pay/refund` | ValidatePayRequest | 退款 |
| POST | `/pay/query` | ValidatePayRequest | 查询订单状态 |
| POST | `/pay/close` | ValidatePayRequest | 关闭订单 |
| GET | `/payPage?no={id}` | - | 收银台 HTML 页面入口 |
| POST | `/payPage/list` | ValidateRequest | 获取可用支付渠道列表 |
| GET | `/payPage/submit` | ValidateRequest | 获取支付跳转链接(渲染 payTemplateDefault.html|
| POST | `/payPage/query` | - | 收银台页面轮询订单状态 |
| POST | `/ali/getOauth` | ValidateRequest | 支付宝小程序获取 openId |
| POST/GET | `/wx/*` | ValidateRequest | 微信授权 / openId / JSAPI / 小程序支付 |
- 路由定义参见 [app/http/routes/route.go](file:///e:/goproject/goproject/PaymentCenter/app/http/routes/route.go)
- 路由→结构体映射参见 [app/http/requestmapping/front.go](file:///e:/goproject/goproject/PaymentCenter/app/http/requestmapping/front.go)
---
## 5. 两种下单模式
### 5.1 模式一V1 直接下单(`POST /pay/front/api/v1/pay/url`
适用于商户自己管理收银台页面:
1. 商户构造请求 `RequestBody{ app_id, timestamp, data, key }`,加密后发起
2. 中间件 `ValidatePayRequest()`:查 App 配置 → 解密 → 反序列化为 `PayReqs`
3. 控制器调用 `thirdpay.ThirdPayInfoCheck()``thirdpay.ThirdPayUrl()`
4. 同步返回 `ApiResponse{ Order, Url, JsInfo }`
### 5.2 模式二V2 预下单 + 收银台(推荐)
适用于商户跳转至我方收银台页面:
1. 商户调用 `POST /pay/front/api/v2/pay/url`
2. `PayUrlV2Service()`
- Redis 分布式锁(`payUrl:{out_trade_no}`3 秒)
- 检查商户是否有可用支付渠道
- 按 `out_trade_no + app_id` 查询订单;不存在则新建订单(状态 WAITPAY
- 返回收银台 URL`https://pay-host/pay/front/api/v1/payPage?no={orders.id}`
3. 商户将用户浏览器跳转到收银台
4. **收银台页面**`payPage.html`
- 读取 URL 参数 `no`**订单自增 ID不是 out_trade_no**
- `POST /payPage/list?id=xxx` 拉取渠道列表
- 单渠道直接跳转 `/payPage/submit`,多渠道让用户选择
- 选择后跳转到第三方支付页面
- 支付完成后轮询 `/payPage/query`,成功后跳转到商户 `return_url`
---
## 6. 收银台页面流程
```
商户后台
│ POST /v2/pay/url ─────┐
│ ▼
│ 支付中心创建订单
│ │
│ ▼
│ 返回 payPage?no={orderId}
└── 用户浏览器 ───► GET payPage.html
├── JS 调 POST /payPage/list 获取渠道
├── GET /payPage/submit 获取跳转链接
│ └──► payTemplateDefault.html window.location
├── POST /payPage/query 轮询订单状态
└── 支付成功 → 跳转 return_url
```
页面文件:
- [payPage.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/payPage.html) — 收银台主页(含加载态、渠道选择、状态确认弹窗)
- [payTemplateDefault.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/payTemplateDefault.html) — 第三方支付跳转
- [success.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/success.html) — 微信 JSAPI 成功
- [fail.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/fail.html) — 支付失败
前端注意:`payPage.html` 中的 `API_BASE_URL` 默认写死为 `http://localhost:7081`,部署时需要替换为生产地址。
---
## 7. 请求加解密体系
### 7.1 两个核心中间件
| 中间件 | 路由 | 说明 |
|--------|------|------|
| `ValidateRequest()` | 收银台列表、授权、小程序等 | 普通参数解析form/json+ validator 校验 + 可选日志 |
| `ValidatePayRequest()` | `/pay/url`、`/pay/refund`、`/pay/query`、`/pay/close` | 支付专用:`app_id` 查表 → 按 `key_type` 解密 data → 二次解析校验 |
中间件代码:[app/http/middlewares/base.go](file:///e:/goproject/goproject/PaymentCenter/app/http/middlewares/base.go)
### 7.2 支付请求结构(加密封装)
```
{
"app_id": 123, // 应用 ID查表得 KeyType
"timestamp": 1700000000, // 时间戳
"data": "...", // 真实业务参数的密文PayReqs JSON → 加密 → Base64
"key": "..." // 部分算法所需对称密钥密文
}
```
// Address houses a users address information
type Address struct {
Street string `json:"street" validate:"required" example:"huandaodonglu"`
City string `json:"city" validate:"required" example:"xiamen"`
Planet string `json:"planet" validate:"required" example:"snow"`
Phone string `json:"phone" validate:"required" example:"snow"`
}
解密后 `data` 对应的业务结构,在 `requestmapping.FrontRequestMap` 中按路由映射。
// 请求数据结构
type TestValidatorRequest struct {
//tips因为组件required不管是没传值或者传 0 or "" 都通过不了但是如果用指针类型那么0就是0而nil无法通过校验
Id *int64 `json:"id" validate:"required" example:"1"`
Age int `json:"age" validate:"required,gte=0,lte=130" example:"20"`
Name *string `json:"name" validate:"required" example:"snow"`
Email string `json:"email" validate:"required,email" example:"snow@github.com"`
Url string `json:"url" validate:"required" example:"github.com/qit-team/snow"`
Mobile string `json:"mobile" validate:"required" example:"snow"`
RangeNum int `json:"range_num" validate:"max=10,min=1" example:"3"`
TestNum *int `json:"test_num" validate:"required,oneof=5 7 9" example:"7"`
Content *string `json:"content" example:"snow"`
Addresses []*Address `json:"addresses" validate:"required,dive,required" `
}
-->
### 7.3 加密算法(由 `app.key_type` 决定)
| 类型 | 实现文件 |
|------|---------|
| NO_CRYPT | 明文(不加密) |
| RSA | [services/apicrypt/rsa.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/rsa.go) |
| SM2 | [services/apicrypt/sm2.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/sm2.go) |
| SM4 | [services/apicrypt/sm4.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/sm4.go) |
注册处:[services/apicrypt/types.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/types.go) 中的 `ApiCryptMap`
### 7.4 响应加密
- 非生产环境:`controllers.Success/Error` 直接返回 `{ code, message, data }` JSON
- 生产环境(`config.GetConf().Env == "production"`):整体 JSON 用 DES3 + Base64 加密后以纯文本返回
- 对应方法:`controllers.EncriptJson()`
---
## 8. 订单模型 & 状态机
### 8.1 Orders 表
字段定义:[app/models/ordersmodel/orders.go](file:///e:/goproject/goproject/PaymentCenter/app/models/ordersmodel/orders.go)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | int64 | 主键snowflake 生成 |
| merchant_id | int64 | 商户 |
| pay_channel_id | int64 | 支付渠道实例 |
| app_id | int64 | 应用 |
| out_trade_no | string(50) | 外部/商户订单号 |
| order_type | tinyint | 1=支付, 2=退款 |
| refund_order_id | int64 | 退款关联的原订单 |
| amount | int | 订单金额,单位:**分** |
| actual_amount | int | 实际金额,单位:**分** |
| payer_total | int | 付款方金额,单位:**分** |
| ext_json | string(1024) | 扩展 JSON |
| desc | string(100) | 商品描述 |
| status | tinyint | 订单状态(见下) |
| create_time / update_time | datetime | 自动维护 |
### 8.2 订单状态(`constants/common/common.go`
| 常量 | 值 | 说明 |
|------|----|------|
| ORDER_STATUS_WAITPAY | 1 | 待支付(刚创建) |
| ORDER_STATUS_PAYING | 2 | 支付中(已调第三方下单) |
| ORDER_STATUS_PAYED | 3 | 支付成功 |
| ORDER_STATUS_FAILED | 4 | 支付失败 |
| ORDER_STATUS_CLOSE | 5 | 已关闭 |
### 8.3 状态流转
```
WAITPAY(1) ──► PAYING(2) ──┬──► PAYED(3)
│ │
└─────► CLOSE(5) └──► FAILED(4)
```
状态检查方法:`services.OrderStatusCheck(order)`,位置 [app/services/pay_page.go](file:///e:/goproject/goproject/PaymentCenter/app/services/pay_page.go#L89-L103)
---
## 9. 支付渠道体系
### 9.1 渠道类型枚举
定义在 `constants/common/common.go`
| 常量 | 值 | 含义 |
|------|----|------|
| PAY_CHANNEL_WECHAT_JSAPI | 1 | 微信公众号 JSAPI |
| PAY_CHANNEL_WECHAT_H5 | 2 | 微信 H5 |
| PAY_CHANNEL_WECHAT_APP | 3 | 微信 APP |
| PAY_CHANNEL_WECHAT_NATIVE | 4 | 微信 Native 扫码 |
| PAY_CHANNEL_WECHAT_MINI | 5 | 微信小程序 |
| PAY_CHANNEL_ALIPAY_WEB | 6 | 支付宝网页/移动应用 |
| PAY_CHANNEL_ALIPAY_MINI | 7 | 支付宝小程序 |
| PAY_CHANNEL_ALIPAY_JSAPI | 8 | 支付宝 JSAPI |
| PAY_CHANNEL_ALIPAY_PC | 9 | 支付宝 PC 网站 |
### 9.2 策略映射(渠道 → 实现方法)
- 下单:`services/thirdpay/do/pay_way.go` 的 `PayWayList[channelType]`
- 退款:`services/thirdpay/do/refund_way.go` 的 `RefundWayList[channelType]`
- 底层统一入口:`third/paymentService/payment_service.go` 的 `PaymentService(ctx, req)`
- 根据 `req.ChannelType` 路由到 `AliPayService()``WechatPayService()`
### 9.3 客户端环境 → 可用渠道
- 微信浏览器内 → JSAPI需要 openId收银台会自动先走授权
- PC 浏览器 → 微信 Native、支付宝 PC
- 手机浏览器(非微信内)→ 微信 H5、支付宝 Web
实现:`services.PayPageChannelList()` + `services.ClientEnvCheck(ua)`
---
## 10. 新增功能的操作清单
### 10.1 新增一个 C 端 API
1. 在 `app/http/entities/front/` 定义 Request/Response 结构体
2. 在 `app/http/requestmapping/front.go` 的两个 map 中添加路由 → 结构体映射
3. 在 `app/http/routes/route.go` 注册路由,挂上合适的中间件
4. 在 `app/http/controllers/front/` 对应文件新增 handler`controllers.GetRequest(c).(*front.XXX)` 取参数)
5. 在 `app/services/``app/services/thirdpay/` 实现业务逻辑
### 10.2 新增一个支付渠道
1. 在 `constants/common/common.go` 增加 `PAY_CHANNEL_XXX` 常量和 `PayChannelName`/`PayChannelList` 条目
2. 在 `services/thirdpay/do/pay_way.go``PayWayList` 注册实现方法
3. 在 `third/paymentService/wechat_service.go``ali_service.go` 增加对应分支
4. 若需区分客户端环境,更新 `OpenInPayChannelMap`
### 10.3 新增一个页面模板
1. 在 `front/templates/` 下新增 `.html`
2. 路由里通过 `c.HTML(http.StatusOK, "文件名.html", gin.H{...})` 渲染
3. `router.LoadHTMLGlob("./front/templates/*")` 已在 routes 中注册
### 10.4 新增一个错误码
1. 在 `constants/errorcode/error_code.go` 定义 const并在 `ErrCodeMap` 注册中文消息
2. 使用:`controllers.Error(c, errorcode.XXX)` 或 `controllers.ApiRes(c, nil, code)`
### 10.5 新增数据模型 / Repository
1. 在 `app/models/xxxmodel/` 定义结构体xorm tag + TableName + GetInstance 单例)
2. 在 `app/data/` 新增 `XxxRepo` 封装 xorm 操作(推荐配合 `builder.Cond` 拼装条件)
3. 在 `app/services/` 新增 `XxxFindOne` / `XxxList` 等服务方法
---
## 11. 编码规范与注意事项
- **金额单位**:全链路使用 **分**int前端展示时 `/100` 转元;不得出现 float64 金额
- **订单 ID vs out_trade_no**
- `orders.id` = 雪花自增 ID支付中心内部、收银台查询使用
- `out_trade_no` = 商户外部订单号(商户下单、查询使用)
- **不要混用**
- **幂等性**V2 下单通过 Redis 分布式锁key=`payUrl:{out_trade_no}`3 秒)+ 数据库 `(out_trade_no, app_id)` 唯一约束保证
- **中间件选型**
- 加密支付接口 → `ValidatePayRequest()`
- 收银台、授权、小程序等 → `ValidateRequest()`
- 回调接口 → 直接在 controller 解析(走第三方验签)
- **统一返回**`controllers.Success/Error/ApiRes/HandCodeRes`,不要手写 JSON
- **错误码来源**`constants/errorcode/error_code.go`,不要硬编码数字
- **日志**`utils.Log(ctx, tag, ...)`;支付链路关键节点必须有日志
- **单元测试**工具类、加解密、snowflake 等均有 `_test.go`,新工具函数建议配套
---
## 12. 关键文件速查
| 功能 | 文件 |
|------|------|
| 路由注册 | [app/http/routes/route.go](file:///e:/goproject/goproject/PaymentCenter/app/http/routes/route.go) |
| 路由→结构体映射 | [app/http/requestmapping/front.go](file:///e:/goproject/goproject/PaymentCenter/app/http/requestmapping/front.go) |
| 中间件 | [app/http/middlewares/base.go](file:///e:/goproject/goproject/PaymentCenter/app/http/middlewares/base.go) |
| 公共返回/参数解析 | [app/http/controllers/base.go](file:///e:/goproject/goproject/PaymentCenter/app/http/controllers/base.go) |
| 支付接口 controller | [app/http/controllers/front/api.go](file:///e:/goproject/goproject/PaymentCenter/app/http/controllers/front/api.go) |
| 收银台 controller | [app/http/controllers/front/pay_page.go](file:///e:/goproject/goproject/PaymentCenter/app/http/controllers/front/pay_page.go) |
| 回调/微信/支付宝 controller | [app/http/controllers/front/payment_controller.go](file:///e:/goproject/goproject/PaymentCenter/app/http/controllers/front/payment_controller.go) |
| 请求结构体 | [app/http/entities/front/pay.go](file:///e:/goproject/goproject/PaymentCenter/app/http/entities/front/pay.go) |
| 订单服务 | [app/services/order.go](file:///e:/goproject/goproject/PaymentCenter/app/services/order.go) |
| 收银台服务(渠道列表/状态检查) | [app/services/pay_page.go](file:///e:/goproject/goproject/PaymentCenter/app/services/pay_page.go) |
| App 校验 | [app/services/api_request_valid.go](file:///e:/goproject/goproject/PaymentCenter/app/services/api_request_valid.go) |
| 第三方支付主流程 | [app/services/thirdpay/pay.go](file:///e:/goproject/goproject/PaymentCenter/app/services/thirdpay/pay.go) |
| 收银台/V2 下单 | [app/services/thirdpay/pay_page.go](file:///e:/goproject/goproject/PaymentCenter/app/services/thirdpay/pay_page.go) |
| 加解密类型注册 | [app/services/apicrypt/types.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/types.go) |
| 错误码 | [app/constants/errorcode/error_code.go](file:///e:/goproject/goproject/PaymentCenter/app/constants/errorcode/error_code.go) |
| 公共常量 | [app/constants/common/common.go](file:///e:/goproject/goproject/PaymentCenter/app/constants/common/common.go) |
| Orders 模型 | [app/models/ordersmodel/orders.go](file:///e:/goproject/goproject/PaymentCenter/app/models/ordersmodel/orders.go) |
| Order Repository | [app/data/orders.go](file:///e:/goproject/goproject/PaymentCenter/app/data/orders.go) |
| 底层 go-pay 调用入口 | app/third/paymentService/payment_service.go |
| 收银台页面 | [front/templates/payPage.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/payPage.html) |
| 跳转模板 | [front/templates/payTemplateDefault.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/payTemplateDefault.html) |
| 雪花 ID 生成 | [app/utils/snowflake/snow_flake.go](file:///e:/goproject/goproject/PaymentCenter/app/utils/snowflake/snow_flake.go) |

View File

@ -21,6 +21,7 @@ const (
PAY_CHANNEL_ALIPAY_MINI = 7
PAY_CHANNEL_ALIPAY_JSAPI = 8
PAY_CHANNEL_ALIPAY_PC = 9
PAY_CHANNEL_PSBC = 11
// 统一登陆信息
ADMIN_USER_ID = "User-Id"
@ -43,6 +44,7 @@ const (
PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信
PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝
PAY_CHANNLE_TYPE_PSBC = 3 // 支付类型:邮储
THIRD_ORDER_TYPE_PAY = 1 // 发起支付
THIRD_ORDER_TYPE_ORDER_QUERY = 2 // 查询订单
@ -66,6 +68,7 @@ var PayChannelName = map[int]string{
PAY_CHANNEL_ALIPAY_MINI: "支付宝支付",
PAY_CHANNEL_ALIPAY_JSAPI: "支付宝支付",
PAY_CHANNEL_ALIPAY_PC: "支付宝支付",
PAY_CHANNEL_PSBC: "邮储支付",
}
var PayChannelList = map[int]string{
@ -77,6 +80,7 @@ var PayChannelList = map[int]string{
PAY_CHANNEL_ALIPAY_WEB: "支付宝网页&移动应用",
PAY_CHANNEL_ALIPAY_MINI: "支付宝小程序",
PAY_CHANNEL_ALIPAY_JSAPI: "支付宝JSAPI",
PAY_CHANNEL_PSBC: "邮储JSAPI",
}
var OrderTypeList = map[int]string{
@ -102,6 +106,6 @@ const (
// 客户端环境和支付渠道的映射关系
var OpenInPayChannelMap = map[int][]int{
OpenInWeChat: {PAY_CHANNEL_WECHAT_JSAPI},
OpenInMobile: {PAY_CHANNEL_WECHAT_H5, PAY_CHANNEL_ALIPAY_WEB},
OpenInWindows: {PAY_CHANNEL_WECHAT_NATIVE, PAY_CHANNEL_ALIPAY_PC},
OpenInMobile: {PAY_CHANNEL_WECHAT_H5, PAY_CHANNEL_ALIPAY_WEB, PAY_CHANNEL_PSBC},
OpenInWindows: {PAY_CHANNEL_WECHAT_NATIVE, PAY_CHANNEL_ALIPAY_PC, PAY_CHANNEL_PSBC},
}

View File

@ -0,0 +1,40 @@
package data
import (
"PaymentCenter/app/models/orderexceptionmodel"
"xorm.io/xorm"
)
type OrderExceptionRepo struct {
repo xorm.Interface
}
func NewOrderExceptionRepo(repo xorm.Interface) *OrderExceptionRepo {
return &OrderExceptionRepo{
repo: repo,
}
}
func (m *OrderExceptionRepo) InsertOne(orderException *orderexceptionmodel.OrderException) (int64, error) {
return m.repo.InsertOne(orderException)
}
type Exception int
const (
OrderStatusOverButPaySuccess Exception = 1
)
func (e Exception) GetDesc() string {
return ExceptionOrderStatusOverButPayFailMap[e]
}
func (e Exception) ToInt() int {
return int(e)
}
var ExceptionOrderStatusOverButPayFailMap = map[Exception]string{
OrderStatusOverButPaySuccess: "订单状态为终态但是收到支付成功的消息",
}

View File

@ -7,6 +7,7 @@ import (
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/services"
"PaymentCenter/app/services/thirdpay"
"github.com/gin-gonic/gin"
"xorm.io/builder"
)
@ -27,6 +28,16 @@ func PayUrl(c *gin.Context) {
controllers.ApiRes(c, nil, check.CheckCode)
return
}
// 关闭关联订单
if len(check.Reqs.CloseOutTradeNo) != 0 {
check.CloseOrderWithOutTradeNo(check.Reqs.CloseOutTradeNo)
if check.CheckCode != errorcode.Success {
controllers.ApiRes(c, nil, check.CheckCode)
return
}
}
pay := thirdpay.ThirdPayUrl(check)
if pay.PayCode != errorcode.Success {
controllers.ApiRes(c, nil, pay.PayCode, pay.ThirdMsg)
@ -35,6 +46,7 @@ func PayUrl(c *gin.Context) {
res.Order = thirdpay.NewOrdersResp(pay.Order)
res.Url = pay.Url
res.ThirdMsg = pay.ThirdMsg
res.JsInfo = pay.JsApiInfo
controllers.ApiRes(c, res, pay.PayCode)
return

View File

@ -0,0 +1,111 @@
package front
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/models/paychannelmodel"
"PaymentCenter/app/services"
"PaymentCenter/app/services/thirdpay/thirdpay_notify"
"PaymentCenter/app/third/paymentService"
"fmt"
"github.com/gin-gonic/gin"
"github.com/goccy/go-json"
"github.com/qit-team/snow-core/log/logger"
"io"
"net/http"
"strconv"
)
// PsbcCallback 邮储支付回调
func PsbcCallback(c *gin.Context) {
logger.Info(c, "PsbcCallback-回调数据", c.Request)
payChannelId := c.Param("payChannelId")
logger.Info(c, "PsbcCallback-回调数据payChannelId", payChannelId)
if payChannelId == "" {
c.String(http.StatusBadRequest, "%s", "fail")
return
}
body, err := io.ReadAll(c.Request.Body)
if err != nil {
logger.Error(c, "PsbcCallback-读取请求体失败", err.Error())
c.String(http.StatusBadRequest, "%s", "fail")
return
}
bodyStr := string(body)
logger.Info(c, "PsbcCallback-回调数据body", bodyStr)
var payChannelModel paychannelmodel.PayChannel
payChannelIdInt, _ := strconv.Atoi(payChannelId)
payChannelModel.Id = int64(payChannelIdInt)
code := services.PayChannelGet(&payChannelModel)
if code == errorcode.PayChannelNotFound {
logger.Error(c, "PsbcCallback-回调数据未获取到支付配置404")
c.String(http.StatusBadRequest, "%s", "fail")
return
}
var psbcConfig paymentService.PsbcPay
err = json.Unmarshal([]byte(payChannelModel.ExtJson), &psbcConfig)
if err != nil {
logger.Error(c, "PsbcCallback-回调数据解析支付配置错误", fmt.Sprintf("错误原因:%s", err.Error()))
c.String(http.StatusBadRequest, "%s", "fail")
return
}
if psbcConfig.MchtNo == "" || psbcConfig.PrivateKey == "" || psbcConfig.BankKey == "" {
logger.Error(c, "PsbcCallback-回调数据解析支付配置错误,解析出来的信息为空")
c.String(http.StatusBadRequest, "%s", "fail")
return
}
psbcConfig.AppID = payChannelModel.AppId
orderId, amountTotal, payerTotal, status, err := paymentService.PsbcVerifyAndParseNotify(bodyStr, psbcConfig)
if err != nil {
logger.Error(c, "PsbcCallback-回调数据验签失败", err.Error())
c.String(http.StatusBadRequest, "%s", "fail")
return
}
logger.Info(c, "PsbcCallback-解析邮储回调结果", fmt.Sprintf("orderId:%d, amountTotal:%d, payerTotal:%d, status:%s", orderId, amountTotal, payerTotal, status))
var orderStatus int
var errCode int
var msg string
switch status {
case "SUCCESS":
orderStatus = common.ORDER_STATUS_PAYED
errCode = errorcode.Success
msg = "支付成功"
case "FAIL":
orderStatus = common.ORDER_STATUS_FAILED
errCode = errorcode.ParamError
msg = "支付失败"
default:
logger.Error(c, "PsbcCallback-订单状态异常", status)
c.String(http.StatusBadRequest, "%s", "fail")
return
}
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderId, errCode, orderStatus, int(amountTotal), int(payerTotal), msg)
notifyResultJson, _ := json.Marshal(notifyResult)
go func() {
payCallback := bodyStr
payParam := "{}"
merchantCallback := string(notifyResultJson)
logStatus := common.THIRD_ORDER_LOG_STATUS_SUCCESS
if notifyResult.ErrCode != errorcode.Success {
logStatus = common.THIRD_ORDER_LOG_STATUS_FAIL
}
paymentService.SaveLog(orderId, common.THIRD_ORDER_TYPE_CALL_BACK, payCallback, payParam, merchantCallback, logStatus)
}()
if notifyResult.ErrCode != errorcode.Success {
logger.Error(c, "PsbcCallback-回调执行失败,失败原因:", fmt.Sprintf("%+v", notifyResult))
c.String(http.StatusBadRequest, "%s", "fail")
return
}
c.String(http.StatusOK, "%s", "success")
return
}

View File

@ -28,7 +28,8 @@ type PayCommonReqBody struct {
type PayReqs struct {
PayCommonReqBody
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
CloseOutTradeNo string `json:"close_out_trade_no" label:"关闭外侧商户订单号"`
}
type RefundReqs struct {
@ -61,9 +62,10 @@ type CloseReqs struct {
// api 接口返回数据, 统一返回结构, order数据会进行加密
type ApiResponse struct {
Order interface{} `json:"order,omitempty"`
Url string `json:"url,omitempty"`
JsInfo *WxMiniPayResponse `json:"js_info,omitempty"`
Order interface{} `json:"order,omitempty"`
Url string `json:"url,omitempty"`
ThirdMsg string `json:"third_msg,omitempty"`
JsInfo *WxMiniPayResponse `json:"js_info,omitempty"`
}
type PayChannelListRequest struct {

View File

@ -11,6 +11,7 @@ import (
"PaymentCenter/app/http/trace"
"PaymentCenter/app/utils/metric"
"PaymentCenter/config"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
"github.com/qit-team/snow-core/http/middleware"
@ -57,6 +58,7 @@ func RegisterRoute(router *gin.Engine) {
{
notify.POST("/wx/:payChannelId", front.WxCallback)
notify.POST("/ali/:payChannelId", front.AliCallback)
notify.POST("/psbc/:payChannelId", front.PsbcCallback)
}
pay := v1.Group("/pay", middlewares.ValidatePayRequest())

View File

@ -0,0 +1,45 @@
package orderexceptionmodel
import (
"sync"
"time"
"github.com/qit-team/snow-core/db"
)
var (
once sync.Once
m *OrderExceptionModel
)
// 实体
type OrderException struct {
Id int64
OrderId int64 `xorm:"'order_id' bigint(20)"`
OutTradeNo string `xorm:"'out_trade_no' varchar(50)"`
ExceptionType int `xorm:"'exception_type' TINYINT"`
ExceptionDesc string `xorm:"'exception_desc' varchar(50)"`
CreateTime time.Time `xorm:"'create_time' datetime created"`
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
Status int `xorm:"'status' TINYINT"`
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
}
// 表名
func (m *OrderException) TableName() string {
return "order_exceptions"
}
// 私有化防止被外部new
type OrderExceptionModel struct {
db.Model //组合基础Model集成基础Model的属性和方法
}
// 单例模式
func GetInstance() *OrderExceptionModel {
once.Do(func() {
m = new(OrderExceptionModel)
//m.DiName = "" //设置数据库实例连接默认db.SingletonMain
})
return m
}

View File

@ -1,9 +1,10 @@
package ordersmodel
import (
"github.com/qit-team/snow-core/db"
"sync"
"time"
"github.com/qit-team/snow-core/db"
)
var (
@ -13,22 +14,23 @@ var (
// 实体
type Orders struct {
Id int64
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
PayChannelId int64 `xorm:"'pay_channel_id' bigint(20)"`
AppId int64 `xorm:"'app_id' bigint(20)"`
OutTradeNo string `xorm:"'out_trade_no' varchar(50)"`
OrderType int `xorm:"'order_type' TINYINT"`
RefundOrderId int64 `xorm:"'refund_order_id' bigint(20)"`
Amount int `xorm:"'amount' int(11)"`
ActualAmount int `xorm:"'actual_amount' int(11)"`
PayerTotal int `xorm:"'payer_total' int(11)"`
ExtJson string `xorm:"'ext_json' varchar(1024)"`
Desc string `xorm:"'desc' varchar(100)"`
CreateTime time.Time `xorm:"'create_time' datetime created"`
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
Status int `xorm:"'status' TINYINT"`
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
Id int64
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
PayChannelId int64 `xorm:"'pay_channel_id' bigint(20)"`
AppId int64 `xorm:"'app_id' bigint(20)"`
OutTradeNo string `xorm:"'out_trade_no' varchar(50)"`
OrderType int `xorm:"'order_type' TINYINT"`
RefundOrderId int64 `xorm:"'refund_order_id' bigint(20)"`
Amount int `xorm:"'amount' int(11)"`
ActualAmount int `xorm:"'actual_amount' int(11)"`
PayerTotal int `xorm:"'payer_total' int(11)"`
ExtJson string `xorm:"'ext_json' varchar(1024)"`
Desc string `xorm:"'desc' varchar(100)"`
RelationCloseOutTradeNo string `xorm:"'relation_close_out_trade_no' varchar(50)"`
CreateTime time.Time `xorm:"'create_time' datetime created"`
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
Status int `xorm:"'status' TINYINT"`
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
}
type OrdersBackendList struct {

View File

@ -9,6 +9,7 @@ import (
"PaymentCenter/app/models/merchantmodel"
"PaymentCenter/app/models/paychannelmodel"
"database/sql"
"xorm.io/builder"
)

View File

@ -14,6 +14,7 @@ import (
"net/url"
"strconv"
"time"
"xorm.io/builder"
"PaymentCenter/app/models/ordersmodel"
@ -21,16 +22,17 @@ import (
)
type PayParam struct {
Merchant *merchantmodel.Merchant
Channel *paychannelmodel.PayChannel
App_id int64
OutTradeNo string
Amount int
ExtJson string
Desc string
ClientIp string
ReturnUrl string
OpenId string
Merchant *merchantmodel.Merchant
Channel *paychannelmodel.PayChannel
App_id int64
OutTradeNo string
Amount int
ExtJson string
Desc string
ClientIp string
ReturnUrl string
OpenId string
CloseOutTradeNo string
}
type Pay struct {
@ -48,16 +50,17 @@ func NewPayWithPayCheck(paycheck *PayCheck) *Pay {
return &Pay{
ctx: paycheck.ctx,
PayParam: &PayParam{
Merchant: paycheck.Merchant,
Channel: paycheck.Channel,
App_id: paycheck.Reqs.AppId,
OutTradeNo: paycheck.Reqs.OutTradeNo,
Amount: paycheck.Reqs.Amount,
ExtJson: paycheck.Reqs.ExtJson,
Desc: paycheck.Reqs.Desc,
ClientIp: paycheck.AppCheck.Ip,
ReturnUrl: paycheck.Reqs.ReturnUrl,
OpenId: paycheck.Reqs.OpenId,
Merchant: paycheck.Merchant,
Channel: paycheck.Channel,
App_id: paycheck.Reqs.AppId,
OutTradeNo: paycheck.Reqs.OutTradeNo,
Amount: paycheck.Reqs.Amount,
ExtJson: paycheck.Reqs.ExtJson,
Desc: paycheck.Reqs.Desc,
ClientIp: paycheck.AppCheck.Ip,
ReturnUrl: paycheck.Reqs.ReturnUrl,
OpenId: paycheck.Reqs.OpenId,
CloseOutTradeNo: paycheck.Reqs.CloseOutTradeNo,
},
RelationOrder: paycheck.OldOrder,
PayCode: errorcode.Success,
@ -85,15 +88,16 @@ func (w *Pay) CreateOrder(order_type int) {
}
order := &ordersmodel.Orders{
MerchantId: w.PayParam.Merchant.Id,
PayChannelId: w.PayParam.Channel.Id,
AppId: w.PayParam.App_id,
OutTradeNo: w.PayParam.OutTradeNo,
OrderType: order_type,
Amount: w.PayParam.Amount,
ExtJson: w.PayParam.ExtJson,
Desc: w.PayParam.Desc,
Status: common.ORDER_STATUS_WAITPAY,
MerchantId: w.PayParam.Merchant.Id,
PayChannelId: w.PayParam.Channel.Id,
AppId: w.PayParam.App_id,
OutTradeNo: w.PayParam.OutTradeNo,
OrderType: order_type,
Amount: w.PayParam.Amount,
ExtJson: w.PayParam.ExtJson,
Desc: w.PayParam.Desc,
RelationCloseOutTradeNo: w.PayParam.CloseOutTradeNo,
Status: common.ORDER_STATUS_WAITPAY,
}
if order_type == common.ORDER_TYPE_REFUND {
order.RefundOrderId = w.RelationOrder.Id
@ -179,6 +183,9 @@ func (w *Pay) PayUrl() (url string) {
// 支付宝jsapi支付
res = paymentService.PaymentService(*w.ctx, *thirdPay)
case common.PAY_CHANNEL_PSBC:
res = paymentService.PaymentService(*w.ctx, *thirdPay)
default:
w.PayCode = errorcode.PayChannelNotBuild
return
@ -208,6 +215,9 @@ func (w *Pay) PayUrl() (url string) {
// 获取签名
err = w.JsApiInfo.SignPaySign(thirdPay.Wx.PrivateKey)
}
} else if w.PayParam.Channel.ChannelType == common.PAY_CHANNEL_PSBC {
// 邮储支付返回 handCodePay 参数
w.ThirdMsg = res.Result
} else {
w.Url = res.Result
}

View File

@ -5,6 +5,7 @@ import (
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/services"
"PaymentCenter/app/services/thirdpay/types"
"xorm.io/builder"
"PaymentCenter/app/models/merchantmodel"
@ -84,11 +85,24 @@ func (w *PayCheck) CheckOrderPay() {
if w.OldOrder.Status == common.ORDER_STATUS_PAYING && w.Reqs.PayChannelId != w.OldOrder.PayChannelId {
w.CheckCode = errorcode.OrderPayChannelChange
}
}
return
}
func (w *PayCheck) CloseOrderWithOutTradeNo(OutTradeNum string) {
if len(OutTradeNum) != 0 {
w.GetOldOrder(&types.OrderFindOne{
OutTradeNo: w.Reqs.CloseOutTradeNo,
})
if w.OldOrder.Status == common.ORDER_STATUS_PAYED || w.OldOrder.Status == common.ORDER_STATUS_CLOSE {
w.CheckCode = errorcode.OrderStatusErr
}
}
return
}
func (w *PayCheck) CheckOrderRefund() (order *ordersmodel.Orders) {
// 查询原来的支付单
w.GetOldOrder(&types.OrderFindOne{

View File

@ -15,6 +15,7 @@ var PayWayList = map[int]func(commonPayInfo *paymentService.PayOrderRequest, cha
common.PAY_CHANNEL_WECHAT_JSAPI: WechatJSAPI,
common.PAY_CHANNEL_WECHAT_MINI: WechatJSAPI,
common.PAY_CHANNEL_ALIPAY_JSAPI: AlipayWeb,
common.PAY_CHANNEL_PSBC: Psbc,
}
func WechatH5(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error {
@ -42,3 +43,12 @@ func WechatJSAPI(commonPayInfo *paymentService.PayOrderRequest, channel *paychan
commonPayInfo.Wx.AppId = channel.AppId
return nil
}
func Psbc(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error {
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonPayInfo.Psbc)
if err != nil {
return err
}
commonPayInfo.Psbc.AppID = channel.AppId
return nil
}

View File

@ -13,6 +13,7 @@ var RefundWayList = map[int]func(commonRefundInfo *paymentService.OrderRefundReq
common.PAY_CHANNEL_ALIPAY_PC: AlipayWebRefund,
common.PAY_CHANNEL_WECHAT_JSAPI: WechatJSAPIRefund,
common.PAY_CHANNEL_WECHAT_MINI: WechatJSAPIRefund,
common.PAY_CHANNEL_PSBC: PsbcRefund,
}
func WechatH5Refund(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error {
@ -44,3 +45,13 @@ func WechatJSAPIRefund(commonRefundInfo *paymentService.OrderRefundRequest, chan
commonRefundInfo.Wx.AppId = channel.AppId
return nil
}
func PsbcRefund(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error {
commonRefundInfo.PayChannel = common.PAY_CHANNLE_TYPE_PSBC
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonRefundInfo.Psbc)
if err != nil {
return err
}
commonRefundInfo.Psbc.AppID = channel.AppId
return nil
}

View File

@ -11,6 +11,7 @@ import (
"PaymentCenter/app/services/thirdpay/types"
"PaymentCenter/app/third/paymentService/payCommon"
"context"
"github.com/jinzhu/copier"
)
@ -122,7 +123,11 @@ func ThirdCloseOrder(ctx context.Context, closeReq front.CloseReqs, appCheck *se
// 调用上游关闭订单
client := thirdpay.NewPayWithPayCheck(check)
client.Order = check.OldOrder
client.CloseOrder()
if client.PayParam.Channel.ChannelType != common.PAY_CHANNEL_ALIPAY_WEB {
//阿里云的网页支付,创单和完成支付是同时完成的,没有关单的必要状态,所以直接关闭掉系统内的订单就好了
//在支付成功回调里如果订单状态为关闭,那么这个单需要走退款
client.CloseOrder()
}
code = client.PayCode
message = client.ThirdMsg
// 修改订单状态为已关闭

View File

@ -43,6 +43,12 @@ func OrderQueryAndNotify(ctx context.Context, orderInfo *ordersmodel.OrdersLeftP
AlipayRootCert: ali.AlipayRootCert,
AlipayPublicCert: ali.AlipayPublicCert,
}
case common.PAY_CHANNLE_TYPE_PSBC:
psbc := paymentService.PsbcPay{}
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &psbc)
query.PayChannel = payCommon.PAY_CHANNLE_TYPE_PSBC
psbc.AppID = orderInfo.AppId
query.Psbc = psbc
default:
utils.Log(nil, "查询订单,支付渠道不支持", orderInfo.ChannelType)
return

View File

@ -7,12 +7,15 @@ import (
"PaymentCenter/app/http/entities"
"PaymentCenter/app/models/appmodel"
"PaymentCenter/app/models/ordercallbacklogmodel"
"PaymentCenter/app/models/orderexceptionmodel"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/services"
"PaymentCenter/app/utils"
"PaymentCenter/app/utils/httpclient"
"github.com/bytedance/sonic"
"fmt"
"time"
"github.com/bytedance/sonic"
"xorm.io/builder"
)
@ -83,6 +86,7 @@ func (o *OrderNotify) Handle() (res *OrderNotifyResp) {
if o.Code != errorcode.Success {
return o.NotifyRespFail(o.Code)
}
o.checkApp()
if o.Code != errorcode.Success {
return o.NotifyRespFail(o.Code)
@ -205,16 +209,42 @@ func (o *OrderNotify) checkApp() {
}
func (o *OrderNotify) checkOrder() {
utils.Log(nil, "检查订单状态", o.OrderId)
cond := builder.NewCond()
cond = cond.And(builder.Eq{"id": o.OrderId})
o.order, o.Code = services.OrderFindOne(&ordersmodel.Orders{}, cond)
if o.Code != errorcode.OrdersExist {
if o.Code != errorcode.Success {
utils.Log(nil, "订单状态错误当前查询code", o.Code)
return
}
utils.Log(nil, "收到回调,当前状态", o.order.Status)
switch o.order.Status {
case common.ORDER_STATUS_PAYING:
return
case common.ORDER_STATUS_PAYED:
return
default:
utils.Log(nil, "订单状态异常,加入异常数据表", o.order.Status)
exceptionModel := data.NewOrderExceptionRepo(orderexceptionmodel.GetInstance().GetDb())
_, err := exceptionModel.InsertOne(&orderexceptionmodel.OrderException{
OrderId: o.order.Id,
OutTradeNo: o.order.OutTradeNo,
ExceptionType: data.OrderStatusOverButPaySuccess.ToInt(),
ExceptionDesc: fmt.Sprintf("%s:%s:%d", data.OrderStatusOverButPaySuccess.GetDesc(), "当前状态为", o.order.Status),
CreateTime: time.Now(),
Status: o.order.Status,
})
if o.order.Status != common.ORDER_STATUS_PAYING {
if err != nil {
utils.Log(nil, "异常数据记录失败:%s", err.Error())
}
o.Code = errorcode.OrderStatusErr
return
}
return
//if o.order.Status != common.ORDER_STATUS_PAYING {
// o.Code = errorcode.OrderStatusErr
// return
//}
//return
}

View File

@ -7,6 +7,7 @@ type Reqs struct {
OutTradeNo string `json:"out_trade_no"`
RefundOutTradeNo string `json:"refund_out_trade_no"`
RefundOrderId string `json:"refundOrder_id"`
CloseOutTradeNo string `json:"close_out_trade_no"`
}
type OrderFindOne struct {

View File

@ -10,10 +10,11 @@ import (
"encoding/json"
"errors"
"fmt"
"strconv"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/alipay"
"github.com/qit-team/snow-core/log/logger"
"strconv"
)
// AliInitClient 使用提供的支付请求参数初始化支付宝客户端
@ -349,6 +350,7 @@ func AliRefundOrderQuery(ctx context.Context, orderRefundQueryRequest OrderRefun
// AliCloseOrder 支付宝订单关闭
func AliCloseOrder(ctx context.Context, orderCloseRequest OrderCloseRequest) (OrderCloseInfo, error) {
// 初始化支付宝客户端
aliClient, err := AliInitClient(orderCloseRequest.Ali)
if err != nil {

View File

@ -16,6 +16,7 @@ const (
PAY_CHANNEL_ALIPAY_JSAPI = 8
PAY_CHANNEL_ALIPAY_PC = 9
PAY_CHANNEL_ALIPAY_QrCode = 10
PAY_CHANNEL_PSBC = 11
PAY_SUCCESS_CODE = 200 // 支付响应成功
PAY_ERROR_CODE = 500 // 支付响应失败
@ -23,15 +24,18 @@ const (
WX_SUCCESS_CODE = 200 // 微信状态码返回成功
WX_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
WX_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
ALI_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
ALI_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
WX_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
WX_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
ALI_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
ALI_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
PSBC_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/psbc/" // 邮储支付回调地址测试环境
PSBC_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/psbc/" // 邮储支付回调地址生产环境
ORDER_NO_TYPE_ORDER_NO = 2
PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信
PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝
PAY_CHANNLE_TYPE_PSBC = 3 // 支付类型:邮储
PAY_REFUND_STATU_COMMON = 0 // 未申请
PAY_REFUND_STATU_ING = 1 // 退款中

View File

@ -13,16 +13,17 @@ import (
)
type PayOrderRequest struct {
PayChannelId int64 `json:"pay_channel_id"` // 支付方式ID
OrderId int64 `json:"order_id"` // 平台订单号
ChannelType int `json:"channel_type"` // 支付渠道枚举,1微信JSAPI2微信H53微信app4微信Native5微信小程序6支付宝网页&移动应用7支付宝小程序8支付宝JSAPI
Description string `json:"description"` // 商品描述
Amount int `json:"amount"` // 金额单位为分
PayerClientIp string `json:"payer_client_ip"` // 终端IP
ReturnUrl string `json:"return_url"` // 支付成功后回调地址
Wx WxPay `json:"wx"` // 微信支付参数
Ali AliPay `json:"ali"` // 支付宝参数
OpenId string `json:"open_id"` // 支付者信息。 openid
PayChannelId int64 `json:"pay_channel_id"` // 支付方式ID
OrderId int64 `json:"order_id"` // 平台订单号
ChannelType int `json:"channel_type"` // 支付渠道枚举,1微信JSAPI2微信H53微信app4微信Native5微信小程序6支付宝网页&移动应用7支付宝小程序8支付宝JSAPI
Description string `json:"description"` // 商品描述
Amount int `json:"amount"` // 金额单位为分
PayerClientIp string `json:"payer_client_ip"` // 终端IP
ReturnUrl string `json:"return_url"` // 支付成功后回调地址
Wx WxPay `json:"wx"` // 微信支付参数
Ali AliPay `json:"ali"` // 支付宝参数
Psbc PsbcPay `json:"psbc"` // 邮储支付参数
OpenId string `json:"open_id"` // 支付者信息。 openid
}
type WxPay struct {
@ -72,6 +73,9 @@ func PaymentService(c context.Context, payOrderRequest PayOrderRequest) PayOrder
case payCommon.PAY_CHANNEL_ALIPAY_JSAPI:
// 支付宝JSAPI支付
info, err = ALiJsApiPayInfo(c, payOrderRequest)
case payCommon.PAY_CHANNEL_PSBC:
// 邮储支付
info, err = PsbcPayInfo(c, payOrderRequest)
default:
payOrderResponse = PayOrderResponse{
@ -109,10 +113,11 @@ func PaymentService(c context.Context, payOrderRequest PayOrderRequest) PayOrder
}
type PayOrderQueryRequest struct {
OrderId int64 `json:"order_id"` // 商户订单号
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
Wx WxPay `json:"wx"`
Ali AliPay `json:"ali"`
OrderId int64 `json:"order_id"` // 商户订单号
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
Wx WxPay `json:"wx"`
Ali AliPay `json:"ali"`
Psbc PsbcPay `json:"psbc"`
}
type PayOrderQueryResponse struct {
@ -143,6 +148,8 @@ func PayOrderQuery(c context.Context, payOrderQueryRequest PayOrderQueryRequest)
info, err = WxOrderQuery(c, payOrderQueryRequest.Wx, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
case payCommon.PAY_CHANNLE_TYPE_ZFB:
info, err = ALiOrderQuery(c, payOrderQueryRequest.Ali, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
case payCommon.PAY_CHANNLE_TYPE_PSBC:
info, err = PsbcOrderQuery(c, payOrderQueryRequest.Psbc, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
default:
payOrderQueryResponse = PayOrderQueryResponse{
Code: payCommon.PAY_ERROR_CODE,
@ -177,13 +184,15 @@ func PayOrderQuery(c context.Context, payOrderQueryRequest PayOrderQueryRequest)
}
type OrderRefundRequest struct {
OrderId int64 `json:"order_id"` // 订单编号
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
RefundReason string `json:"refund_reason"` // 退款原因
RefundAmount int64 `json:"refund_amount"` // 退款金额,单位分, 微信需要传入订单总额,不是用户实际支付金额
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
Wx WxPay `json:"wx"`
Ali AliPay `json:"ali"`
OrderId int64 `json:"order_id"` // 订单编号
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
RefundReason string `json:"refund_reason"` // 退款原因
RefundAmount int64 `json:"refund_amount"` // 退款金额,单位分, 微信需要传入订单总额,不是用户实际支付金额
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
TransactionId string `json:"transaction_id"` // 第三方交易号
Wx WxPay `json:"wx"`
Ali AliPay `json:"ali"`
Psbc PsbcPay `json:"psbc"`
}
type OrderRefundResponse struct {
@ -213,6 +222,8 @@ func OrderRefund(c context.Context, orderRefundRequest OrderRefundRequest) Order
info, err = WxOrderRefund(c, orderRefundRequest)
case payCommon.PAY_CHANNLE_TYPE_ZFB:
info, err = AliRefundOrder(c, orderRefundRequest)
case payCommon.PAY_CHANNLE_TYPE_PSBC:
info, err = PsbcRefundOrder(c, orderRefundRequest)
default:
orderRefundResponse = OrderRefundResponse{
Code: payCommon.PAY_ERROR_CODE,
@ -247,11 +258,12 @@ func OrderRefund(c context.Context, orderRefundRequest OrderRefundRequest) Order
}
type OrderRefundQueryRequest struct {
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
OrderId int64 `json:"order_id"` // 支付订单号
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
Wx WxPay `json:"wx"`
Ali AliPay `json:"ali"`
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
OrderId int64 `json:"order_id"` // 支付订单号
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
Wx WxPay `json:"wx"`
Ali AliPay `json:"ali"`
Psbc PsbcPay `json:"psbc"`
}
type OrderRefundQueryResponse struct {
Code int `json:"code"`
@ -304,10 +316,11 @@ func OrderRefundQuery(c context.Context, orderRefundQueryRequest OrderRefundQuer
}
type OrderCloseRequest struct {
OrderId int64 `json:"order_id"` // 支付订单号
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
Wx WxPay `json:"wx"`
Ali AliPay `json:"ali"`
OrderId int64 `json:"order_id"` // 支付订单号
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
Wx WxPay `json:"wx"`
Ali AliPay `json:"ali"`
Psbc PsbcPay `json:"psbc"`
}
type OrderCloseResponse struct {
@ -331,7 +344,10 @@ func OrderClose(c context.Context, orderCloseRequest OrderCloseRequest) OrderClo
// 微信H5支付
info, err = WxCloseOrder(c, orderCloseRequest)
case payCommon.PAY_CHANNLE_TYPE_ZFB:
info, err = AliCloseOrder(c, orderCloseRequest)
case payCommon.PAY_CHANNLE_TYPE_PSBC:
info, err = PsbcCloseOrder(c, orderCloseRequest)
default:
orderCloseResponse = OrderCloseResponse{
Code: payCommon.PAY_ERROR_CODE,

View File

@ -0,0 +1,191 @@
# Payment SDK
支付能力独立 SDK封装邮储手机银行支付、查询、退款、对账单、回调验签等能力供支付中心或其他业务系统复用。
## 功能特性
- 支付链接生成SM2+SM4 加密)
- 订单支付状态查询
- 退款申请
- 对账单查询与下载
- 回调通知验签与解密
- 工具方法订单号生成、Map 转签名字符串、HMAC-SHA256 签名
## 快速开始
### 1. 初始化客户端
```go
import "qteam/app/sdk/payment"
cfg := payment.Config{
MerchantId: "yourMerchantId",
MchtNo: "yourMchtNo",
AppID: "yourAppId",
SopPublicKey: "yourSopPublicKey",
PrivateKey: "yourPrivateKey",
Pubkey: "yourPubkey",
BankKey: "yourBankKey",
Sha: "yourShaKey",
ReturnUrl: "https://your-domain.com/return",
SuccessUrl: "https://your-domain.com/success",
NotifyUrl: "https://your-domain.com/notify",
ShowTitleBar: "1",
LoginHost: "https://login.example.com/",
OrderHost: "https://order.example.com/",
FileHost: "https://file.example.com/",
ShopId: "yourShopId",
}
client := payment.NewClient(cfg)
```
### 2. 创建支付链接
```go
link, err := client.CreatePaymentLink(payment.PaymentLinkRequest{
OrderNo: payment.GenerateOrderNumber(),
ProductName: "测试商品",
Price: "19.90",
BackUrl: "https://mall.example.com/pay",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("支付链接:", link.PayUrl)
fmt.Println("订单号:", link.OrderNo)
fmt.Println("前端验签:", link.Sign)
```
### 3. 查询订单
```go
result, err := client.OrderQuery("SJ20240101000000001")
if err != nil {
log.Fatal(err)
}
fmt.Println("订单状态:", result.OrderSta)
fmt.Println("响应码:", result.RespCode)
```
### 4. 申请退款
```go
refund, err := client.Refund(payment.RefundRequest{
OrderNo: "SJ20240101000000001",
Price: "19.90",
OrgTxnSeq: "bankOrderNo123",
RefundDesc: "用户主动退款",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("退款订单号:", refund.RefundOrderNo)
fmt.Println("退款状态:", refund.RefundOrderSta)
```
### 5. 对账单查询与下载
```go
// 查询对账单
bill, err := client.BillQuery(time.Now())
if err != nil {
log.Fatal(err)
}
// 下载对账单
for _, file := range bill.Files {
fileId := file["fileId"].(string)
data, err := client.BillDownload(fileId, time.Now())
if err != nil {
log.Fatal(err)
}
// 处理对账单数据
}
```
### 6. 处理回调通知
```go
// 解密通知
decrypted, err := client.DecryptNotify(rawJson)
if err != nil {
log.Fatal(err)
}
// 验签并解析
notifyData, err := client.VerifyAndParseNotify(rawJson)
if err != nil {
log.Fatal(err)
}
fmt.Println("通知数据:", notifyData)
```
## 核心类型说明
### Config
支付配置包含商户信息、密钥、URL 等必要配置。
### PaymentLinkRequest
```go
type PaymentLinkRequest struct {
OrderNo string
ProductName string
Price string
BackUrl string
}
```
### PaymentLinkResponse
```go
type PaymentLinkResponse struct {
OrderNo string
NotifyUrl string
Sign string
PlainText string
PayUrl string
}
```
### OrderQueryResponse
```go
type OrderQueryResponse struct {
OrderNo string
OrderSta string
RespCode string
RespMsg string
}
```
### RefundResponse
```go
type RefundResponse struct {
RespCode string
RespMsg string
RefundOrderNo string
RefundOrderSta string
TxnAmt string
}
```
## 注意事项
1. **密钥安全**:私钥、公钥等敏感信息请通过配置中心或环境变量传入,不要硬编码在代码中。
2. **并发安全**`GenerateOrderNumber` 和 `RandomNumber` 基于时间戳生成,高并发场景下建议由调用方保证唯一性。
3. **错误处理**:所有接口均返回 `error`,调用方需根据业务场景处理重试、降级等逻辑。
4. **状态码映射**:邮储订单状态码 `03-支付成功`、`04-支付失败`、`05-检查失败` 等,请参考 `types.go` 中的常量定义。
## 与现有系统集成建议
- **支付中心**:可直接使用此 SDK 封装统一支付服务。
- **业务系统**:通过依赖此 SDK 接入支付能力,避免重复实现加密、验签逻辑。
- **测试环境**:可通过 `Config` 切换测试环境地址和密钥。

View File

@ -0,0 +1,114 @@
package payment
import (
"encoding/json"
"fmt"
"time"
)
// BillQuery 查询对账单
// 对齐 YouChuKoffee 的 AccountBillQuery 流程:
// 1. 构建完整 {head, body} 结构body 包含 accountingDate, fileIntfcName
// 2. 整个 {head, body} 一起加密
// 3. head 同时作为 HTTP Header 明文传输
func (c *Client) BillQuery(date time.Time) (*BillQueryResponse, error) {
now := time.Now().Format("20060102150405")
BusiMainId := now + RandomNumber(10)
if date.IsZero() {
date = time.Now().AddDate(0, 0, -1)
}
// 构建完整 requesthead+body 一起加密,对齐 YouChuKoffee
requestBody := map[string]interface{}{
"head": map[string]string{
"partnerTxSriNo": BusiMainId,
"reqTime": now,
"method": "ufile.query.commonQuery",
"version": "1",
"merchantId": c.cfg.MerchantId,
"appID": c.cfg.AppID,
"accessType": "API",
"reserve": "",
},
"body": map[string]string{
"accountingDate": date.Format("20060102"),
"fileIntfcName": c.cfg.MchtNo,
},
}
// 整个 {head, body} 一起加密
encryptedReq, err := EncryptRequest(requestBody, c.cfg)
if err != nil {
return nil, fmt.Errorf("加密请求失败: %v", err)
}
encryptedBytes, _ := json.Marshal(encryptedReq)
url := c.cfg.FileHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
// head 同时作为 HTTP Header 明文传输
head := requestBody["head"].(map[string]string)
body, err := c.doPost(url, head, encryptedBytes)
if err != nil {
return nil, err
}
responseData, err := c.DecryptResponse(string(body), false)
if err != nil {
return nil, fmt.Errorf("解密响应失败: %v原始响应: %s", err, string(body))
}
var result BillQueryResponse
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
return nil, fmt.Errorf("解析响应失败: %v响应内容: %s", err, responseData)
}
return &result, nil
}
// BillDownload 下载对账单
// 对齐 YouChuKoffee 的 AccountBillDownload 流程:
// 1. 构建完整 {head, body} 结构body 包含 fileIntfcName, sm4Key, fileId
// 2. 整个 {head, body} 一起加密
// 3. head 同时作为 HTTP Header 明文传输
func (c *Client) BillDownload(fileId string, date time.Time) ([]byte, error) {
now := time.Now().Format("20060102150405")
BusiMainId := now + RandomNumber(10)
// 构建完整 requesthead+body 一起加密,对齐 YouChuKoffee
requestBody := map[string]interface{}{
"head": map[string]string{
"partnerTxSriNo": BusiMainId,
"reqTime": now,
"method": "ufile.download.commonDownload",
"version": "1",
"merchantId": c.cfg.MerchantId,
"appID": c.cfg.AppID,
"accessType": "API",
"reserve": "",
},
"body": map[string]string{
"fileIntfcName": c.cfg.MchtNo,
"sm4Key": "",
"fileId": fileId,
},
}
// 整个 {head, body} 一起加密
encryptedReq, err := EncryptRequest(requestBody, c.cfg)
if err != nil {
return nil, fmt.Errorf("加密请求失败: %v", err)
}
encryptedBytes, _ := json.Marshal(encryptedReq)
url := c.cfg.FileHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
// head 同时作为 HTTP Header 明文传输
head := requestBody["head"].(map[string]string)
body, err := c.doPost(url, head, encryptedBytes)
if err != nil {
return nil, err
}
return body, nil
}

View File

@ -0,0 +1,324 @@
package payment
import (
"bytes"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"net/http"
"sort"
"strings"
"time"
"github.com/ZZMarquis/gm/sm4"
"github.com/tjfoc/gmsm/sm2"
"github.com/tjfoc/gmsm/x509"
)
// Client 支付客户端
type Client struct {
cfg Config
}
// NewClient 创建支付客户端
func NewClient(cfg Config) *Client {
return &Client{cfg: cfg}
}
// doPost 发送 POST 请求到邮储银行
// head 信息通过 HTTP Header 明文传输encryptedBody 作为 HTTP POST Body
// 对齐 YouChuKoffee 的 postbank.doPost 流程
func (c *Client) doPost(url string, head map[string]string, encryptedBody []byte) ([]byte, error) {
req, err := http.NewRequest("POST", url, bytes.NewReader(encryptedBody))
if err != nil {
return nil, fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
for k, v := range head {
req.Header.Set(k, v)
}
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %v", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP请求失败状态码: %d响应: %s", resp.StatusCode, string(body))
}
return body, nil
}
// MapToString 将 map 转换为排序后的 key=value&key=value 格式
func MapToString(m map[string]string) string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
var result []string
for _, k := range keys {
result = append(result, fmt.Sprintf("%s=%s", k, m[k]))
}
return strings.Join(result, "&")
}
// HmacSha256To16 生成 HMAC-SHA256 签名16进制
func HmacSha256To16(key string, data string) string {
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(data))
encode := mac.Sum(nil)
return hex.EncodeToString(encode)
}
// GenerateOrderNumber 生成订单号
func GenerateOrderNumber() string {
datePart := time.Now().Format("20060102150405")
randomPart := fmt.Sprintf("%06d", time.Now().Nanosecond()%1000000)
return "SJ" + datePart + randomPart
}
// RandomNumber 生成指定长度的随机数字字符串
func RandomNumber(n int) string {
result := make([]byte, n)
for i := 0; i < n; i++ {
result[i] = byte(time.Now().Nanosecond()%10 + '0')
time.Sleep(1)
}
return string(result)
}
// EncryptMobile 手机银行支付参数加密
// 返回: tysdPayParams(base64), tysdEncryptKey(base64)
func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string, error) {
defer func() {
if err := recover(); err != nil {
fmt.Println("加密失败", err)
}
}()
sm4Key := generateSM4Key()
// SM2 加密 SM4 密钥(使用银行公钥)
bankPubKey, err := x509.ReadPublicKeyFromHex(c.cfg.BankKey)
if err != nil {
return "", "", fmt.Errorf("读取银行公钥失败: %v", err)
}
encryptKeyBytes, err := sm2.Encrypt(bankPubKey, sm4Key, nil, sm2.C1C3C2)
if err != nil {
return "", "", fmt.Errorf("sm2加密失败: %v", err)
}
encryptKey := hex.EncodeToString(encryptKeyBytes)
if len(encryptKey) > 2 && encryptKey[0:2] == "04" {
encryptKeyBytes = encryptKeyBytes[1:]
}
// SM2 签名(与 YouChuKoffee 对齐UserID 传 nil默认值 1234567812345678
merchantPrivKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
if err != nil {
return "", "", fmt.Errorf("读取商户私钥失败: %v", err)
}
r, s, err := sm2.Sm2Sign(merchantPrivKey, []byte(signStr), nil, rand.Reader)
if err != nil {
return "", "", fmt.Errorf("签名失败: %v", err)
}
sig := encodeBase64(rsToBytes(r, s))
// 拼接参数并 SM4 ECB 加密
param := fmt.Sprintf("%s&sign=%s", inputJson, sig)
tmp, err := sm4ECBEncrypt(sm4Key, pkcs5Padding([]byte(param), 16))
if err != nil {
return "", "", fmt.Errorf("sm4加密失败: %v", err)
}
return encodeBase64(tmp), encodeBase64(encryptKeyBytes), nil
}
// DecryptResponse 解密银行响应
func (c *Client) DecryptResponse(respJson string, isRequest bool) (string, error) {
var reqData map[string]string
if err := json.Unmarshal([]byte(respJson), &reqData); err != nil {
return "", fmt.Errorf("解析响应JSON失败: %v响应内容: %s", err, respJson)
}
dataKey := "response"
if isRequest {
dataKey = "request"
}
_, hasData := reqData[dataKey]
_, hasSignature := reqData["signature"]
_, hasEncryptKey := reqData["encryptKey"]
if !hasData || !hasSignature || !hasEncryptKey {
if code, ok := reqData["code"]; ok {
msg := reqData["msg"]
if msg == "" {
msg = reqData["message"]
}
return "", fmt.Errorf("银行返回错误,错误码: %s错误信息: %s", code, msg)
}
if respCode, ok := reqData["respCode"]; ok {
respMsg := reqData["respMsg"]
return "", fmt.Errorf("银行返回错误,错误码: %s错误信息: %s", respCode, respMsg)
}
missingFields := []string{}
if !hasData {
missingFields = append(missingFields, dataKey)
}
if !hasSignature {
missingFields = append(missingFields, "signature")
}
if !hasEncryptKey {
missingFields = append(missingFields, "encryptKey")
}
return "", fmt.Errorf("响应格式不正确,缺少字段: %v响应内容: %s", missingFields, respJson)
}
reqData["accessToken"] = ""
inData := reqData[dataKey]
inSignature := reqData["signature"]
inEncryptKey := reqData["encryptKey"]
// 验签
checked := c.verify(fmt.Sprintf("%s%s%s", inData, inEncryptKey, ""), inSignature)
if !checked {
return "", fmt.Errorf("签名验证失败")
}
// 解密 SM4 密钥
privKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
if err != nil {
return "", fmt.Errorf("读取私钥失败: %v", err)
}
hexEncryptKey, err := hex.DecodeString(inEncryptKey)
if err != nil {
return "", fmt.Errorf("解密sm4key失败: %v", err)
}
sm4Key, err := sm2.Decrypt(privKey, hexEncryptKey, sm2.C1C3C2)
if err != nil {
return "", fmt.Errorf("解密sm2key失败: %v", err)
}
// 解密数据
request, _ := base64.StdEncoding.DecodeString(inData)
encryptedSm4Key, err := sm4.CBCDecrypt(sm4Key, getSM4IV(), request)
decryptedStr := string(pkcs5UnPadding(encryptedSm4Key))
// 提取 body 字段(银行解密后的结构为 {head, body},业务数据在 body 中)
var decryptedMap map[string]interface{}
if jsonErr := json.Unmarshal([]byte(decryptedStr), &decryptedMap); jsonErr == nil {
if bodyVal, bodyOk := decryptedMap["body"]; bodyOk && bodyVal != nil {
if bodyStr, isStr := bodyVal.(string); isStr {
return bodyStr, nil
}
bodyBytes, marshalErr := json.Marshal(bodyVal)
if marshalErr == nil {
return string(bodyBytes), nil
}
}
}
return decryptedStr, nil
}
// VerifySignature 验签
func (c *Client) VerifySignature(content, signature string) bool {
return c.verify(content, signature)
}
func (c *Client) verify(content, signature string) bool {
pubKey, err := x509.ReadPublicKeyFromHex(c.cfg.SopPublicKey)
if err != nil {
panic(fmt.Sprintf("pubKeyBytes sm2 ReadPublicKeyFromHex err: %v", err))
}
r, s := signToRS(signature)
return sm2.Sm2Verify(pubKey, []byte(content), []byte(c.cfg.MerchantId), r, s)
}
func signToRS(signStr string) (*big.Int, *big.Int) {
sub := strings.Split(signStr, "#")
if len(sub) != 2 {
panic(fmt.Sprintf("err rs: %x", sub))
}
r, _ := new(big.Int).SetString(sub[0], 16)
s, _ := new(big.Int).SetString(sub[1], 16)
return r, s
}
func rsToBytes(r, s *big.Int) []byte {
rBytes := r.Bytes()
sBytes := s.Bytes()
result := make([]byte, 0, len(rBytes)+len(sBytes))
result = append(result, rBytes...)
result = append(result, sBytes...)
return result
}
func encodeBase64(data []byte) string {
return base64.StdEncoding.EncodeToString(data)
}
func getSM4IV() []byte {
return []byte("UISwD9fW6cFh9SNS")
}
func generateSM4Key() []byte {
key := make([]byte, 16)
_, err := rand.Read(key)
if err != nil {
panic(fmt.Sprintf("生成SM4密钥失败: %v", err))
}
return key
}
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := make([]byte, padding)
for i := 0; i < padding; i++ {
padtext[i] = byte(padding)
}
return append(ciphertext, padtext...)
}
func pkcs5UnPadding(origData []byte) []byte {
length := len(origData)
if length == 0 {
return origData
}
unpadding := int(origData[length-1])
if unpadding > length {
return origData
}
return origData[:(length - unpadding)]
}
func sm4ECBEncrypt(key, plaintext []byte) ([]byte, error) {
block, err := sm4.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
plaintext = pkcs5Padding(plaintext, blockSize)
ciphertext := make([]byte, len(plaintext))
for start := 0; start < len(plaintext); start += blockSize {
block.Encrypt(ciphertext[start:start+blockSize], plaintext[start:start+blockSize])
}
return ciphertext, nil
}

View File

@ -0,0 +1,97 @@
package payment
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"strings"
"github.com/ZZMarquis/gm/sm4"
"github.com/tjfoc/gmsm/sm2"
"github.com/tjfoc/gmsm/x509"
)
// EncryptRequest 加密请求
// 对齐 YouChuKoffee 的 EncryptRequest → postbank.Encrypt 流程:
// 1. 序列化完整 request{head, body} 一起)
// 2. SM4 CBC 加密 → base64 → addNewline每76字符加 \r\n
// 3. SM2 加密 SM4 密钥(使用 SOP 公钥)→ HEX 大写作为 encryptKey
// 4. signature = SM2_Sign(request_base64 + encryptKey + accessToken)
// 5. 返回 {request, signature, encryptKey, accessToken}
func EncryptRequest(request interface{}, cfg Config) (map[string]string, error) {
client := NewClient(cfg)
accessToken := ""
// Step 1: 序列化完整 request{head, body} 一起加密)
inputBytes, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("序列化请求失败: %v", err)
}
inputJson := string(inputBytes)
// Step 2: SM4 CBC 加密
sm4Key := generateSM4Key()
iv := getSM4IV()
paddedData := pkcs5Padding([]byte(inputJson), sm4.BlockSize)
tmp, err := sm4.CBCEncrypt(sm4Key, iv, paddedData)
if err != nil {
return nil, fmt.Errorf("SM4加密失败: %v", err)
}
responseMsg := base64.StdEncoding.EncodeToString(tmp)
responseMsg = addNewline(responseMsg) // 对齐 YouChuKoffee每76字符加 \r\n
// Step 3: SM2 加密 SM4 密钥
sopPubKey, err := x509.ReadPublicKeyFromHex(cfg.SopPublicKey)
if err != nil {
return nil, fmt.Errorf("读取SOP公钥失败: %v", err)
}
encryptKeyBytes, err := sm2.Encrypt(sopPubKey, sm4Key, rand.Reader, sm2.C1C3C2)
if err != nil {
return nil, fmt.Errorf("SM2加密SM4密钥失败: %v", err)
}
encryptKey := strings.ToUpper(hex.EncodeToString(encryptKeyBytes))
// Step 4: 签名(对齐 YouChuKoffee sign()UserID = MerchantId
signContent := fmt.Sprintf("%s%s%s", responseMsg, encryptKey, accessToken)
signature, err := client.signWithUserID(signContent, []byte(cfg.MerchantId))
if err != nil {
return nil, fmt.Errorf("生成签名失败: %v", err)
}
result := map[string]string{
"request": responseMsg,
"signature": signature,
"encryptKey": encryptKey,
"accessToken": accessToken,
}
return result, nil
}
// signWithUserID 使用指定 UserID 对内容进行 SM2 签名
// 对齐 YouChuKoffee 的 sign() + rSToSign():直接返回 r.Text(16) + "#" + s.Text(16),不做 base64 编码
func (c *Client) signWithUserID(content string, userId []byte) (string, error) {
privKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
if err != nil {
return "", fmt.Errorf("读取私钥失败: %v", err)
}
r, s, err := sm2.Sm2Sign(privKey, []byte(content), userId, rand.Reader)
if err != nil {
return "", fmt.Errorf("SM2签名失败: %v", err)
}
return r.Text(16) + "#" + s.Text(16), nil
}
// addNewline 每76个字符添加 \r\n对齐 YouChuKoffee 的 postbank.addNewline
func addNewline(str string) string {
lineLength := 76
var result strings.Builder
for i := 0; i < len(str); i++ {
if i > 0 && i%lineLength == 0 {
result.WriteString("\r\n")
}
result.WriteByte(str[i])
}
return result.String()
}

View File

@ -0,0 +1,40 @@
package payment
import (
"encoding/json"
"fmt"
)
// DecryptNotify 解密回调通知
func (c *Client) DecryptNotify(rawJson string) (string, error) {
return c.DecryptResponse(rawJson, true)
}
// VerifyNotifySignature 验证回调通知签名
func (c *Client) VerifyNotifySignature(content, signature string) bool {
return c.VerifySignature(content, signature)
}
// ParseNotify 解析回调通知
func (c *Client) ParseNotify(rawJson string) (*NotifyRequest, error) {
var req NotifyRequest
if err := json.Unmarshal([]byte(rawJson), &req); err != nil {
return nil, fmt.Errorf("解析通知失败: %v", err)
}
return &req, nil
}
// VerifyAndParseNotify 验签并解析回调通知
func (c *Client) VerifyAndParseNotify(rawJson string) (*YouChuOrderNotifyRequest, error) {
decrypted, err := c.DecryptNotify(rawJson)
if err != nil {
return nil, fmt.Errorf("解密通知失败: %v", err)
}
var result YouChuOrderNotifyRequest
if err := json.Unmarshal([]byte(decrypted), &result); err != nil {
return nil, fmt.Errorf("解析解密后数据失败: %v解密内容: %s", err, decrypted)
}
return &result, nil
}

View File

@ -0,0 +1,76 @@
package payment
import (
"encoding/json"
"fmt"
"time"
)
// OrderQuery 查询订单支付状态
// 对齐 YouChuKoffee 的 OrderQuery 流程:
// 1. 构建完整 {head, body} 结构
// 2. 整个 {head, body} 一起加密EncryptRequest
// 3. head 同时作为 HTTP Header 明文传输
func (c *Client) OrderQuery(orderNo string) (*OrderQueryResponse, error) {
now := time.Now().Format("20060102150405")
BusiMainId := now + RandomNumber(10)
// 构建完整 requesthead+body 一起加密,对齐 YouChuKoffee
requestBody := map[string]interface{}{
"head": map[string]string{
"partnerTxSriNo": BusiMainId,
"reqTime": now,
"method": "b2c.gatewaypay.orderQuery",
"version": "1",
"merchantId": c.cfg.MerchantId,
"appID": c.cfg.AppID,
"accessType": "API",
"reserve": "",
},
"body": map[string]interface{}{
"busiMainId": BusiMainId,
"reqTransTime": now,
"data": map[string]string{
"txnCode": "1004",
"sourceId": "16",
"reqTraceId": now + RandomNumber(10),
"reqDate": now, // 14 位 YYYYMMDDHHmmss
"txnDt": now,
"mchtNo": c.cfg.MchtNo,
"oldSeqNo": orderNo,
},
},
}
// 整个 {head, body} 一起加密
encryptedReq, err := EncryptRequest(requestBody, c.cfg)
if err != nil {
return nil, fmt.Errorf("加密请求失败: %v", err)
}
encryptedBytes, _ := json.Marshal(encryptedReq)
url := c.cfg.OrderHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
// head 同时作为 HTTP Header 明文传输
head := requestBody["head"].(map[string]string)
body, err := c.doPost(url, head, encryptedBytes)
if err != nil {
return nil, err
}
responseData, err := c.DecryptResponse(string(body), false)
if err != nil {
return nil, fmt.Errorf("解密响应失败: %v原始响应: %s", err, string(body))
}
var result OrderQueryResponse
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
return nil, fmt.Errorf("解析响应失败: %v响应内容: %s", err, responseData)
}
if result.RespCode != "" && result.RespCode != "0000" && result.RespCode != "00" {
return nil, fmt.Errorf("订单查询失败,错误码: %s错误信息: %s", result.RespCode, result.RespMsg)
}
return &result, nil
}

View File

@ -0,0 +1,151 @@
package payment
import (
"encoding/hex"
"fmt"
"net/url"
"strings"
"time"
)
// CreatePaymentLink 创建支付链接
func (c *Client) CreatePaymentLink(req PaymentLinkRequest) (*PaymentLinkResponse, error) {
var payUrlTemplate string
if len(req.BackUrl) > 0 && strings.Contains(req.BackUrl, "?") {
payUrlTemplate = "%s&fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
} else {
payUrlTemplate = "%s?fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
}
orderData := map[string]string{
"merchantNo": c.cfg.MchtNo,
"orderInfos": req.ProductName,
"orderNo": req.OrderNo,
"amount": req.Price,
"successUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl)),
"acctType": "2",
"notifyUrl": hex.EncodeToString([]byte(c.cfg.NotifyUrl)),
}
signData := map[string]string{
"merchantNo": c.cfg.MchtNo,
"orderNo": req.OrderNo,
"amount": req.Price,
}
sign, enKey, err := c.EncryptMobile(MapToString(orderData), MapToString(signData))
if err != nil {
return nil, fmt.Errorf("加密支付参数失败: %v", err)
}
payUrl := fmt.Sprintf(payUrlTemplate,
req.BackUrl,
sign,
c.cfg.ShopId,
enKey,
url.QueryEscape(c.cfg.ReturnUrl),
c.cfg.ShowTitleBar,
)
plainText := c.cfg.MchtNo + "|" + req.OrderNo + "|" + req.Price
signature := HmacSha256To16(c.cfg.Sha, plainText)
return &PaymentLinkResponse{
OrderNo: req.OrderNo,
NotifyUrl: c.cfg.NotifyUrl,
Sign: signature,
PlainText: plainText,
PayUrl: payUrl,
}, nil
}
// CreatePaymentLinkWithBackUrl 创建支付链接(带 fromId 判断)
func (c *Client) CreatePaymentLinkWithBackUrl(req PaymentLinkRequest) (*PaymentLinkResponse, error) {
var payUrlTemplate string
hasQuery := len(req.BackUrl) > 0 && strings.Contains(req.BackUrl, "?")
hasFromId := len(req.BackUrl) > 0 && contains(req.BackUrl, "fromId")
if hasFromId {
if hasQuery {
payUrlTemplate = "%s&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
} else {
payUrlTemplate = "%s?tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
}
} else {
if hasQuery {
payUrlTemplate = "%s&fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
} else {
payUrlTemplate = "%s?fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
}
}
orderData := map[string]string{
"merchantNo": c.cfg.MchtNo,
"orderInfos": req.ProductName,
"orderNo": req.OrderNo,
"amount": req.Price,
"successUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl)),
"acctType": "2",
"notifyUrl": hex.EncodeToString([]byte(c.cfg.NotifyUrl)),
}
signData := map[string]string{
"merchantNo": c.cfg.MchtNo,
"orderNo": req.OrderNo,
"amount": req.Price,
}
sign, enKey, err := c.EncryptMobile(MapToString(orderData), MapToString(signData))
if err != nil {
return nil, fmt.Errorf("加密支付参数失败: %v", err)
}
payUrl := fmt.Sprintf(payUrlTemplate,
req.BackUrl,
sign,
c.cfg.ShopId,
enKey,
url.QueryEscape(c.cfg.ReturnUrl),
c.cfg.ShowTitleBar,
)
plainText := c.cfg.MchtNo + "|" + req.OrderNo + "|" + req.Price
signature := HmacSha256To16(c.cfg.Sha, plainText)
return &PaymentLinkResponse{
OrderNo: req.OrderNo,
NotifyUrl: c.cfg.NotifyUrl,
Sign: signature,
PlainText: plainText,
PayUrl: payUrl,
}, nil
}
func contains(s, substr string) bool {
return len(s) > 0 && len(substr) > 0 && strings.Contains(s, substr)
}
// CreateHandCodePayParams 生成 handCodePay 插件参数
func (c *Client) CreateHandCodePayParams(req PaymentLinkRequest) (*HandCodePayResponse, error) {
plainText := c.cfg.MchtNo + "|" + req.OrderNo + "|" + req.Price
signature := HmacSha256To16(c.cfg.Sha, plainText)
txnDt := time.Now().Format("2006-01-02")
plain := fmt.Sprintf("TermSsn=%s|MercCode=%s|TranAmt=%s|MercUrl=%s|psbcmcc=%s|BackLink=%s|TxnDt=%s",
req.OrderNo,
c.cfg.MchtNo,
req.Price,
c.cfg.NotifyUrl,
c.cfg.Psbcmcc,
req.BackUrl,
txnDt,
)
return &HandCodePayResponse{
Plain: plain,
Sign: signature,
PlainText: plainText,
Signature: "",
}, nil
}

View File

@ -0,0 +1,78 @@
package payment
import (
"encoding/json"
"fmt"
"time"
)
// Refund 申请退款
// 对齐 YouChuKoffee 的 OrderRefund 流程:
// 1. 构建完整 {head, body} 结构body 包含 busiMainId, reqTransTime, data
// 2. 整个 {head, body} 一起加密
// 3. head 同时作为 HTTP Header 明文传输
func (c *Client) Refund(req RefundRequest) (*RefundResponse, error) {
now := time.Now().Format("20060102150405")
BusiMainId := now + RandomNumber(10)
// 构建完整 requesthead+body 一起加密,对齐 YouChuKoffee
requestBody := map[string]interface{}{
"head": map[string]string{
"partnerTxSriNo": BusiMainId,
"reqTime": now,
"method": "b2c.gatewaypay.orderRefund",
"version": "1",
"merchantId": c.cfg.MerchantId,
"appID": c.cfg.AppID,
"accessType": "API",
"reserve": "",
},
"body": map[string]interface{}{
"busiMainId": BusiMainId,
"reqTransTime": now,
"data": map[string]string{
"txnCode": "1003",
"sourceId": "16",
"reqTraceId": req.OrderNo + now[4:14], // MMDDHHmmss 10位后缀
"reqDate": now, // 14 位 YYYYMMDDHHmmss
"mchtNo": c.cfg.MchtNo,
"orgTxnSeq": req.OrgTxnSeq,
"txnAmt": req.Price,
"orgTxnAmt": req.Price,
"refundDesc": "用户主动退款",
},
},
}
// 整个 {head, body} 一起加密
encryptedReq, err := EncryptRequest(requestBody, c.cfg)
if err != nil {
return nil, fmt.Errorf("加密请求失败: %v", err)
}
encryptedBytes, _ := json.Marshal(encryptedReq)
url := c.cfg.OrderHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
// head 同时作为 HTTP Header 明文传输
head := requestBody["head"].(map[string]string)
body, err := c.doPost(url, head, encryptedBytes)
if err != nil {
return nil, err
}
responseData, err := c.DecryptResponse(string(body), false)
if err != nil {
return nil, fmt.Errorf("解密响应失败: %v原始响应: %s", err, string(body))
}
var result RefundResponse
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
return nil, fmt.Errorf("解析响应失败: %v响应内容: %s", err, responseData)
}
if result.RespCode != "" && result.RespCode != "0000" && result.RespCode != "00" {
return nil, fmt.Errorf("退款申请失败,错误码: %s错误信息: %s", result.RespCode, result.RespMsg)
}
return &result, nil
}

View File

@ -0,0 +1,154 @@
package payment
import (
"time"
)
// Config 支付配置
type Config struct {
MerchantId string
MchtNo string
AppID string
SopPublicKey string
PrivateKey string
Pubkey string
BankKey string
Sha string
ReturnUrl string
SuccessUrl string
NotifyUrl string
ShowTitleBar string
LoginHost string
OrderHost string
FileHost string
ShopId string
Psbcmcc string // 三方服务商标识,如 LSXD、JBZ
}
// PaymentLinkRequest 生成支付链接请求
type PaymentLinkRequest struct {
OrderNo string
ProductName string
Price string
BackUrl string
}
// PaymentLinkResponse 生成支付链接响应
type PaymentLinkResponse struct {
OrderNo string `json:"order_no"`
NotifyUrl string `json:"notify_url"`
Sign string `json:"sign"`
PlainText string `json:"plain_text"`
PayUrl string `json:"pay_url"`
}
// HandCodePayResponse handCodePay 插件参数
type HandCodePayResponse struct {
Plain string `json:"plain"`
Sign string `json:"sign"`
PlainText string `json:"plain_text"`
Signature string `json:"signature"`
}
// OrderQueryRequest 订单查询请求
type OrderQueryRequest struct {
OrderNo string
}
// OrderQueryResponse 订单查询响应
type OrderQueryResponse struct {
RespCode string `json:"code"`
RespMsg string `json:"respMsg"`
RespCd string `json:"respCd"`
ReqTraceId string `json:"reqTraceId"` //请求方流水号或者订单号,
OrderNo string `json:"orderNo"` //统一收单订单号
OrderSta string `json:"orderSta"` //03-支付成功 04-支付失败 05-检查失败
TxnFg string `json:"txnFg"` //0-正常 2-已部分退货 3- 已全部退货
TxnAmt string `json:"txnAmt"` // 交易金额 单位为元精确到小数点后2位
}
// RefundRequest 退款请求
type RefundRequest struct {
OrderNo string
Price string
OrgTxnSeq string
RefundDesc string
}
// RefundResponse 退款响应
type RefundResponse struct {
RespCode string `json:"code"`
RespMsg string `json:"respMsg"`
RespCd string `json:"respCd"`
TxnCode string `json:"txnCode"`
SourceId string `json:"sourceId"`
ReqTraceId string `json:"ReqTraceId"`
RefundOrderNo string `json:"refundOrderNo"`
RefundOrderSta string `json:"refundOrderSta"`
MchtNo string `json:"mchtNo"`
TxnAmt string `json:"txnAmt"`
}
// BillQueryRequest 对账单查询请求
type BillQueryRequest struct {
Date time.Time
}
// BillQueryResponse 对账单查询响应
type BillQueryResponse struct {
Files []map[string]interface{} `json:"files"`
}
// BillDownloadRequest 对账单下载请求
type BillDownloadRequest struct {
FileId string
Date time.Time
}
// NotifyRequest 回调通知请求
type NotifyRequest struct {
Request string `json:"request"`
Signature string `json:"signature"`
AccessToken string `json:"accessToken"`
EncryptKey string `json:"encryptKey"`
}
// NotifyResponse 回调通知响应
type NotifyResponse struct {
RespCode string `json:"respCode"`
RespMsg string `json:"respMsg"`
Data interface{} `json:"data"`
LinkUrl string `json:"linkUrl"`
}
type YouChuOrderNotifyRequest struct {
TxnCode string `json:"txnCode"`
SourceId string `json:"sourceId"`
ReqDate string `json:"reqDate"`
ReqTraceId string `json:"reqTraceId"` // 商户提交的订单号
OrderNo string `json:"orderNo"` // 银行的订单号
TxnAmt string `json:"txnAmt"`
OrderSta string `json:"orderSta"` //03-支付成功 04-支付失败05-检查失败
MchtNo string `json:"mchtNo"`
TermId string `json:"termId"`
TxnFlag string `json:"txnFlag"` //01-消费 03-退货
TxnKind string `json:"txnKind"` //01-银行卡 02-微信 03-支付宝
}
// OrderStatus 订单状态
type OrderStatus string
const (
OrderStatusWait OrderStatus = "01"
OrderStatusSuccess OrderStatus = "03"
OrderStatusFail OrderStatus = "04"
OrderStatusCheckFail OrderStatus = "05"
)
// RefundStatus 退款状态
type RefundStatus string
const (
RefundStatusSuccess RefundStatus = "03"
RefundStatusFail RefundStatus = "04"
)

View File

@ -0,0 +1,226 @@
package paymentService
import (
"PaymentCenter/app/third/paymentService/payCommon"
psbc "PaymentCenter/app/third/paymentService/psbc"
"PaymentCenter/config"
"context"
"encoding/json"
"fmt"
"github.com/qit-team/snow-core/log/logger"
"strconv"
)
type PsbcPay struct {
MerchantId string `json:"merchant_id"` // 商户ID
MchtNo string `json:"mcht_no"` // 商户号
AppID string `json:"app_id"` // 应用ID
SopPublicKey string `json:"sop_public_key"` // SOP公钥
PrivateKey string `json:"private_key"` // 商户私钥
Pubkey string `json:"pubkey"` // 商户公钥
BankKey string `json:"bank_key"` // 银行公钥
Sha string `json:"sha"` // SHA密钥
ReturnUrl string `json:"return_url"` // 支付返回地址
SuccessUrl string `json:"success_url"` // 支付成功地址
NotifyUrl string `json:"notify_url"` // 回调通知地址
ShowTitleBar string `json:"show_title_bar"` // 是否显示标题栏
LoginHost string `json:"login_host"` // 登录服务地址
OrderHost string `json:"order_host"` // 订单服务地址
FileHost string `json:"file_host"` // 文件服务地址
ShopId string `json:"shop_id"` // 店铺ID
Psbcmcc string `json:"psbcmcc"` // 三方服务商标识
}
func PsbcInitClient(psbcConfig PsbcPay) *psbc.Client {
cfg := psbc.Config{
MerchantId: psbcConfig.MerchantId,
MchtNo: psbcConfig.MchtNo,
AppID: psbcConfig.AppID,
SopPublicKey: psbcConfig.SopPublicKey,
PrivateKey: psbcConfig.PrivateKey,
Pubkey: psbcConfig.Pubkey,
BankKey: psbcConfig.BankKey,
Sha: psbcConfig.Sha,
ReturnUrl: psbcConfig.ReturnUrl,
SuccessUrl: psbcConfig.SuccessUrl,
NotifyUrl: psbcConfig.NotifyUrl,
ShowTitleBar: psbcConfig.ShowTitleBar,
LoginHost: psbcConfig.LoginHost,
OrderHost: psbcConfig.OrderHost,
FileHost: psbcConfig.FileHost,
ShopId: psbcConfig.ShopId,
Psbcmcc: psbcConfig.Psbcmcc,
}
return psbc.NewClient(cfg)
}
func PsbcPayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) {
envConfig := config.GetConf()
notifyUrl := fmt.Sprintf(envConfig.PayService.Host+payCommon.PSBC_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)
psbcConfig := payOrderRequest.Psbc
psbcConfig.NotifyUrl = notifyUrl
psbcClient := PsbcInitClient(psbcConfig)
amount := fmt.Sprintf("%.2f", float64(payOrderRequest.Amount)/100.0)
orderNo := strconv.FormatInt(payOrderRequest.OrderId, 10)
req := psbc.PaymentLinkRequest{
OrderNo: orderNo,
ProductName: payOrderRequest.Description,
Price: amount,
BackUrl: payOrderRequest.ReturnUrl,
}
resp, err := psbcClient.CreateHandCodePayParams(req)
if err != nil {
logger.Error(c, "PsbcPayInfo 发生错误", fmt.Sprintf("错误信息:%s", err.Error()))
return "", err
}
respBytes, err := json.Marshal(resp)
if err != nil {
logger.Error(c, "PsbcPayInfo 序列化失败", fmt.Sprintf("错误信息:%s", err.Error()))
return "", err
}
return string(respBytes), nil
}
func PsbcOrderQuery(ctx context.Context, psbcConfig PsbcPay, orderNo string) (PayOrderQueryInfo, error) {
psbcClient := PsbcInitClient(psbcConfig)
resp, err := psbcClient.OrderQuery(orderNo)
if err != nil {
logger.Error(ctx, "PsbcOrderQuery 发生错误", fmt.Sprintf("错误信息:%s", err.Error()))
return PayOrderQueryInfo{}, err
}
tradeState := "NOTPAY"
tradeStateDesc := ""
switch resp.OrderSta {
case "03":
tradeState = "SUCCESS"
tradeStateDesc = "支付成功"
case "04", "05":
tradeState = "FAIL"
tradeStateDesc = "支付失败"
default:
tradeState = "NOTPAY"
tradeStateDesc = "未支付"
}
var amountTotal int64
var payerTotal int64
if resp.TxnAmt != "" {
amountFloat, err := strconv.ParseFloat(resp.TxnAmt, 64)
if err == nil {
amountTotal = int64(amountFloat * 100)
payerTotal = int64(amountFloat * 100)
}
}
successTime := ""
outTradeNo, _ := strconv.ParseInt(orderNo, 10, 64)
return PayOrderQueryInfo{
AppId: psbcConfig.AppID,
OutTradeNo: outTradeNo,
TransactionId: resp.OrderNo,
TradeState: tradeState,
TradeStateDesc: tradeStateDesc,
SuccessTime: successTime,
AmountTotal: amountTotal,
PayerTotal: payerTotal,
}, nil
}
func PsbcRefundOrder(ctx context.Context, orderRefundRequest OrderRefundRequest) (OrderRefundInfo, error) {
psbcClient := PsbcInitClient(orderRefundRequest.Psbc)
refundAmount := fmt.Sprintf("%.2f", float64(orderRefundRequest.RefundAmount)/100.0)
orderNo := strconv.FormatInt(orderRefundRequest.OrderId, 10)
req := psbc.RefundRequest{
OrderNo: orderNo,
Price: refundAmount,
OrgTxnSeq: orderRefundRequest.TransactionId,
RefundDesc: orderRefundRequest.RefundReason,
}
resp, err := psbcClient.Refund(req)
if err != nil {
logger.Error(ctx, "PsbcRefundOrder 发生错误", fmt.Sprintf("申请退款接口失败,错误信息:%s", err.Error()))
return OrderRefundInfo{}, err
}
refundStatus := payCommon.PAY_REFUND_STATU_COMMON
switch resp.RefundOrderSta {
case "03":
refundStatus = payCommon.PAY_REFUND_STATU_SUCCESS
case "04":
refundStatus = payCommon.PAY_REFUND_STATU_FAIL
}
refundFee := int64(0)
if resp.TxnAmt != "" {
amountFloat, err := strconv.ParseFloat(resp.TxnAmt, 64)
if err == nil {
refundFee = int64(amountFloat * 100)
}
}
return OrderRefundInfo{
OutTradeNo: orderRefundRequest.OrderId,
TransactionId: resp.RefundOrderNo,
RefundFee: refundFee,
RefundOrderId: orderRefundRequest.RefundOrderId,
RefundStatus: refundStatus,
RefundSuccessTime: "",
}, nil
}
func PsbcCloseOrder(ctx context.Context, orderCloseRequest OrderCloseRequest) (OrderCloseInfo, error) {
return OrderCloseInfo{
OutTradeNo: orderCloseRequest.OrderId,
}, nil
}
func PsbcVerifyAndParseNotify(rawBody string, psbcConfig PsbcPay) (orderId int64, amountTotal int64, payerTotal int64, status string, err error) {
psbcClient := PsbcInitClient(psbcConfig)
result, err := psbcClient.VerifyAndParseNotify(rawBody)
if err != nil {
logger.Error(context.Background(), "PsbcVerifyAndParseNotify 发生错误", fmt.Sprintf("验签解密失败,错误信息:%s", err.Error()))
return 0, 0, 0, "", err
}
orderId, err = strconv.ParseInt(result.ReqTraceId, 10, 64)
if err != nil {
logger.Error(context.Background(), "PsbcVerifyAndParseNotify 发生错误", fmt.Sprintf("订单号转换失败,错误信息:%s", err.Error()))
return 0, 0, 0, "", err
}
if result.TxnAmt != "" {
amountFloat, err := strconv.ParseFloat(result.TxnAmt, 64)
if err == nil {
amountTotal = int64(amountFloat * 100)
payerTotal = amountTotal
}
}
orderSta := ""
if result.OrderSta != "" {
orderSta = result.OrderSta
}
switch orderSta {
case "03":
status = "SUCCESS"
case "04", "05":
status = "FAIL"
default:
status = "NOTPAY"
}
return orderId, amountTotal, payerTotal, status, nil
}

View File

@ -0,0 +1,105 @@
package paymentService
import (
"PaymentCenter/config"
"context"
"encoding/json"
"fmt"
"github.com/qit-team/snow-core/kernel/server"
"github.com/qit-team/snow-core/log/logger"
"os"
"testing"
)
func TestPsbcPay(t *testing.T) {
c := context.Background()
//解析启动命令
opts := config.GetOptions()
if opts.ShowVersion {
fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate)
os.Exit(0)
}
//加载配置
opts.ConfFile = "../../../.env"
cf, err := config.Load(opts.ConfFile)
if err != nil {
return
}
//注册日志类服务
err = logger.Pr.Register(logger.SingletonMain, cf.Log, true)
if err != nil {
return
}
//data := `{"merchant_id": "your_merchant_id", "mcht_no": "your_mcht_no", "app_id": "your_app_id", "sop_public_key": "your_sop_public_key", "private_key": "your_private_key", "pubkey": "your_pubkey", "bank_key": "your_bank_key", "sha": "your_sha_key", "return_url": "https://example.com/return", "success_url": "https://example.com/success", "notify_url": "https://example.com/notify", "show_title_bar": "1", "login_host": "https://login.example.com", "order_host": "https://order.example.com", "file_host": "https://file.example.com", "shop_id": "your_shop_id"}`
psbc := PsbcPay{
MerchantId: "testMerchant001",
MchtNo: "100610100019042",
AppID: "961925472724332544001",
SopPublicKey: "04CABE03249C94BDC8A6A4440DA1B2ADFACF73F4340E5F1B9A76463694B44C2E5600A9BEAA035739383C292CF9F1C4695FAAC7963CD5033D5D647A6B1EBE78EC6A",
PrivateKey: "140c5c68da1829b79d8e4629a8b9548bd694ccc7061fbacb1079aed0e5ac33fa",
Pubkey: "0447fe9ed13aac6200c92b893ad1289a98437c8404e64b1d2f7c755698a8b8e8acb35c1db2bedc5213c930bdfc10efb0e12269cf6a06877679f114fe5ae9dd4469",
BankKey: "04E0E2E37F11901483CDFBC47F489D87D5D78C55DD7F919B73DEA83007748668B7871A1BA9608F156E25B7D64C7821379BAC1E2C591D5A50FF311D1AAE026C1DAE",
Sha: "636879vrt96t57w6f59",
ReturnUrl: "http://milk.h5.test.86698.cn/#/pages/ycnc/order",
SuccessUrl: "http://milk.h5.test.86698.cn/#/pages/ycnc/orderDetail?isPayBack=true&order_no=",
NotifyUrl: "http://milk.test.api.cdlsxd.cn/api/v1/order/notify",
ShowTitleBar: "true",
LoginHost: "http://wap.dev.psbc.com/sop-h5/biz/crecard/",
OrderHost: "http://wap.dev.psbc.com/sop-h5/biz/unionpay/",
FileHost: "",
ShopId: "LSXD0001",
}
data, _ := json.Marshal(psbc)
fmt.Println(string(data))
//err = sonic.Unmarshal([]byte(data), &psbc)
//if err != nil {
// fmt.Println(err)
// return
//}
request := PayOrderRequest{
PayChannelId: 8935141660703064070,
OrderId: 374700296052352,
ChannelType: 11, // 11-邮储支付
Description: "测试商品",
Amount: 100,
PayerClientIp: "192.168.110.235",
Psbc: psbc,
}
//支付
orderResult := PaymentService(c, request)
t.Log(orderResult)
//// 查询订单
//qreq := PayOrderQueryRequest{
// OrderId: request.OrderId,
// PayChannel: 3,
// Psbc: request.Psbc,
//}
//queryResult := PayOrderQuery(c, qreq)
//t.Log(queryResult)
//// 退款
//refund := OrderRefundRequest{
// OrderId: 3747002960422784848,
// RefundOrderId: 2017620703512514385,
// RefundReason: "测试支付商品",
// RefundAmount: 500,
// PayChannel: 11,
// Psbc: request.Psbc,
//}
//refundResult := OrderRefund(c, refund)
//t.Log(refundResult)
//// 关闭订单
//closeOrder := OrderCloseRequest{
// OrderId: request.OrderId,
// PayChannel: 3,
// Psbc: request.Psbc,
//}
//closeResutl := OrderClose(c, closeOrder)
//t.Log(closeResutl)
}

View File

@ -457,33 +457,13 @@ func PayType(payChannel int) int {
return common.PAY_CHANNLE_TYPE_WECHAT
case common.PAY_CHANNEL_ALIPAY_JSAPI, common.PAY_CHANNEL_ALIPAY_WEB, common.PAY_CHANNEL_ALIPAY_MINI, common.PAY_CHANNEL_ALIPAY_PC:
return common.PAY_CHANNLE_TYPE_ZFB
case common.PAY_CHANNEL_PSBC:
return common.PAY_CHANNLE_TYPE_PSBC
default:
return 0
}
}
// redis控制访问频率
func KeyExistsOrSet(key string, expire int) bool {
redisClient := redis.GetRedis()
// 假设Exists方法返回的是int64类型表示键是否存在0为不存在1为存在
if exists, err := redisClient.Exists(context.Background(), key).Result(); err == nil && exists == 1 {
return true
} else if err != nil {
// 处理错误情况,可以根据实际情况记录日志或返回错误
Log(nil, "redis_Exists异常", err)
return false
}
// 如果键不存在则设置键并返回false
if err := redisClient.SetEX(context.Background(), key, "", time.Duration(expire)*time.Second).Err(); err != nil {
// 处理设置键时的错误情况
Log(nil, "redis_SetEX异常", err)
return false
}
return false
}
// AcquireLock 尝试获取分布式锁,localValue用于检测是否是同一个客户端持有的锁锁
func AcquireLock(key, lockValue string, expired time.Duration) (bool, error) {
ctx := context.Background()

37
go.mod
View File

@ -5,7 +5,7 @@ go 1.23.0
toolchain go1.23.10
require (
github.com/BurntSushi/toml v0.4.1
github.com/BurntSushi/toml v1.1.0
github.com/ZZMarquis/gm v1.3.2
github.com/ahmetb/go-linq/v3 v3.2.0
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
@ -17,7 +17,7 @@ require (
github.com/go-pay/util v0.0.2
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/go-sql-driver/mysql v1.6.0
github.com/go-sql-driver/mysql v1.7.1
github.com/goccy/go-json v0.10.5
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/jinzhu/copier v0.4.0
@ -26,19 +26,19 @@ require (
github.com/openzipkin/zipkin-go v0.2.2
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.12.2
github.com/qit-team/snow-core v0.1.28
github.com/qit-team/snow-core v0.1.29
github.com/qit-team/work v0.3.11
github.com/robfig/cron v1.2.0
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
github.com/swaggo/gin-swagger v1.3.3
github.com/swaggo/swag v1.7.9
github.com/tjfoc/gmsm v1.4.1
github.com/valyala/fasthttp v1.31.0
github.com/valyala/fasthttp v1.48.0
google.golang.org/grpc v1.56.3
google.golang.org/protobuf v1.36.6
gopkg.in/go-playground/validator.v9 v9.31.0
xorm.io/builder v0.3.9
xorm.io/xorm v1.2.5
xorm.io/builder v0.3.13
xorm.io/xorm v1.3.2
)
require (
@ -51,15 +51,16 @@ require (
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.2.2 // indirect
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.7 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/apache/rocketmq-client-go/v2 v2.1.0 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/apache/rocketmq-client-go/v2 v2.1.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v1.0.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
@ -71,7 +72,7 @@ require (
github.com/go-pay/xlog v0.0.3 // indirect
github.com/go-pay/xtime v0.0.2 // indirect
github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/go-redis/redis/v8 v8.11.4 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
@ -81,7 +82,7 @@ require (
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
@ -94,21 +95,24 @@ require (
github.com/nats-io/jwt v0.3.2 // indirect
github.com/nats-io/nkeys v0.1.3 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stathat/consistent v1.0.0 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tidwall/gjson v1.12.1 // indirect
github.com/tidwall/gjson v1.15.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/arch v0.16.0 // indirect
@ -121,9 +125,8 @@ require (
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
stathat.com/c/consistent v1.0.0 // indirect
xorm.io/core v0.7.3 // indirect
)

180
go.sum
View File

@ -39,9 +39,10 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
@ -83,12 +84,11 @@ github.com/aliyun/aliyun-mns-go-sdk v1.0.2/go.mod h1:eD/mEH7SwtLSwI9p8fP9VTH2cYM
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/aliyunmq/mq-http-go-sdk v1.0.3/go.mod h1:JYfRMQoPexERvnNNBcal0ZQ2TVQ5ialDiW9ScjaadEM=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/rocketmq-client-go/v2 v2.1.0 h1:3eABKfxc1WmS2lLTTbKMe1gZfZV6u1Sx9orFnOfABV0=
github.com/apache/rocketmq-client-go/v2 v2.1.0/go.mod h1:oEZKFDvS7sz/RWU0839+dQBupazyBV7WX5cP6nrio0Q=
github.com/apache/rocketmq-client-go/v2 v2.1.1 h1:WY/LkOYSQaVyV+HOqdiIgF4LE3beZ/jwdSLKZlzpabw=
github.com/apache/rocketmq-client-go/v2 v2.1.1/go.mod h1:GZzExtXY9zpI6FfiVJYAhw2IXQtgnHUuWpULo7nr5lw=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@ -108,6 +108,10 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
@ -120,6 +124,10 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -158,8 +166,9 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -178,7 +187,9 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@ -193,7 +204,7 @@ github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9S
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@ -235,28 +246,28 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@ -308,7 +319,7 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -342,6 +353,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -472,10 +484,12 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
@ -494,7 +508,7 @@ 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/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
@ -528,13 +542,11 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
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.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
@ -586,12 +598,13 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@ -606,8 +619,12 @@ github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
@ -653,8 +670,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/qit-team/snow-core v0.1.28 h1:RrX7i6GLbcMMSVzAT1lXgS/S3M2b1OrAnsoPaRGR4PI=
github.com/qit-team/snow-core v0.1.28/go.mod h1:J9CNj6P2IRh72yVa7rut4T8ikq/4DjaisLqXZy40TNg=
github.com/qit-team/snow-core v0.1.29 h1:tJVfFiv4kHo6DqfsPwwf/LfYSS2pik2WabnLsxzO358=
github.com/qit-team/snow-core v0.1.29/go.mod h1:D8PXgiIFjSCelYyRSeZPSwebcDtsrCioTi/qtXR2yQM=
github.com/qit-team/work v0.3.11 h1:AAtLTCOJ01WMFcvviK9rDGhHzaHE3bvunMOnSZ/80k8=
github.com/qit-team/work v0.3.11/go.mod h1:h5m1cZjn+BznChuAyMiR/+IUyWEmaMylPKRhq/AlxKw=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@ -676,6 +693,7 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
@ -686,16 +704,15 @@ github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJ
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/assertions v1.2.1 h1:bKNHfEv7tSIjZ8JbKaFjzFINljxG4lzZvmHUnElzOIg=
github.com/smartystreets/assertions v1.2.1/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8=
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
@ -709,6 +726,8 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stathat/consistent v1.0.0 h1:ZFJ1QTRn8npNBKW065raSZ8xfOqhpb8vLOkfp4CcL/U=
github.com/stathat/consistent v1.0.0/go.mod h1:uajTPbgSygZBJ+V+0mY7meZ8i0XAcZs7AQ6V121XSxw=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
@ -728,6 +747,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
@ -740,15 +761,14 @@ github.com/swaggo/swag v1.7.9 h1:6vCG5mm43ebDzGlZPMGYrYI4zKFfOr5kicQX8qjeDwc=
github.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA=
github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo=
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw=
github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
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/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@ -756,9 +776,9 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
github.com/ugorji/go v1.2.11/go.mod h1:2CGjQPolsidfhgBxo2wBo1Xh48rJWqUepV6q7OMkdWA=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
@ -766,8 +786,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.31.0 h1:lrauRLII19afgCs2fnWRJ4M5IkV0lo2FqA61uGkNBfE=
github.com/valyala/fasthttp v1.31.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
github.com/valyala/fasthttp v1.48.0 h1:oJWvHb9BIZToTQS3MuQ2R3bJZiNSa2KiNdeI8A+79Tc=
github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
@ -778,7 +798,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@ -801,8 +821,8 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
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.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@ -817,6 +837,9 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -836,10 +859,12 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -877,7 +902,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -927,11 +953,12 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -958,6 +985,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1024,21 +1053,30 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1048,6 +1086,11 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1118,7 +1161,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1242,7 +1286,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
@ -1265,8 +1310,9 @@ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:a
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@ -1355,7 +1401,6 @@ modernc.org/ccgo/v3 v3.12.95 h1:Ym2JG2G3P4IyZqjTTojHTl7qO0RysXeGSYPSoKPSBxc=
modernc.org/ccgo/v3 v3.12.95/go.mod h1:ZcLyvtocXYi8uF+9Ebm3G8EF8HNY5hGomBqthDp4eC8=
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg=
@ -1408,30 +1453,29 @@ modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14=
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.11.2/go.mod h1:+mhs/P1ONd+6G7hcAs6irwDi/bjTQ7nLW6LHRBsEa3A=
modernc.org/sqlite v1.14.2 h1:ohsW2+e+Qe2To1W6GNezzKGwjXwSax6R+CrhRxVaFbE=
modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI=
modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY=
modernc.org/tcl v1.9.2/go.mod h1:aw7OnlIoiuJgu1gwbTZtrKnGpDqH9wyH++jZcxdqNsg=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c=
stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0=
xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc=
xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/core v0.7.3 h1:W8ws1PlrnkS1CZU1YWaYLMQcQilwAmQXU0BJDJon+H0=
xorm.io/core v0.7.3/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/xorm v1.2.5 h1:tqN7OhN8P9xi52qBb76I8m5maAJMz/SSbgK2RGPCPbo=
xorm.io/xorm v1.2.5/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0=
xorm.io/xorm v1.3.2 h1:uTRRKF2jYzbZ5nsofXVUx6ncMaek+SHjWYtCXyZo1oM=
xorm.io/xorm v1.3.2/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=

2
logs/.gitignore vendored
View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -4,6 +4,7 @@ import (
"PaymentCenter/app/console"
"PaymentCenter/app/http/routes"
"PaymentCenter/app/jobs"
"PaymentCenter/app/utils"
"PaymentCenter/bootstrap"
"PaymentCenter/config"
_ "PaymentCenter/docs"
@ -66,7 +67,7 @@ func main() {
fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate)
os.Exit(0)
}
utils.Log(nil, "正在启动服务...")
handleCmd(opts)
err := startServer(opts)