Compare commits
4 Commits
v1.2.2
...
3dc9bc5b1d
| Author | SHA1 | Date | |
|---|---|---|---|
| 3dc9bc5b1d | |||
| 7fe415de63 | |||
| 8e42fad8aa | |||
| 7a3c47f1d4 |
@@ -40,12 +40,13 @@ http 调用 clients 的初始化函数
|
|||||||
jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
||||||
|
|
||||||
慢速请求底层调用埋点监控
|
慢速请求底层调用埋点监控
|
||||||
|
|
||||||
- redis
|
- redis
|
||||||
- gorm
|
- gorm
|
||||||
- 三方接口
|
- 三方接口
|
||||||
|
|
||||||
冷数据迁移方案
|
冷数据迁移方案
|
||||||
|
|
||||||
## 业务逻辑
|
## 业务逻辑
|
||||||
|
|
||||||
### 订单关闭的几种方式
|
### 订单关闭的几种方式
|
||||||
@@ -64,7 +65,8 @@ jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
|||||||
|
|
||||||
### 节点分配与存储逻辑
|
### 节点分配与存储逻辑
|
||||||
|
|
||||||
提取:
|
提取:
|
||||||
|
|
||||||
- 检查用户套餐与白名单
|
- 检查用户套餐与白名单
|
||||||
- 选中代理
|
- 选中代理
|
||||||
- 找到当前可用端口最多的代理
|
- 找到当前可用端口最多的代理
|
||||||
@@ -76,6 +78,7 @@ jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
|||||||
- 分别提交连接与配置请求
|
- 分别提交连接与配置请求
|
||||||
|
|
||||||
释放:
|
释放:
|
||||||
|
|
||||||
- 根据批次查出所有端口与相关节点
|
- 根据批次查出所有端口与相关节点
|
||||||
- 分别提交断开与关闭请求
|
- 分别提交断开与关闭请求
|
||||||
- 释放端口
|
- 释放端口
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
# Docker 部署说明
|
|
||||||
|
|
||||||
本文档说明如何使用 Docker 构建和部署平台服务。
|
|
||||||
|
|
||||||
## 构建镜像
|
|
||||||
|
|
||||||
在项目根目录下执行以下命令构建 Docker 镜像:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build -t platform:latest .
|
|
||||||
```
|
|
||||||
|
|
||||||
## 生产环境部署
|
|
||||||
|
|
||||||
由于涉及敏感的 `.pem` 证书文件,这些文件不包含在代码库或 Docker 镜像中,而是在运行时通过卷挂载的方式提供。
|
|
||||||
|
|
||||||
### 准备证书文件
|
|
||||||
|
|
||||||
1. 在生产服务器上创建一个目录用于存放证书文件,例如:`/path/to/certs/`
|
|
||||||
2. 将必要的证书文件放入此目录:
|
|
||||||
- `pub_key.pem`
|
|
||||||
- `apiclient_key.pem`
|
|
||||||
|
|
||||||
### 运行容器
|
|
||||||
|
|
||||||
使用以下命令运行容器,挂载证书目录:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d \
|
|
||||||
--name platform \
|
|
||||||
-p 8080:8080 \
|
|
||||||
-e APP_PORT=8080 \
|
|
||||||
-v /path/to/certs:/app/certs \
|
|
||||||
platform:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### 环境变量
|
|
||||||
|
|
||||||
可以通过环境变量来配置应用程序:
|
|
||||||
|
|
||||||
- `APP_PORT`: 应用监听的端口号(默认: 8080)
|
|
||||||
- 其他应用相关的环境变量可以通过 `-e` 参数添加
|
|
||||||
|
|
||||||
### 证书路径配置
|
|
||||||
|
|
||||||
如果应用程序需要知道证书的路径,可以通过环境变量配置:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d \
|
|
||||||
--name platform \
|
|
||||||
-p 8080:8080 \
|
|
||||||
-e APP_PORT=8080 \
|
|
||||||
-e PUB_KEY_PATH=/app/certs/pub_key.pem \
|
|
||||||
-e APICLIENT_KEY_PATH=/app/certs/apiclient_key.pem \
|
|
||||||
-v /path/to/certs:/app/certs \
|
|
||||||
platform:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
## 使用 Docker Compose
|
|
||||||
|
|
||||||
也可以通过 Docker Compose 进行部署,创建 `docker-compose.yml` 文件:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
|
||||||
platform:
|
|
||||||
image: platform:latest
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
environment:
|
|
||||||
- APP_PORT=8080
|
|
||||||
- PUB_KEY_PATH=/app/certs/pub_key.pem
|
|
||||||
- APICLIENT_KEY_PATH=/app/certs/apiclient_key.pem
|
|
||||||
volumes:
|
|
||||||
- /path/to/certs:/app/certs
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
然后执行:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
## 安全建议
|
|
||||||
|
|
||||||
1. 确保证书文件的权限设置正确,仅允许必要的用户访问
|
|
||||||
2. 在生产环境中考虑使用 Docker Secrets 或 Kubernetes Secrets 来管理敏感信息
|
|
||||||
3. 定期更新证书和密钥
|
|
||||||
16
publish.ps1
Normal file
16
publish.ps1
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
if (-not $args) {
|
||||||
|
Write-Error "需要指定版本号"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$confrim = Read-Host "构建版本为 [platform:$($args[0])],是否继续?(y/n)"
|
||||||
|
if ($confrim -ne "y") {
|
||||||
|
Write-Host "已取消构建"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
docker build -t 43.226.58.254:53000/lanhu/platform:latest .
|
||||||
|
docker build -t 43.226.58.254:53000/lanhu/platform:$($args[0]) .
|
||||||
|
|
||||||
|
docker push 43.226.58.254:53000/lanhu/platform:latest
|
||||||
|
docker push 43.226.58.254:53000/lanhu/platform:$($args[0])
|
||||||
@@ -353,6 +353,9 @@ func authPassword(c *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m
|
|||||||
admin.LastLogin = u.P(time.Now())
|
admin.LastLogin = u.P(time.Now())
|
||||||
admin.LastLoginIP = ip
|
admin.LastLoginIP = ip
|
||||||
admin.LastLoginUA = ua
|
admin.LastLoginUA = ua
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, ErrAuthorizeInvalidRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成会话
|
// 生成会话
|
||||||
@@ -364,12 +367,7 @@ func authPassword(c *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m
|
|||||||
AccessToken: uuid.NewString(),
|
AccessToken: uuid.NewString(),
|
||||||
AccessTokenExpires: now.Add(time.Duration(env.SessionAccessExpire) * time.Second),
|
AccessTokenExpires: now.Add(time.Duration(env.SessionAccessExpire) * time.Second),
|
||||||
}
|
}
|
||||||
if user != nil {
|
|
||||||
session.UserID = &user.ID
|
|
||||||
}
|
|
||||||
if admin != nil {
|
|
||||||
session.AdminID = &admin.ID
|
|
||||||
}
|
|
||||||
if req.Remember {
|
if req.Remember {
|
||||||
session.RefreshToken = u.P(uuid.NewString())
|
session.RefreshToken = u.P(uuid.NewString())
|
||||||
session.RefreshTokenExpires = u.P(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second))
|
session.RefreshTokenExpires = u.P(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second))
|
||||||
@@ -377,18 +375,20 @@ func authPassword(c *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m
|
|||||||
|
|
||||||
// 保存用户更新和会话
|
// 保存用户更新和会话
|
||||||
err = q.Q.Transaction(func(tx *q.Query) error {
|
err = q.Q.Transaction(func(tx *q.Query) error {
|
||||||
if err := SaveSession(tx, session); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if user != nil {
|
if user != nil {
|
||||||
if err := tx.User.Save(user); err != nil {
|
if err := tx.User.Save(user); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
session.UserID = &user.ID
|
||||||
}
|
}
|
||||||
if admin != nil {
|
if admin != nil {
|
||||||
if err := tx.Admin.Save(admin); err != nil {
|
if err := tx.Admin.Save(admin); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
session.AdminID = &admin.ID
|
||||||
|
}
|
||||||
|
if err := SaveSession(tx, session); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
|
"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
|
"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/partnerpayments/h5"
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
||||||
)
|
)
|
||||||
@@ -18,6 +19,7 @@ var WechatPay *WechatPayClient
|
|||||||
|
|
||||||
type WechatPayClient struct {
|
type WechatPayClient struct {
|
||||||
Native *native.NativeApiService
|
Native *native.NativeApiService
|
||||||
|
H5 *h5.H5ApiService
|
||||||
Notify *notify.Handler
|
Notify *notify.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ func initWechatPay() error {
|
|||||||
// 创建 WechatPay 服务
|
// 创建 WechatPay 服务
|
||||||
WechatPay = &WechatPayClient{
|
WechatPay = &WechatPayClient{
|
||||||
Native: &native.NativeApiService{Client: client},
|
Native: &native.NativeApiService{Client: client},
|
||||||
|
H5: &h5.H5ApiService{Client: client},
|
||||||
Notify: handler,
|
Notify: handler,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -172,8 +172,13 @@ func UpdatePassword(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证手机号
|
||||||
|
if req.Phone != authCtx.User.Phone {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "手机号码不正确")
|
||||||
|
}
|
||||||
|
|
||||||
// 验证手机令牌
|
// 验证手机令牌
|
||||||
if req.Phone == "" || req.Code == "" {
|
if req.Code == "" {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "手机号码和验证码不能为空")
|
return fiber.NewError(fiber.StatusBadRequest, "手机号码和验证码不能为空")
|
||||||
}
|
}
|
||||||
err = s.Verifier.VerifySms(c.Context(), req.Phone, req.Code)
|
err = s.Verifier.VerifySms(c.Context(), req.Phone, req.Code)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
wecahtpaycore "github.com/wechatpay-apiv3/wechatpay-go/core"
|
wecahtpaycore "github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||||
|
|
||||||
"github.com/smartwalle/alipay/v3"
|
"github.com/smartwalle/alipay/v3"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/partnerpayments/h5"
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@@ -150,6 +151,24 @@ func (s *tradeService) CreateTrade(uid int32, now time.Time, data *CreateTradeDa
|
|||||||
}
|
}
|
||||||
paymentUrl = *resp.CodeUrl
|
paymentUrl = *resp.CodeUrl
|
||||||
|
|
||||||
|
// 微信 + 手机网站
|
||||||
|
case method == m.TradeMethodWechat && platform == m.TradePlatformMobile:
|
||||||
|
resp, _, err := g.WechatPay.H5.Prepay(context.Background(), h5.PrepayRequest{
|
||||||
|
SpAppid: &env.WechatPayAppId,
|
||||||
|
SpMchid: &env.WechatPayMchId,
|
||||||
|
OutTradeNo: &tradeNo,
|
||||||
|
Description: &subject,
|
||||||
|
TimeExpire: &expire,
|
||||||
|
NotifyUrl: &env.WechatPayCallbackUrl,
|
||||||
|
Amount: &h5.Amount{
|
||||||
|
Total: u.P(amountReal.Mul(decimal.NewFromInt(100)).Round(0).IntPart()),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paymentUrl = *resp.H5Url
|
||||||
|
|
||||||
// 商福通 + 电脑网站
|
// 商福通 + 电脑网站
|
||||||
case
|
case
|
||||||
method == m.TradeMethodSftAlipay && platform == m.TradePlatformPC,
|
method == m.TradeMethodSftAlipay && platform == m.TradePlatformPC,
|
||||||
|
|||||||
Reference in New Issue
Block a user