修复字典选项和公告提示加载异常,优化tcp和websocket消息处理

This commit is contained in:
孟帅 2023-06-25 19:22:08 +08:00
parent 773f26b479
commit 4a06a895b3
15 changed files with 114 additions and 53 deletions

View File

@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package common package common
import ( import (

View File

@ -57,7 +57,7 @@ func (dao *sysDictTypeDao) GetTypes(ctx context.Context, id int64) (types []stri
columns, err := dao.Ctx(ctx).Fields("type"). columns, err := dao.Ctx(ctx).Fields("type").
Where("id", id). Where("id", id).
WhereOr("pid", id). WhereOr("pid", id).
Where("status", consts.StatusEnabled).All() Where("status", consts.StatusEnabled).Array()
types = g.NewVar(columns).Strings() types = g.NewVar(columns).Strings()
return return
} }

View File

@ -12,6 +12,7 @@ import (
"github.com/gogf/gf/v2/net/gtcp" "github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog" "github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/grpool"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"hotgo/utility/simple" "hotgo/utility/simple"
"reflect" "reflect"
@ -49,6 +50,7 @@ type Client struct {
closeEvent CallbackEvent // 连接关闭事件 closeEvent CallbackEvent // 连接关闭事件
sync.Mutex // 状态锁 sync.Mutex // 状态锁
heartbeat int64 // 心跳 heartbeat int64 // 心跳
msgGo *grpool.Pool // 消息处理协程池
routers map[string]RouterHandler // 已注册的路由 routers map[string]RouterHandler // 已注册的路由
conn *gtcp.Conn // 连接对象 conn *gtcp.Conn // 连接对象
wg sync.WaitGroup // 状态控制 wg sync.WaitGroup // 状态控制
@ -100,7 +102,8 @@ func NewClient(config *ClientConfig) (client *Client, err error) {
client.timeout = config.Timeout client.timeout = config.Timeout
} }
client.rpc = NewRpc(client.Ctx) client.msgGo = grpool.New(5)
client.rpc = NewRpc(client.Ctx, client.msgGo, client.Logger)
return return
} }
@ -252,8 +255,7 @@ func (client *Client) read() {
switch msg.Router { switch msg.Router {
case "ResponseServerLogin", "ResponseServerHeartbeat": // 服务登录、心跳无需验证签名 case "ResponseServerLogin", "ResponseServerHeartbeat": // 服务登录、心跳无需验证签名
ctx, cancel := initCtx(gctx.New(), &Context{}) client.doHandleRouterMsg(initCtx(gctx.New(), &Context{}), f, msg.Data)
doHandleRouterMsg(f, ctx, cancel, msg.Data)
default: // 通用路由消息处理 default: // 通用路由消息处理
in, err := VerifySign(msg.Data, client.auth.AppId, client.auth.SecretKey) in, err := VerifySign(msg.Data, client.auth.AppId, client.auth.SecretKey)
if err != nil { if err != nil {
@ -261,18 +263,18 @@ func (client *Client) read() {
continue continue
} }
ctx, cancel := initCtx(gctx.New(), &Context{ ctx := initCtx(gctx.New(), &Context{
Conn: client.conn, Conn: client.conn,
Auth: client.auth, Auth: client.auth,
TraceID: in.TraceID, TraceID: in.TraceID,
}) })
// 响应rpc消息 // 响应rpc消息
if client.rpc.HandleMsg(ctx, cancel, msg.Data) { if client.rpc.HandleMsg(ctx, msg.Data) {
return return
} }
doHandleRouterMsg(f, ctx, cancel, msg.Data) client.doHandleRouterMsg(ctx, f, msg.Data)
} }
} }
}) })
@ -377,3 +379,23 @@ func (client *Client) RpcRequest(ctx context.Context, data interface{}) (res int
_ = client.Write(data) _ = client.Write(data)
}) })
} }
// doHandleRouterMsg 处理路由消息
func (client *Client) doHandleRouterMsg(ctx context.Context, fun RouterHandler, args ...interface{}) {
ctx, cancel := context.WithCancel(ctx)
err := client.msgGo.AddWithRecover(ctx,
func(ctx context.Context) {
fun(ctx, args...)
cancel()
},
func(ctx context.Context, err error) {
client.Logger.Warningf(ctx, "doHandleRouterMsg msgGo exec err:%+v", err)
cancel()
},
)
if err != nil {
client.Logger.Warningf(ctx, "doHandleRouterMsg msgGo Add err:%+v", err)
return
}
}

View File

@ -12,14 +12,13 @@ import (
) )
// initCtx 初始化上下文对象指针到上下文对象中,以便后续的请求流程中可以修改 // initCtx 初始化上下文对象指针到上下文对象中,以便后续的请求流程中可以修改
func initCtx(ctx context.Context, model *Context) (newCtx context.Context, cancel context.CancelFunc) { func initCtx(ctx context.Context, model *Context) (newCtx context.Context) {
if model.TraceID != "" { if model.TraceID != "" {
newCtx, _ = gtrace.WithTraceID(ctx, model.TraceID) newCtx, _ = gtrace.WithTraceID(ctx, model.TraceID)
} else { } else {
newCtx = ctx newCtx = ctx
} }
newCtx = context.WithValue(newCtx, consts.ContextTCPKey, model) newCtx = context.WithValue(newCtx, consts.ContextTCPKey, model)
newCtx, cancel = context.WithCancel(newCtx)
return return
} }

View File

@ -10,13 +10,9 @@ import (
"encoding/json" "encoding/json"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/gtcp" "github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/grpool"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
) )
// GoPool 初始化一个协程池,用于处理消息处理
var GoPool = grpool.New(20)
// RouterHandler 路由消息处理器 // RouterHandler 路由消息处理器
type RouterHandler func(ctx context.Context, args ...interface{}) type RouterHandler func(ctx context.Context, args ...interface{})
@ -64,11 +60,3 @@ func MsgPkg(data interface{}, auth *AuthMeta, traceID string) string {
} }
return msg.TraceID return msg.TraceID
} }
// doHandleRouterMsg 处理路由消息
func doHandleRouterMsg(fun RouterHandler, ctx context.Context, cancel context.CancelFunc, args ...interface{}) {
_ = GoPool.Add(ctx, func(ctx context.Context) {
fun(ctx, args...)
cancel()
})
}

View File

@ -10,6 +10,8 @@ import (
"fmt" "fmt"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/gtcp" "github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/grpool"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/utility/simple" "hotgo/utility/simple"
"sync" "sync"
@ -20,6 +22,8 @@ type Rpc struct {
ctx context.Context ctx context.Context
mutex sync.Mutex mutex sync.Mutex
callbacks map[string]RpcRespFunc callbacks map[string]RpcRespFunc
msgGo *grpool.Pool // 消息处理协程池
logger *glog.Logger // 日志处理器
} }
// RpcResp 响应结构 // RpcResp 响应结构
@ -31,10 +35,12 @@ type RpcResp struct {
type RpcRespFunc func(resp interface{}, err error) type RpcRespFunc func(resp interface{}, err error)
// NewRpc 初始化一个rpc协议 // NewRpc 初始化一个rpc协议
func NewRpc(ctx context.Context) *Rpc { func NewRpc(ctx context.Context, msgGo *grpool.Pool, logger *glog.Logger) *Rpc {
return &Rpc{ return &Rpc{
ctx: ctx, ctx: ctx,
callbacks: make(map[string]RpcRespFunc), callbacks: make(map[string]RpcRespFunc),
msgGo: msgGo,
logger: logger,
} }
} }
@ -44,7 +50,7 @@ func (r *Rpc) GetCallId(client *gtcp.Conn, traceID string) string {
} }
// HandleMsg 处理rpc消息 // HandleMsg 处理rpc消息
func (r *Rpc) HandleMsg(ctx context.Context, cancel context.CancelFunc, data interface{}) bool { func (r *Rpc) HandleMsg(ctx context.Context, data interface{}) bool {
user := GetCtx(ctx) user := GetCtx(ctx)
callId := r.GetCallId(user.Conn, user.TraceID) callId := r.GetCallId(user.Conn, user.TraceID)
@ -53,10 +59,19 @@ func (r *Rpc) HandleMsg(ctx context.Context, cancel context.CancelFunc, data int
delete(r.callbacks, callId) delete(r.callbacks, callId)
r.mutex.Unlock() r.mutex.Unlock()
simple.SafeGo(ctx, func(ctx context.Context) { ctx, cancel := context.WithCancel(ctx)
err := r.msgGo.AddWithRecover(ctx, func(ctx context.Context) {
call(data, nil) call(data, nil)
cancel() cancel()
}, func(ctx context.Context, err error) {
r.logger.Warningf(ctx, "rpc HandleMsg msgGo exec err:%+v", err)
cancel()
}) })
if err != nil {
r.logger.Warningf(ctx, "rpc HandleMsg msgGo Add err:%+v", err)
}
return true return true
} }
return false return false

View File

@ -12,6 +12,7 @@ import (
"github.com/gogf/gf/v2/net/gtcp" "github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog" "github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/grpool"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/utility/simple" "hotgo/utility/simple"
"reflect" "reflect"
@ -45,6 +46,7 @@ type Server struct {
closeFlag bool // 服务关闭标签 closeFlag bool // 服务关闭标签
clients map[string]*ClientConn // 已登录的认证客户端 clients map[string]*ClientConn // 已登录的认证客户端
mutexConns sync.Mutex // 连接锁,主要用于客户端上下线 mutexConns sync.Mutex // 连接锁,主要用于客户端上下线
msgGo *grpool.Pool // 消息处理协程池
cronRouters map[string]RouterHandler // 定时任务路由 cronRouters map[string]RouterHandler // 定时任务路由
queueRouters map[string]RouterHandler // 队列路由 queueRouters map[string]RouterHandler // 队列路由
authRouters map[string]RouterHandler // 任务路由 authRouters map[string]RouterHandler // 任务路由
@ -75,8 +77,8 @@ func NewServer(config *ServerConfig) (server *Server, err error) {
server.clients = make(map[string]*ClientConn) server.clients = make(map[string]*ClientConn)
server.closeFlag = false server.closeFlag = false
server.Logger = g.Log("tcpServer") server.Logger = g.Log("tcpServer")
server.rpc = NewRpc(server.Ctx) server.msgGo = grpool.New(20)
server.rpc = NewRpc(server.Ctx, server.msgGo, server.Logger)
server.startCron() server.startCron()
return return
} }
@ -103,18 +105,18 @@ func (server *Server) accept(conn *gtcp.Conn) {
switch msg.Router { switch msg.Router {
case "ServerLogin": // 服务登录 case "ServerLogin": // 服务登录
// 初始化上下文 // 初始化上下文
ctx, cancel := initCtx(gctx.New(), &Context{ ctx := initCtx(gctx.New(), &Context{
Conn: conn, Conn: conn,
}) })
doHandleRouterMsg(server.onServerLogin, ctx, cancel, msg.Data) server.doHandleRouterMsg(ctx, server.onServerLogin, msg.Data)
case "ServerHeartbeat": // 心跳 case "ServerHeartbeat": // 心跳
if client == nil { if client == nil {
server.Logger.Infof(server.Ctx, "conn not connected, ignore the heartbeat, msg:%+v", msg) server.Logger.Infof(server.Ctx, "conn not connected, ignore the heartbeat, msg:%+v", msg)
continue continue
} }
// 初始化上下文 // 初始化上下文
ctx, cancel := initCtx(gctx.New(), &Context{}) ctx := initCtx(gctx.New(), &Context{})
doHandleRouterMsg(server.onServerHeartbeat, ctx, cancel, msg.Data, client) server.doHandleRouterMsg(ctx, server.onServerHeartbeat, msg.Data, client)
default: // 通用路由消息处理 default: // 通用路由消息处理
if client == nil { if client == nil {
server.Logger.Warningf(server.Ctx, "conn is not logged in but sends a routing message. actively conn disconnect, msg:%+v", msg) server.Logger.Warningf(server.Ctx, "conn is not logged in but sends a routing message. actively conn disconnect, msg:%+v", msg)
@ -137,14 +139,14 @@ func (server *Server) handleRouterMsg(msg *Message, client *ClientConn) {
} }
// 初始化上下文 // 初始化上下文
ctx, cancel := initCtx(gctx.New(), &Context{ ctx := initCtx(gctx.New(), &Context{
Conn: client.Conn, Conn: client.Conn,
Auth: client.Auth, Auth: client.Auth,
TraceID: in.TraceID, TraceID: in.TraceID,
}) })
// 响应rpc消息 // 响应rpc消息
if server.rpc.HandleMsg(ctx, cancel, msg.Data) { if server.rpc.HandleMsg(ctx, msg.Data) {
return return
} }
@ -159,7 +161,7 @@ func (server *Server) handleRouterMsg(msg *Message, client *ClientConn) {
return return
} }
doHandleRouterMsg(f, ctx, cancel, msg.Data) server.doHandleRouterMsg(ctx, f, msg.Data)
} }
switch client.Auth.Group { switch client.Auth.Group {
@ -174,6 +176,26 @@ func (server *Server) handleRouterMsg(msg *Message, client *ClientConn) {
} }
} }
// doHandleRouterMsg 处理路由消息
func (server *Server) doHandleRouterMsg(ctx context.Context, fun RouterHandler, args ...interface{}) {
ctx, cancel := context.WithCancel(ctx)
err := server.msgGo.AddWithRecover(ctx,
func(ctx context.Context) {
fun(ctx, args...)
cancel()
},
func(ctx context.Context, err error) {
server.Logger.Warningf(ctx, "doHandleRouterMsg msgGo exec err:%+v", err)
cancel()
},
)
if err != nil {
server.Logger.Warningf(ctx, "doHandleRouterMsg msgGo Add err:%+v", err)
return
}
}
// getLoginConn 获取指定已登录的连接 // getLoginConn 获取指定已登录的连接
func (server *Server) getLoginConn(conn *gtcp.Conn) *ClientConn { func (server *Server) getLoginConn(conn *gtcp.Conn) *ClientConn {
client, ok := server.clients[conn.RemoteAddr().String()] client, ok := server.clients[conn.RemoteAddr().String()]

View File

@ -190,13 +190,13 @@ func (s *sAdminDept) List(ctx context.Context, in adminin.DeptListInp) (res *adm
// 部门名称 // 部门名称
if in.Name != "" { if in.Name != "" {
columns, err := dao.AdminDept.Ctx(ctx).Fields("pid").WhereLike("name", "%"+in.Name+"%").All() columns, err := dao.AdminDept.Ctx(ctx).Fields("pid").WhereLike("name", "%"+in.Name+"%").Array()
if err != nil { if err != nil {
err = gerror.Wrap(err, "过滤部门列表失败-1") err = gerror.Wrap(err, "过滤部门列表失败-1")
return nil, err return nil, err
} }
ds := g.NewVar(columns.Array()).Int64s() ds := g.NewVar(columns).Int64s()
ids = append(ids, ds...) ids = append(ids, ds...)
pids = append(pids, ds...) pids = append(pids, ds...)
if len(ids) == 0 { if len(ids) == 0 {
@ -205,13 +205,13 @@ func (s *sAdminDept) List(ctx context.Context, in adminin.DeptListInp) (res *adm
} }
if in.Code != "" { if in.Code != "" {
columns, err := dao.AdminDept.Ctx(ctx).Fields("pid").WhereLike("code", "%"+in.Code+"%").All() columns, err := dao.AdminDept.Ctx(ctx).Fields("pid").WhereLike("code", "%"+in.Code+"%").Array()
if err != nil { if err != nil {
err = gerror.Wrap(err, "过滤部门列表失败-2") err = gerror.Wrap(err, "过滤部门列表失败-2")
return nil, err return nil, err
} }
ds := g.NewVar(columns.Array()).Int64s() ds := g.NewVar(columns).Int64s()
ids = append(ids, ds...) ids = append(ids, ds...)
pids = append(pids, ds...) pids = append(pids, ds...)
if len(ids) == 0 { if len(ids) == 0 {

View File

@ -585,16 +585,13 @@ func (s *sAdminMember) List(ctx context.Context, in adminin.MemberListInp) (list
} }
for _, v := range list { for _, v := range list {
columns, err := dao.AdminMemberPost.Ctx(ctx). columns, err := dao.AdminMemberPost.Ctx(ctx).Fields(dao.AdminMemberPost.Columns().PostId).Where(dao.AdminMemberPost.Columns().MemberId, v.Id).Array()
Fields(dao.AdminMemberPost.Columns().PostId).
Where(dao.AdminMemberPost.Columns().MemberId, v.Id).All()
if err != nil { if err != nil {
err = gerror.Wrap(err, "获取用户岗位数据失败!") err = gerror.Wrap(err, "获取用户岗位数据失败!")
return nil, 0, err return nil, 0, err
} }
v.PostIds = g.NewVar(columns.Array()).Int64s() v.PostIds = g.NewVar(columns).Int64s()
} }
return return
} }

View File

@ -81,6 +81,7 @@ func (s *sAdminMenu) VerifyUnique(ctx context.Context, in adminin.VerifyUniqueIn
func (s *sAdminMenu) Edit(ctx context.Context, in adminin.MenuEditInp) (err error) { func (s *sAdminMenu) Edit(ctx context.Context, in adminin.MenuEditInp) (err error) {
// 验证唯一性 // 验证唯一性
err = s.VerifyUnique(ctx, adminin.VerifyUniqueInp{ err = s.VerifyUnique(ctx, adminin.VerifyUniqueInp{
Id: in.Id,
Where: g.Map{ Where: g.Map{
dao.AdminMenu.Columns().Title: in.Title, dao.AdminMenu.Columns().Title: in.Title,
dao.AdminMenu.Columns().Name: in.Name, dao.AdminMenu.Columns().Name: in.Name,

View File

@ -327,7 +327,7 @@ func (s *sAdminNotice) messageIds(ctx context.Context, memberId int64) (ids []in
Where("status", consts.StatusEnabled). Where("status", consts.StatusEnabled).
Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(memberId)+"')))", Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(memberId)+"')))",
[]int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}, consts.NoticeTypeLetter, []int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}, consts.NoticeTypeLetter,
).All() ).Array()
if err != nil { if err != nil {
err = gerror.Wrap(err, "获取我的消息失败!") err = gerror.Wrap(err, "获取我的消息失败!")
return return

View File

@ -29,10 +29,15 @@ func (q *qServeLog) GetTopic() string {
} }
// Handle 处理消息 // Handle 处理消息
func (q *qServeLog) Handle(ctx context.Context, mqMsg queue.MqMsg) (err error) { func (q *qServeLog) Handle(ctx context.Context, mqMsg queue.MqMsg) error {
var data entity.SysServeLog var data entity.SysServeLog
if err = json.Unmarshal(mqMsg.Body, &data); err != nil { if err := json.Unmarshal(mqMsg.Body, &data); err != nil {
return err queue.Logger().Infof(ctx, "ServeLog Handle Unmarshal err:%+v", err)
return nil
} }
return service.SysServeLog().RealWrite(ctx, data)
if err := service.SysServeLog().RealWrite(ctx, data); err != nil {
queue.Logger().Infof(ctx, "ServeLog Handle Write err:%+v", err)
}
return nil
} }

View File

@ -43,5 +43,4 @@ func WebSocket(ctx context.Context, group *ghttp.RouterGroup) {
"admin/monitor/trends": admin.Monitor.Trends, // 后台监控,动态数据 "admin/monitor/trends": admin.Monitor.Trends, // 后台监控,动态数据
"admin/monitor/runInfo": admin.Monitor.RunInfo, // 后台监控,运行信息 "admin/monitor/runInfo": admin.Monitor.RunInfo, // 后台监控,运行信息
}) })
} }

View File

@ -3,13 +3,13 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package websocket package websocket
import ( import (
"context" "context"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/grpool"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"net/http" "net/http"
@ -19,6 +19,7 @@ var (
ctxManager context.Context // 主上下文 ctxManager context.Context // 主上下文
clientManager = NewClientManager() // 客户端管理 clientManager = NewClientManager() // 客户端管理
routers = make(map[string]EventHandler) // 消息路由 routers = make(map[string]EventHandler) // 消息路由
msgGo = grpool.New(20)
upGrader = websocket.Upgrader{ upGrader = websocket.Upgrader{
ReadBufferSize: 1024, ReadBufferSize: 1024,
WriteBufferSize: 1024, WriteBufferSize: 1024,

View File

@ -3,10 +3,10 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package websocket package websocket
import ( import (
"context"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
"runtime/debug" "runtime/debug"
@ -36,7 +36,20 @@ func handlerMsg(client *Client, message []byte) {
g.Log().Warningf(ctxManager, "handlerMsg function id %v: not registered", request.Event) g.Log().Warningf(ctxManager, "handlerMsg function id %v: not registered", request.Event)
return return
} }
fun(client, request)
err := msgGo.AddWithRecover(ctxManager,
func(ctx context.Context) {
fun(client, request)
},
func(ctx context.Context, err error) {
g.Log().Warningf(ctxManager, "handlerMsg msgGo exec err:%+v", err)
},
)
if err != nil {
g.Log().Warningf(ctxManager, "handlerMsg msgGo Add err:%+v", err)
return
}
} }
// RegisterMsg 注册消息 // RegisterMsg 注册消息