mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-01-23 02:40:23 +08:00
优化服务退出流程,增加中间件文档
This commit is contained in:
parent
fdefb42253
commit
c511a2e6b3
@ -69,7 +69,7 @@
|
||||
16. 插件应用:支持一键生成插件模板,每个插件之间开发隔离,拥有独立多应用入口、独立配置。完美支持多人协同开发、插件插拔不会对原系统产生影响等。
|
||||
17. 服务监控:监视当前系统CPU、内存、磁盘、网络、堆栈等相关信息。
|
||||
18. 附件管理:文件图片上传,支持本地、阿里云oss、腾讯云cos、ucloud对象存储、七牛云对象存储等多种上传驱动,后台一键切换配置。
|
||||
19. TCP服务:基于gtcp的应用化实例,支持长连接、断线重连、自动维护心跳、服务登录、服务授权等。主要用于网络服务进程之间的消息通讯。
|
||||
19. TCP服务:基于gtcp的应用实例,支持长连接、断线重连、自动维护心跳、签名、服务登录、服务授权等。主要用于C/S服务器和服务进程之间的数据通讯。
|
||||
20. 消息队列:同时兼容 kafka、redis、rocketmq、磁盘队列,一键配置切换到场景适用的MQ。
|
||||
21. 通知公告:采用websocket实时推送在线用户最新通知、公告、私信消息。
|
||||
22. 地区编码:整合国内通用省市区编码,运用于项目于一身,支持动态省市区选项。
|
||||
|
@ -16,7 +16,8 @@
|
||||
- [目录结构](sys-catalog.md)
|
||||
- [开发规范](sys-exploit.md)
|
||||
- [控制台](sys-console.md)
|
||||
- 请求中间件和WebHook
|
||||
- [中间件/拦截器](sys-middleware.md)
|
||||
- [WebHook](sys-webhook.md)
|
||||
- [权限控制](sys-auth.md)
|
||||
- [支付网关](sys-payment.md)
|
||||
- [数据库](sys-db.md)
|
||||
|
BIN
docs/guide-zh-CN/images/sys-middleware-error-log.png
Normal file
BIN
docs/guide-zh-CN/images/sys-middleware-error-log.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
@ -13,6 +13,7 @@
|
||||
- 仅推荐在开发期间快速调试使用,线上实际部署时建议将各个服务分开部署,这样重新部署某个服务时无需全部重启。
|
||||
|
||||
```shell
|
||||
|
||||
# 默认
|
||||
go run main.go
|
||||
|
||||
@ -22,6 +23,7 @@ gf run main.go
|
||||
|
||||
### HTTP服务
|
||||
- 启动HTTP服务,包含websocket。
|
||||
|
||||
```shell
|
||||
# 默认
|
||||
go run main.go http
|
||||
@ -41,7 +43,7 @@ go run main.go queue
|
||||
gf run main.go --args "queue"
|
||||
```
|
||||
|
||||
### 定时任务(暂未拆分,目前随HTTP服务启动)
|
||||
### 定时任务
|
||||
- 启动系统中统一注册的定时任务。
|
||||
|
||||
```shell
|
||||
@ -55,6 +57,8 @@ gf run main.go --args "cron"
|
||||
|
||||
### 常用工具
|
||||
- 释放casbin权限,用于清理无效的权限设置。
|
||||
|
||||
|
||||
```shell
|
||||
go run main.go tools -m=casbin -a1=refresh
|
||||
```
|
||||
@ -62,6 +66,7 @@ go run main.go tools -m=casbin -a1=refresh
|
||||
|
||||
### Makefile
|
||||
- 通过make提供一些快捷命令
|
||||
|
||||
```shell
|
||||
# 一键编译,打包前后端代码到可执行文件
|
||||
make build
|
||||
|
204
docs/guide-zh-CN/sys-middleware.md
Normal file
204
docs/guide-zh-CN/sys-middleware.md
Normal file
@ -0,0 +1,204 @@
|
||||
## 中间件/拦截器
|
||||
|
||||
目录
|
||||
|
||||
- 介绍
|
||||
- 全局中间件
|
||||
- 鉴权中间件
|
||||
- 响应中间件
|
||||
- 更多
|
||||
|
||||
### 介绍
|
||||
- 在hotgo中,中间件/拦截器主要作用于web请求的上下文预设、跨域请求处理、鉴权处理、请求拦截和请求结束后统一响应处理等。
|
||||
|
||||
|
||||
### 全局中间件
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// 初始化请求上下文,一般需要第一个进行加载,后续中间件存在依赖关系
|
||||
service.Middleware().Ctx()
|
||||
|
||||
// 跨域中间件,自动处理跨域问题
|
||||
service.Middleware().CORS()
|
||||
|
||||
// IP黑名单中间件,如果请求IP被后台拉黑,所有请求将被拒绝
|
||||
service.Middleware().Blacklist()
|
||||
|
||||
// 演示系統操作限制,当开启演示模式时,所有POST请求将被拒绝
|
||||
service.Middleware().DemoLimit()
|
||||
|
||||
// HTTP响应预处理,在业务处理完成后,对响应结果进行格式化和错误过滤,将处理后的数据发送给请求方
|
||||
service.Middleware().ResponseHandler()
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
### 鉴权中间件
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// 在鉴权中间件下的路由如果没有通过权限验证,后续请求将被拒绝
|
||||
// 在hotgo中,鉴权中间件一般是配合一个业务模块下的路由组进行使用
|
||||
// 目前admin、api、home、websocket模块都已接入
|
||||
// 如果你需要创建一个新的模块也需要用到鉴权中间件,可以参考:server/internal/logic/middleware/admin_auth.go
|
||||
|
||||
|
||||
// 一个简单例子
|
||||
s := g.Server()
|
||||
s.Group("/api", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(service.Middleware().ApiAuth)
|
||||
group.Bind(
|
||||
member.Member, // 管理员
|
||||
)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 响应中间件
|
||||
- 文件路径:server/internal/logic/middleware/response.go
|
||||
|
||||
|
||||
#### 自定义响应
|
||||
- 由于响应中间件是全局的,并且是统一使用json格式进行响应的,但是在实际的开发中可能存在一些需要使用非json格式的响应,所以你需要进行单独的处理。
|
||||
- 推荐以下几种处理方式,可做参考:
|
||||
1. 使用`ghttp.ExitAll()`,需要注意的是此方法会终止后续所有的http处理
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := new(ghttp.Request) // 当前请求对象
|
||||
|
||||
// 清空响应
|
||||
r.Response.ClearBuffer()
|
||||
|
||||
// 写入响应
|
||||
r.Response.Write("自定义响应内容")
|
||||
|
||||
// 终止后续http处理
|
||||
r.ExitAll()
|
||||
}
|
||||
```
|
||||
|
||||
2. 在`server/internal/logic/middleware/response.go`中根据请求的独有特征进行单独的处理,兼容后续http处理。
|
||||
|
||||
|
||||
#### 重写响应错误提示
|
||||
|
||||
- 在实际开发中,我们可能想要隐藏一些敏感错误,返回给客户端友好的错误提示,但开发者同时又想需要看到真实的敏感错误。对此hotgo已经进行了过滤处理,下面是一个简单的例子:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
func test() error {
|
||||
err = gerror.New("这是一个sql执行错误")
|
||||
err = gerror.Wrap(err, "用户创建失败,请稍后重试!~")
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
- 开启debug时的客户端响应:
|
||||
```json
|
||||
{
|
||||
"code": -1,
|
||||
"message": "用户创建失败,请稍后重试!~",
|
||||
"error": [
|
||||
"1. 用户创建失败,请稍后重试!~",
|
||||
" 1). hotgo/internal/logic/admin.(*sAdminMember).List",
|
||||
" E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526",
|
||||
"2. 这是一个sql执行错误", " 1). hotgo/internal/logic/admin.(*sAdminMember).List",
|
||||
" E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:525",
|
||||
" 2). hotgo/internal/controller/admin/admin.(*cMember).List",
|
||||
" E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/controller/admin/admin/member.go:157", " 3). github.com/gogf/gf/v2/net/ghttp.(*middleware).callHandlerFunc.func1", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:152", " 4). github.com/gogf/gf/v2/net/ghttp.niceCallFunc", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_func.go:55", " 5). github.com/gogf/gf/v2/net/ghttp.(*middleware).callHandlerFunc", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:129", " 6). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:75", " 7). github.com/gogf/gf/v2/util/gutil.TryCatch", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/util/gutil/gutil.go:56", " 8). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:49", " 9). hotgo/internal/logic/middleware.(*sMiddleware).AdminAuth", " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/admin_auth.go:53", " 10). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.1", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:55", " 11). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:54", " 12). hotgo/internal/logic/middleware.(*sMiddleware).ResponseHandler", " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/response.go:24", " 13). hotgo/internal/logic/middleware.(*sMiddleware).DemoLimit", " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:90", " 14). hotgo/internal/logic/middleware.(*sMiddleware).Blacklist", " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/limit_blacklist.go:22", " 15). hotgo/internal/logic/middleware.(*sMiddleware).CORS", " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:83", " 16). hotgo/internal/logic/middleware.(*sMiddleware).Ctx", " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:62", " 17). github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_middleware_tracing.go:79", " 18). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.5", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:96", " 19). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:95", " 20). github.com/gogf/gf/v2/net/ghttp.(*Server).ServeHTTP", " E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_server_handler.go:132", ""
|
||||
],
|
||||
"timestamp": 1684145107,
|
||||
"traceID": "084022730d495f17f19e550140f3e1a8"
|
||||
}
|
||||
```
|
||||
|
||||
- 关闭debug时的客户端响应:
|
||||
```json
|
||||
{
|
||||
"code": -1,
|
||||
"message": "用户创建失败,请稍后重试!~",
|
||||
"timestamp": 1684145107,
|
||||
"traceID": "084022730d495f17f19e550140f3e1a8"
|
||||
}
|
||||
```
|
||||
|
||||
- 控制台的输出日志:
|
||||
```shell
|
||||
2023-05-15 18:05:07.776 {084022730d495f17f19e550140f3e1a8} 200 "GET http localhost:8000 /admin/member/list?page=1&pageSize=10&roleId=-1 HTTP/1.1" 0.002, 127.0.0.1, "http://192.168.0.207:8001/login", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Co
|
||||
re/1.94.197.400 QQBrowser/11.7.5287.400", -1, "", ""
|
||||
Stack:
|
||||
1. 用户创建失败,请稍后重试!~
|
||||
1). hotgo/internal/logic/admin.(*sAdminMember).List
|
||||
E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526
|
||||
2. 这是一个sql执行错误
|
||||
1). hotgo/internal/logic/admin.(*sAdminMember).List
|
||||
E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/response.go:24
|
||||
13). hotgo/internal/logic/middleware.(*sMiddleware).DemoLimit
|
||||
E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:90
|
||||
|
||||
```
|
||||
|
||||
- 如果你开启了访问日志,那么日志记录中会详细记录本次请求的相关信息,内容如下:
|
||||
![./images/sys-middleware-error-log.png](./images/sys-middleware-error-log.png)
|
||||
|
||||
|
||||
#### 重写错误码
|
||||
- hotgo默认使用了gf内置的错误码进行业务处理,通常情况下成功状态码为`0`,失败状态码为`-1`
|
||||
- 查看gf内置错误码:https://goframe.org/pages/viewpage.action?pageId=30739587
|
||||
- 以下是自定义错误码的简单例子:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
func test() error {
|
||||
// 使用自定义状态码30001响应客户端
|
||||
err = gerror.NewCode(gcode.New(30001, "用户创建失败,请稍后重试!~", nil))
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
- 客户端响应如下:
|
||||
```json
|
||||
{
|
||||
"code": 30001,
|
||||
"message": "用户创建失败,请稍后重试!~",
|
||||
"timestamp": 1684146313,
|
||||
"traceID": "b4f90e16264a5f17cd3fc27141aba448"
|
||||
}
|
||||
```
|
||||
|
||||
### 更多
|
||||
- 更多关于中间件/拦截器的介绍请参考:https://goframe.org/pages/viewpage.action?pageId=55289881
|
||||
|
3
docs/guide-zh-CN/sys-webhook.md
Normal file
3
docs/guide-zh-CN/sys-webhook.md
Normal file
@ -0,0 +1,3 @@
|
||||
## WebHook
|
||||
|
||||
待写
|
@ -7,9 +7,9 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"hotgo/internal/service"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -20,17 +20,17 @@ var (
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
service.AuthClient().Start(ctx)
|
||||
|
||||
// 退出信号监听
|
||||
signalListen(ctx, func(sig os.Signal) {
|
||||
service.AuthClient().Stop(ctx)
|
||||
})
|
||||
serverWg.Add(1)
|
||||
|
||||
// 信号监听
|
||||
signalListen(ctx, signalHandlerForOverall)
|
||||
select {
|
||||
case <-serverCloseSignal:
|
||||
// ...
|
||||
service.AuthClient().Stop(ctx)
|
||||
serverWg.Done()
|
||||
}
|
||||
|
||||
g.Log().Debug(ctx, "auth successfully closed ..")
|
||||
return
|
||||
},
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
serverCloseSignal chan struct{}
|
||||
Main = &gcmd.Command{
|
||||
Main = &gcmd.Command{
|
||||
Description: `默认启动所有服务`,
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
return All.Func(ctx, parser)
|
||||
@ -76,10 +75,10 @@ var (
|
||||
|
||||
select {
|
||||
case <-serverCloseSignal:
|
||||
// ...
|
||||
serverWg.Wait()
|
||||
}
|
||||
|
||||
g.Log().Debug(ctx, "service successfully closed ..")
|
||||
g.Log().Debug(ctx, "all service successfully closed ..")
|
||||
return
|
||||
},
|
||||
}
|
||||
@ -89,5 +88,4 @@ func init() {
|
||||
if err := Main.AddCommand(All, Http, Queue, Cron, Auth, Tools, Help); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
serverCloseSignal = make(chan struct{}, 1)
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"hotgo/internal/crons"
|
||||
"hotgo/internal/service"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -25,17 +25,18 @@ var (
|
||||
// tcp客户端
|
||||
service.CronClient().Start(ctx)
|
||||
|
||||
// 退出信号监听
|
||||
signalListen(ctx, func(sig os.Signal) {
|
||||
service.CronClient().Stop(ctx)
|
||||
crons.StopALL()
|
||||
serverCloseSignal <- struct{}{}
|
||||
})
|
||||
serverWg.Add(1)
|
||||
|
||||
// 信号监听
|
||||
signalListen(ctx, signalHandlerForOverall)
|
||||
select {
|
||||
case <-serverCloseSignal:
|
||||
// ...
|
||||
service.CronClient().Stop(ctx)
|
||||
crons.StopALL()
|
||||
serverWg.Done()
|
||||
}
|
||||
|
||||
g.Log().Debug(ctx, "cron successfully closed ..")
|
||||
return
|
||||
},
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package cmd
|
||||
|
||||
import (
|
||||
@ -11,6 +10,12 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"hotgo/utility/simple"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
serverCloseSignal = make(chan struct{}, 1)
|
||||
serverWg = sync.WaitGroup{}
|
||||
)
|
||||
|
||||
func signalHandlerForOverall(sig os.Signal) {
|
||||
|
@ -10,13 +10,11 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"hotgo/internal/crons"
|
||||
"hotgo/internal/library/addons"
|
||||
"hotgo/internal/library/casbin"
|
||||
"hotgo/internal/router"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/internal/websocket"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -77,13 +75,20 @@ var (
|
||||
// https
|
||||
setSSL(ctx, s)
|
||||
|
||||
// 退出信号监听
|
||||
signalListen(ctx, func(sig os.Signal) {
|
||||
s.Shutdown()
|
||||
crons.StopALL()
|
||||
websocket.Stop()
|
||||
service.TCPServer().Stop(ctx)
|
||||
})
|
||||
serverWg.Add(1)
|
||||
|
||||
// 信号监听
|
||||
signalListen(ctx, signalHandlerForOverall)
|
||||
go func() {
|
||||
select {
|
||||
case <-serverCloseSignal:
|
||||
websocket.Stop()
|
||||
service.TCPServer().Stop(ctx)
|
||||
s.Shutdown() // 主服务建议放在最后一个关闭
|
||||
g.Log().Debug(ctx, "http successfully closed ..")
|
||||
serverWg.Done()
|
||||
}
|
||||
}()
|
||||
|
||||
// Just run the server.
|
||||
s.Run()
|
||||
|
@ -25,12 +25,14 @@ var (
|
||||
g.Log().Debug(ctx, "start queue consumer success..")
|
||||
})
|
||||
|
||||
serverWg.Add(1)
|
||||
|
||||
// 信号监听
|
||||
signalListen(ctx, signalHandlerForOverall)
|
||||
|
||||
select {
|
||||
case <-serverCloseSignal:
|
||||
// ...
|
||||
serverWg.Done()
|
||||
}
|
||||
|
||||
g.Log().Debug(ctx, "queue successfully closed ..")
|
||||
|
@ -7,7 +7,9 @@ package consts
|
||||
|
||||
import "github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
// RequestEncryptKey 请求加密密钥用于敏感数据加密,16位字符,前后端需保持一致。安全起见请修改此值
|
||||
// RequestEncryptKey
|
||||
// 请求加密密钥用于敏感数据加密,16位字符,前后端需保持一致
|
||||
// 安全起见,生产环境运行时请注意修改
|
||||
var RequestEncryptKey = []byte("f080a463654b2279")
|
||||
|
||||
// 配置数据类型
|
||||
|
@ -27,6 +27,7 @@ func Build(ctx context.Context, sk Skeleton, conf *model.BuildAddonConfig) (err
|
||||
"@{.description}": sk.Description,
|
||||
"@{.author}": sk.Author,
|
||||
"@{.version}": sk.Version,
|
||||
"@{.hgVersion}": consts.VersionApp, // HG 版本
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -195,7 +195,9 @@ func (client *Client) connect() {
|
||||
reconnect:
|
||||
conn := client.dial()
|
||||
if conn == nil {
|
||||
client.Logger.Debugf(client.Ctx, "client dial failed")
|
||||
if !client.stopFlag {
|
||||
client.Logger.Debugf(client.Ctx, "client dial failed")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -311,6 +313,11 @@ func (client *Client) Stop() {
|
||||
client.Close()
|
||||
}
|
||||
|
||||
// IsStop 是否已停止
|
||||
func (client *Client) IsStop() bool {
|
||||
return client.stopFlag
|
||||
}
|
||||
|
||||
// Destroy 销毁当前连接
|
||||
func (client *Client) Destroy() {
|
||||
client.stopCron()
|
||||
|
@ -294,6 +294,11 @@ func (server *Server) Close() {
|
||||
server.wgLn.Wait()
|
||||
}
|
||||
|
||||
// IsClose 服务是否关闭
|
||||
func (server *Server) IsClose() bool {
|
||||
return server.closeFlag
|
||||
}
|
||||
|
||||
// Write 向指定客户端发送消息
|
||||
func (server *Server) Write(conn *gtcp.Conn, data interface{}) (err error) {
|
||||
if server.closeFlag {
|
||||
|
@ -99,6 +99,8 @@ func Logout(r *ghttp.Request) (err error) {
|
||||
|
||||
claims, err := parseToken(ctx, header)
|
||||
if err != nil {
|
||||
g.Log().Debugf(ctx, "logout parseToken err:%+v", err)
|
||||
err = errorLogin
|
||||
return
|
||||
}
|
||||
|
||||
@ -138,10 +140,13 @@ func ParseLoginUser(r *ghttp.Request) (user *model.Identity, err error) {
|
||||
|
||||
claims, err := parseToken(ctx, header)
|
||||
if err != nil {
|
||||
g.Log().Debugf(ctx, "parseToken err:%+v", err)
|
||||
err = errorLogin
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
// 认证key
|
||||
authKey = GetAuthKey(header)
|
||||
// 登录token
|
||||
tokenKey = GetTokenKey(claims.App, authKey)
|
||||
@ -285,7 +290,7 @@ func GetAuthorization(r *ghttp.Request) string {
|
||||
|
||||
// GetAuthKey 认证key
|
||||
func GetAuthKey(token string) string {
|
||||
return gmd5.MustEncryptString(token)
|
||||
return gmd5.MustEncryptString("hotgo" + token)
|
||||
}
|
||||
|
||||
// GetTokenKey 令牌缓存key
|
||||
|
@ -227,18 +227,18 @@ func (s *sAdminMember) UpdateMobile(ctx context.Context, in adminin.MemberUpdate
|
||||
return err
|
||||
}
|
||||
|
||||
var memberInfo *entity.AdminMember
|
||||
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
|
||||
var mb *entity.AdminMember
|
||||
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&mb); err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return err
|
||||
}
|
||||
|
||||
if memberInfo == nil {
|
||||
if mb == nil {
|
||||
err = gerror.New("用户信息不存在")
|
||||
return err
|
||||
}
|
||||
|
||||
if memberInfo.Mobile == in.Mobile {
|
||||
if mb.Mobile == in.Mobile {
|
||||
err = gerror.New("新旧手机号不能一样")
|
||||
return
|
||||
}
|
||||
@ -249,10 +249,10 @@ func (s *sAdminMember) UpdateMobile(ctx context.Context, in adminin.MemberUpdate
|
||||
}
|
||||
|
||||
// 存在原绑定号码,需要进行验证
|
||||
if memberInfo.Mobile != "" {
|
||||
if mb.Mobile != "" {
|
||||
err = service.SysSmsLog().VerifyCode(ctx, sysin.VerifyCodeInp{
|
||||
Event: consts.SmsTemplateBind,
|
||||
Mobile: memberInfo.Mobile,
|
||||
Mobile: mb.Mobile,
|
||||
Code: in.Code,
|
||||
})
|
||||
if err != nil {
|
||||
@ -264,8 +264,7 @@ func (s *sAdminMember) UpdateMobile(ctx context.Context, in adminin.MemberUpdate
|
||||
dao.AdminMember.Columns().Mobile: in.Mobile,
|
||||
}
|
||||
|
||||
_, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update()
|
||||
if err != nil {
|
||||
if _, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update(); err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return err
|
||||
}
|
||||
@ -281,13 +280,13 @@ func (s *sAdminMember) UpdateProfile(ctx context.Context, in adminin.MemberUpdat
|
||||
return err
|
||||
}
|
||||
|
||||
var memberInfo *entity.AdminMember
|
||||
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
|
||||
var mb *entity.AdminMember
|
||||
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&mb); err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return err
|
||||
}
|
||||
|
||||
if memberInfo == nil {
|
||||
if mb == nil {
|
||||
err = gerror.New("用户信息不存在")
|
||||
return err
|
||||
}
|
||||
@ -302,8 +301,7 @@ func (s *sAdminMember) UpdateProfile(ctx context.Context, in adminin.MemberUpdat
|
||||
dao.AdminMember.Columns().Address: in.Address,
|
||||
}
|
||||
|
||||
_, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update()
|
||||
if err != nil {
|
||||
if _, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update(); err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return err
|
||||
}
|
||||
@ -718,7 +716,9 @@ func (s *sAdminMember) MemberLoginStat(ctx context.Context, in adminin.MemberLog
|
||||
|
||||
// GetIdByCode 通过邀请码获取用户ID
|
||||
func (s *sAdminMember) GetIdByCode(ctx context.Context, in adminin.GetIdByCodeInp) (res *adminin.GetIdByCodeModel, err error) {
|
||||
err = dao.AdminMember.Ctx(ctx).Fields(adminin.GetIdByCodeModel{}).Where("invite_code", in.Code).Scan(&res)
|
||||
if err = dao.AdminMember.Ctx(ctx).Fields(adminin.GetIdByCodeModel{}).Where("invite_code", in.Code).Scan(&res); err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -728,6 +728,9 @@ func (s *sAdminMember) Select(ctx context.Context, in adminin.MemberSelectInp) (
|
||||
Fields("id as value,real_name as label,username,avatar").
|
||||
Handler(handler.FilterAuthWithField("id")).
|
||||
Scan(&res)
|
||||
if err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ import (
|
||||
"hotgo/internal/dao"
|
||||
"hotgo/internal/library/token"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/model/do"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
@ -255,16 +254,6 @@ func (s *sAdminSite) handleLogin(ctx context.Context, mb *entity.AdminMember) (r
|
||||
return nil, err
|
||||
}
|
||||
|
||||
update := do.AdminMember{
|
||||
LastActiveAt: user.LoginAt,
|
||||
}
|
||||
|
||||
// 更新登录信息
|
||||
if _, err = dao.AdminMember.Ctx(ctx).Data(update).Where(do.AdminMember{Id: mb.Id}).Update(); err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return
|
||||
}
|
||||
|
||||
res = &adminin.LoginModel{
|
||||
Username: user.Username,
|
||||
Id: user.Id,
|
||||
|
@ -20,9 +20,9 @@ func (s *sHook) accessLog(r *ghttp.Request) {
|
||||
if r.IsFileRequest() {
|
||||
return
|
||||
}
|
||||
|
||||
var ctx = contexts.Detach(r.Context())
|
||||
modelCtx := contexts.Get(ctx)
|
||||
if modelCtx == nil {
|
||||
if contexts.Get(ctx) == nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,6 @@ func (s *sHook) lastAdminActive(r *ghttp.Request) {
|
||||
_, err := g.Model("admin_member").
|
||||
Ctx(ctx).
|
||||
Where("id", member.Id).
|
||||
WhereLT("last_active_at", gtime.Now()).
|
||||
Data(g.Map{"last_active_at": gtime.Now()}).
|
||||
Update()
|
||||
if err != nil {
|
||||
|
@ -101,16 +101,16 @@ func responseJson(r *ghttp.Request) {
|
||||
|
||||
if err = r.GetError(); err != nil {
|
||||
// 记录到自定义错误日志文件
|
||||
g.Log().Warningf(ctx, "exception:%v", err)
|
||||
g.Log().Stdout(false).Printf(ctx, "exception:%v", err)
|
||||
|
||||
code = gerror.Code(err).Code()
|
||||
|
||||
// 是否输出错误到页面
|
||||
if g.Cfg().MustGet(ctx, "hotgo.debug", true).Bool() {
|
||||
message = err.Error()
|
||||
message = gerror.Current(err).Error()
|
||||
data = charset.ParseErrStack(err)
|
||||
} else {
|
||||
message = consts.ErrorMessage(err)
|
||||
message = consts.ErrorMessage(gerror.Current(err))
|
||||
}
|
||||
} else {
|
||||
data = r.GetHandlerResponse()
|
||||
|
@ -105,7 +105,7 @@ func (s *sSysLog) AutoLog(ctx context.Context) error {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
g.Log().Error(ctx, "autoLog err:%+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -75,7 +75,7 @@ func (s *sAuthClient) Start(ctx context.Context) {
|
||||
|
||||
// Stop 停止服务
|
||||
func (s *sAuthClient) Stop(ctx context.Context) {
|
||||
if s.client != nil {
|
||||
if s.client != nil && !s.client.IsStop() {
|
||||
s.client.Stop()
|
||||
g.Log().Debug(ctx, "AuthClient stop..")
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func (s *sCronClient) Start(ctx context.Context) {
|
||||
|
||||
// Stop 停止服务
|
||||
func (s *sCronClient) Stop(ctx context.Context) {
|
||||
if s.client != nil {
|
||||
if s.client != nil && !s.client.IsStop() {
|
||||
s.client.Stop()
|
||||
g.Log().Debug(ctx, "CronClient stop..")
|
||||
}
|
||||
|
@ -53,15 +53,17 @@ func (s *sTCPServer) Start(ctx context.Context) {
|
||||
})
|
||||
|
||||
// 服务监听
|
||||
if err := s.serv.Listen(); err != nil {
|
||||
g.Log().Warningf(ctx, "TCPServer Listen err:%v", err)
|
||||
if err = s.serv.Listen(); err != nil {
|
||||
if !s.serv.IsClose() {
|
||||
g.Log().Warningf(ctx, "TCPServer Listen err:%v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Stop 关闭服务
|
||||
func (s *sTCPServer) Stop(ctx context.Context) {
|
||||
if s.serv != nil {
|
||||
if s.serv != nil && !s.serv.IsClose() {
|
||||
s.serv.Close()
|
||||
g.Log().Debug(ctx, "TCPServer stop..")
|
||||
}
|
||||
|
@ -2,11 +2,9 @@ package adminin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/encoding/gbase64"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/utility/encrypt"
|
||||
"hotgo/utility/simple"
|
||||
)
|
||||
|
||||
// RegisterInp 账号注册
|
||||
@ -20,18 +18,11 @@ type RegisterInp struct {
|
||||
|
||||
func (in *RegisterInp) Filter(ctx context.Context) (err error) {
|
||||
// 解密密码
|
||||
str, err := gbase64.Decode([]byte(in.Password))
|
||||
password, err := simple.DecryptText(in.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
str, err = encrypt.AesECBDecrypt(str, consts.RequestEncryptKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
password := string(str)
|
||||
|
||||
if err = g.Validator().Data(password).Rules("password").Messages("密码长度在6~18之间").Run(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
### 迁移或安装
|
||||
|
||||
1、安装 HotGo (2.1.4及以上)
|
||||
1、安装 HotGo (@{.hgVersion}及以上)
|
||||
|
||||
项目介绍:https://github.com/bufanyun/hotgo
|
||||
|
||||
|
@ -18,20 +18,30 @@ import (
|
||||
"hotgo/utility/encrypt"
|
||||
)
|
||||
|
||||
// DecryptText 解密文本
|
||||
func DecryptText(text string) (string, error) {
|
||||
str, err := gbase64.Decode([]byte(text))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
str, err = encrypt.AesECBDecrypt(str, consts.RequestEncryptKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(str), nil
|
||||
}
|
||||
|
||||
// CheckPassword 检查密码
|
||||
func CheckPassword(input, salt, hash string) (err error) {
|
||||
// 解密密码
|
||||
password, err := gbase64.Decode([]byte(input))
|
||||
password, err := DecryptText(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
password, err = encrypt.AesECBDecrypt(password, consts.RequestEncryptKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hash != gmd5.MustEncryptString(string(password)+salt) {
|
||||
if hash != gmd5.MustEncryptString(password+salt) {
|
||||
err = gerror.New("用户密码不正确")
|
||||
return
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<QuillEditor
|
||||
ref="quillEditor"
|
||||
ref="quillEditorRef"
|
||||
toolbar="full"
|
||||
v-model:content="content"
|
||||
@ready="readyQuill"
|
||||
@ -33,7 +33,7 @@
|
||||
const emit = defineEmits(['update:value']);
|
||||
const message = useMessage();
|
||||
const initFinish = ref(false);
|
||||
const quillEditor = ref();
|
||||
const quillEditorRef = ref();
|
||||
const content = ref();
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
value: '',
|
||||
@ -41,14 +41,14 @@
|
||||
});
|
||||
|
||||
function readyQuill() {
|
||||
quillEditor.value.setHTML(props.value);
|
||||
quillEditorRef.value.setHTML(props.value);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(newValue) => {
|
||||
if (!initFinish.value) {
|
||||
quillEditor.value?.setHTML(newValue);
|
||||
quillEditorRef.value?.setHTML(newValue);
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -67,7 +67,7 @@
|
||||
}
|
||||
|
||||
function onUpdateContent() {
|
||||
emit('update:value', quillEditor.value.getHTML());
|
||||
emit('update:value', quillEditorRef.value.getHTML());
|
||||
}
|
||||
|
||||
function checkFileType(map: string[], fileType: string) {
|
||||
|
Loading…
Reference in New Issue
Block a user