This commit is contained in:
孟帅
2023-05-10 23:54:50 +08:00
parent bbe655a4d8
commit 49a96750bf
314 changed files with 15138 additions and 6244 deletions

View File

@@ -3,7 +3,6 @@ package tcp
import (
"context"
"fmt"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gtcp"
@@ -36,6 +35,7 @@ type Client struct {
IsLogin bool // 是否已登录
addr string
auth *AuthMeta
rpc *Rpc
timeout time.Duration
connectInterval time.Duration
maxConnectCount uint
@@ -103,6 +103,7 @@ func NewClient(config *ClientConfig) (client *Client, err error) {
client.timeout = config.Timeout
}
client.rpc = NewRpc(client.Ctx)
return
}
@@ -248,7 +249,31 @@ func (client *Client) read() {
client.Logger.Debugf(client.Ctx, "client RecvPkg invalid message: %+v", msg)
continue
}
f(msg.Data, client.conn)
switch msg.Router {
case "ResponseServerLogin", "ResponseServerHeartbeat": // 服务登录、心跳无需验证签名
ctx, cancel := initCtx(gctx.New(), &Context{})
doHandleRouterMsg(f, ctx, cancel, msg.Data)
default: // 通用路由消息处理
in, err := VerifySign(msg.Data, client.auth.AppId, client.auth.SecretKey)
if err != nil {
client.Logger.Warningf(client.Ctx, "client read VerifySign err:%+v message: %+v", err, msg)
continue
}
ctx, cancel := initCtx(gctx.New(), &Context{
Conn: client.conn,
Auth: client.auth,
TraceID: in.TraceID,
})
// 响应rpc消息
if client.rpc.HandleMsg(ctx, cancel, msg.Data) {
return
}
doHandleRouterMsg(f, ctx, cancel, msg.Data)
}
}
})
}
@@ -307,16 +332,45 @@ func (client *Client) Write(data interface{}) error {
return gerror.New("client Write message is nil")
}
// 签名
SetSign(data, gctx.CtxId(client.Ctx), client.auth.AppId, client.auth.SecretKey)
msgType := reflect.TypeOf(data)
if msgType == nil || msgType.Kind() != reflect.Ptr {
return gerror.Newf("client json message pointer required: %+v", data)
}
msg := &Message{Router: msgType.Elem().Name(), Data: data}
client.Logger.Debugf(client.Ctx, "client Write Router:%v, data:%+v", msg.Router, gjson.New(data).String())
return SendPkg(client.conn, msg)
}
// Send 发送消息
func (client *Client) Send(ctx context.Context, data interface{}) error {
MsgPkg(data, client.auth, gctx.CtxId(ctx))
return client.Write(data)
}
// Reply 回复消息
func (client *Client) Reply(ctx context.Context, data interface{}) (err error) {
user := GetCtx(ctx)
if user == nil {
err = gerror.New("获取回复用户信息失败")
return
}
MsgPkg(data, client.auth, user.TraceID)
return client.Write(data)
}
// RpcRequest 发送消息并等待响应结果
func (client *Client) RpcRequest(ctx context.Context, data interface{}) (res interface{}, err error) {
var (
traceID = MsgPkg(data, client.auth, gctx.CtxId(ctx))
key = client.rpc.GetCallId(client.conn, traceID)
)
if traceID == "" {
err = gerror.New("traceID is required")
return
}
return client.rpc.Request(key, func() {
client.Write(data)
})
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/gogf/gf/v2/os/gcron"
"github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/consts"
)
func (client *Client) getCronKey(s string) string {
@@ -19,19 +20,19 @@ func (client *Client) stopCron() {
func (client *Client) startCron() {
// 心跳超时检查
if gcron.Search(client.getCronKey(cronHeartbeatVerify)) == nil {
if gcron.Search(client.getCronKey(consts.TCPCronHeartbeatVerify)) == nil {
gcron.AddSingleton(client.Ctx, "@every 600s", func(ctx context.Context) {
if client.heartbeat < gtime.Timestamp()-600 {
client.Logger.Debugf(client.Ctx, "client heartbeat timeout, about to reconnect..")
client.Logger.Debugf(client.Ctx, "client heartbeat timeout, about to reconnect..")
client.Destroy()
}
}, client.getCronKey(cronHeartbeatVerify))
}, client.getCronKey(consts.TCPCronHeartbeatVerify))
}
// 心跳
if gcron.Search(client.getCronKey(cronHeartbeat)) == nil {
if gcron.Search(client.getCronKey(consts.TCPCronHeartbeat)) == nil {
gcron.AddSingleton(client.Ctx, "@every 120s", func(ctx context.Context) {
client.serverHeartbeat()
}, client.getCronKey(cronHeartbeat))
}, client.getCronKey(consts.TCPCronHeartbeat))
}
}

View File

@@ -1,16 +1,19 @@
package tcp
import (
"github.com/gogf/gf/v2/errors/gcode"
"context"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts"
"hotgo/internal/model/input/msgin"
)
// serverLogin 心跳
func (client *Client) serverHeartbeat() {
if err := client.Write(&msgin.ServerHeartbeat{}); err != nil {
client.Logger.Debugf(client.Ctx, "client WriteMsg ServerHeartbeat err:%+v", err)
ctx := gctx.New()
if err := client.Send(ctx, &msgin.ServerHeartbeat{}); err != nil {
client.Logger.Debugf(ctx, "client WriteMsg ServerHeartbeat err:%+v", err)
return
}
}
@@ -22,40 +25,45 @@ func (client *Client) serverLogin() {
Name: client.auth.Name,
}
if err := client.Write(data); err != nil {
client.Logger.Debugf(client.Ctx, "client WriteMsg ServerLogin err:%+v", err)
ctx := gctx.New()
if err := client.Send(ctx, data); err != nil {
client.Logger.Debugf(ctx, "client WriteMsg ServerLogin err:%+v", err)
return
}
}
func (client *Client) onResponseServerLogin(ctx context.Context, args ...interface{}) {
var in *msgin.ResponseServerLogin
if err := gconv.Scan(args[0], &in); err != nil {
client.Logger.Infof(ctx, "onResponseServerLogin message Scan failed:%+v, args:%+v", err, args[0])
return
}
if in.Code != consts.TCPMsgCodeSuccess {
client.IsLogin = false
client.Logger.Warningf(ctx, "onResponseServerLogin quit err:%v", in.Message)
client.Destroy()
return
}
client.IsLogin = true
if client.loginEvent != nil {
client.loginEvent()
}
}
func (client *Client) onResponseServerLogin(args ...interface{}) {
var in *msgin.ResponseServerLogin
if err := gconv.Scan(args[0], &in); err != nil {
client.Logger.Infof(client.Ctx, "onResponseServerLogin message Scan failed:%+v, args:%+v", err, args[0])
return
}
client.Logger.Infof(client.Ctx, "onResponseServerLogin in:%+v", *in)
if in.Code != gcode.CodeOK.Code() {
client.IsLogin = false
client.Logger.Warningf(client.Ctx, "onResponseServerLogin quit err:%v", in.Message)
client.Destroy()
return
}
client.IsLogin = true
}
func (client *Client) onResponseServerHeartbeat(args ...interface{}) {
func (client *Client) onResponseServerHeartbeat(ctx context.Context, args ...interface{}) {
var in *msgin.ResponseServerHeartbeat
if err := gconv.Scan(args[0], &in); err != nil {
client.Logger.Infof(client.Ctx, "onResponseServerHeartbeat message Scan failed:%+v, args:%+v", err, args)
client.Logger.Infof(ctx, "onResponseServerHeartbeat message Scan failed:%+v, args:%+v", err, args)
return
}
if in.Code != consts.TCPMsgCodeSuccess {
client.Logger.Warningf(ctx, "onResponseServerHeartbeat err:%v", in.Message)
return
}
client.heartbeat = gtime.Timestamp()
client.Logger.Infof(client.Ctx, "onResponseServerHeartbeat in:%+v", *in)
}

View File

@@ -0,0 +1,57 @@
package tcp
import (
"context"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/net/gtrace"
"hotgo/internal/consts"
)
// initCtx 初始化上下文对象指针到上下文对象中,以便后续的请求流程中可以修改
func initCtx(ctx context.Context, model *Context) (newCtx context.Context, cancel context.CancelFunc) {
if model.TraceID != "" {
newCtx, _ = gtrace.WithTraceID(ctx, model.TraceID)
} else {
newCtx = ctx
}
newCtx = context.WithValue(newCtx, consts.ContextTCPKey, model)
newCtx, cancel = context.WithCancel(newCtx)
return
}
// SetCtx 设置上下文变量
func SetCtx(ctx context.Context, model *Context) {
context.WithValue(ctx, consts.ContextTCPKey, model)
}
// GetCtx 获得上下文变量如果没有设置那么返回nil
func GetCtx(ctx context.Context) *Context {
value := ctx.Value(consts.ContextTCPKey)
if value == nil {
return nil
}
if localCtx, ok := value.(*Context); ok {
return localCtx
}
return nil
}
// GetCtxConn .
func GetCtxConn(ctx context.Context) *gtcp.Conn {
c := GetCtx(ctx)
if c == nil {
return nil
}
return c.Conn
}
// GetCtxAuth 认证元数据
func GetCtxAuth(ctx context.Context) *AuthMeta {
c := GetCtx(ctx)
if c == nil {
return nil
}
return c.Auth
}

View File

@@ -1,19 +1,8 @@
package tcp
import "github.com/gogf/gf/v2/os/gtime"
// 定时任务
const (
cronHeartbeatVerify = "tcpHeartbeatVerify"
cronHeartbeat = "tcpHeartbeat"
cronAuthVerify = "tcpAuthVerify"
)
// 认证分组
const (
ClientGroupCron = "cron" // 定时任务
ClientGroupQueue = "queue" // 消息队列
ClientGroupAuth = "auth" // 服务授权
import (
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/gtime"
)
// AuthMeta 认证元数据
@@ -25,5 +14,11 @@ type AuthMeta struct {
EndAt *gtime.Time `json:"-"`
}
type Context struct {
Conn *gtcp.Conn `json:"conn"`
Auth *AuthMeta `json:"auth"` // 认证元数据
TraceID string `json:"traceID"` // 链路ID
}
// CallbackEvent 回调事件
type CallbackEvent func()

View File

@@ -0,0 +1,22 @@
package tcp
type Response interface {
PkgResponse()
GetError() (err error)
}
// PkgResponse 打包响应消息
func PkgResponse(data interface{}) {
if c, ok := data.(Response); ok {
c.PkgResponse()
return
}
}
// GetResponseError 解析响应消息中的错误
func GetResponseError(data interface{}) (err error) {
if c, ok := data.(Response); ok {
return c.GetError()
}
return
}

View File

@@ -1,13 +1,17 @@
package tcp
import (
"context"
"encoding/json"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/grpool"
"github.com/gogf/gf/v2/util/gconv"
)
type RouterHandler func(args ...interface{})
var GoPool = grpool.New(100)
type RouterHandler func(ctx context.Context, args ...interface{})
// Message 路由消息
type Message struct {
@@ -37,3 +41,26 @@ func RecvPkg(conn *gtcp.Conn) (*Message, error) {
return msg, err
}
}
// MsgPkg 打包消息
func MsgPkg(data interface{}, auth *AuthMeta, traceID string) string {
// 打包签名
msg := PkgSign(data, auth.AppId, auth.SecretKey, traceID)
// 打包响应消息
PkgResponse(data)
if msg == nil {
return ""
}
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

@@ -0,0 +1,103 @@
package tcp
import (
"context"
"fmt"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/gtcp"
"hotgo/internal/consts"
"hotgo/utility/simple"
"sync"
"time"
)
type Rpc struct {
ctx context.Context
mutex sync.Mutex
callbacks map[string]RpcRespFunc
}
type RpcResp struct {
res interface{}
err error
}
type RpcRespFunc func(resp interface{}, err error)
func NewRpc(ctx context.Context) *Rpc {
return &Rpc{
ctx: ctx,
callbacks: make(map[string]RpcRespFunc),
}
}
// GetCallId 获取回调id
func (r *Rpc) GetCallId(client *gtcp.Conn, traceID string) string {
return fmt.Sprintf("%v.%v", client.LocalAddr().String(), traceID)
}
// HandleMsg 处理rpc消息
func (r *Rpc) HandleMsg(ctx context.Context, cancel context.CancelFunc, data interface{}) bool {
user := GetCtx(ctx)
callId := r.GetCallId(user.Conn, user.TraceID)
if call, ok := r.callbacks[callId]; ok {
r.mutex.Lock()
delete(r.callbacks, callId)
r.mutex.Unlock()
simple.SafeGo(ctx, func(ctx context.Context) {
call(data, nil)
cancel()
})
return true
}
return false
}
// Request 发起rpc请求
func (r *Rpc) Request(callId string, send func()) (res interface{}, err error) {
var (
waitCh = make(chan struct{})
resCh = make(chan RpcResp, 1)
isClose = false
)
defer func() {
isClose = true
close(resCh)
// 移除消息
if _, ok := r.callbacks[callId]; ok {
r.mutex.Lock()
delete(r.callbacks, callId)
r.mutex.Unlock()
}
}()
simple.SafeGo(r.ctx, func(ctx context.Context) {
close(waitCh)
// 加入回调
r.mutex.Lock()
r.callbacks[callId] = func(res interface{}, err error) {
if !isClose {
resCh <- RpcResp{res: res, err: err}
}
}
r.mutex.Unlock()
// 发送消息
send()
})
<-waitCh
select {
case <-time.After(consts.TCPRpcTimeout):
err = gerror.New("rpc response timeout")
return
case got := <-resCh:
return got.res, got.err
}
}

View File

@@ -3,12 +3,12 @@ package tcp
import (
"context"
"fmt"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog"
"hotgo/internal/consts"
"reflect"
"sync"
"time"
@@ -31,6 +31,7 @@ type Server struct {
Logger *glog.Logger
addr string
name string
rpc *Rpc
ln *gtcp.Server
wgLn sync.WaitGroup
mutex sync.Mutex
@@ -72,6 +73,7 @@ func NewServer(config *ServerConfig) (server *Server, err error) {
return
}
server.Logger = logger
server.rpc = NewRpc(server.Ctx)
server.startCron()
@@ -100,13 +102,19 @@ func (server *Server) accept(conn *gtcp.Conn) {
switch msg.Router {
case "ServerLogin": // 服务登录
server.onServerLogin(msg.Data, conn)
// 初始化上下文
ctx, cancel := initCtx(gctx.New(), &Context{
Conn: conn,
})
doHandleRouterMsg(server.onServerLogin, ctx, cancel, msg.Data)
case "ServerHeartbeat": // 心跳
if client == nil {
server.Logger.Infof(server.Ctx, "conn not connected, ignore the heartbeat, msg:%+v", msg)
continue
}
server.onServerHeartbeat(msg, client)
// 初始化上下文
ctx, cancel := initCtx(gctx.New(), &Context{})
doHandleRouterMsg(server.onServerHeartbeat, ctx, cancel, msg.Data, client)
default: // 通用路由消息处理
if client == nil {
server.Logger.Warningf(server.Ctx, "conn is not logged in but sends a routing message. actively conn disconnect, msg:%+v", msg)
@@ -121,14 +129,25 @@ func (server *Server) accept(conn *gtcp.Conn) {
// handleRouterMsg 处理路由消息
func (server *Server) handleRouterMsg(msg *Message, client *ClientConn) {
// 验证签名
err := VerifySign(msg.Data, client.Auth.AppId, client.Auth.SecretKey)
in, err := VerifySign(msg.Data, client.Auth.AppId, client.Auth.SecretKey)
if err != nil {
server.Logger.Warningf(server.Ctx, "handleRouterMsg VerifySign err:%+v message: %+v", err, msg)
return
}
// 初始化上下文
ctx, cancel := initCtx(gctx.New(), &Context{
Conn: client.Conn,
Auth: client.Auth,
TraceID: in.TraceID,
})
// 响应rpc消息
if server.rpc.HandleMsg(ctx, cancel, msg.Data) {
return
}
handle := func(routers map[string]RouterHandler, group string) {
if routers == nil {
server.Logger.Debugf(server.Ctx, "handleRouterMsg route is not initialized %v message: %+v", group, msg)
@@ -139,15 +158,16 @@ func (server *Server) handleRouterMsg(msg *Message, client *ClientConn) {
server.Logger.Debugf(server.Ctx, "handleRouterMsg invalid %v message: %+v", group, msg)
return
}
f(msg.Data, client)
doHandleRouterMsg(f, ctx, cancel, msg.Data)
}
switch client.Auth.Group {
case ClientGroupCron:
case consts.TCPClientGroupCron:
handle(server.cronRouters, client.Auth.Group)
case ClientGroupQueue:
case consts.TCPClientGroupQueue:
handle(server.queueRouters, client.Auth.Group)
case ClientGroupAuth:
case consts.TCPClientGroupAuth:
handle(server.authRouters, client.Auth.Group)
default:
server.Logger.Warningf(server.Ctx, "group is not registered: %+v", client.Auth.Group)
@@ -173,6 +193,16 @@ func (server *Server) getAppIdClients(appid string) (list []*ClientConn) {
return
}
// GetGroupClients 获取指定分组的所有连接
func (server *Server) GetGroupClients(group string) (list []*ClientConn) {
for _, v := range server.clients {
if v.Auth.Group == group {
list = append(list, v)
}
}
return
}
// RegisterAuthRouter 注册授权路由
func (server *Server) RegisterAuthRouter(routers map[string]RouterHandler) {
server.mutex.Lock()
@@ -272,7 +302,39 @@ func (server *Server) Write(conn *gtcp.Conn, data interface{}) (err error) {
msg := &Message{Router: msgType.Elem().Name(), Data: data}
server.Logger.Debugf(server.Ctx, "server Write Router:%v, data:%+v", msg.Router, gjson.New(data).String())
return SendPkg(conn, msg)
}
// Send 发送消息
func (server *Server) Send(ctx context.Context, client *ClientConn, data interface{}) (err error) {
MsgPkg(data, client.Auth, gctx.CtxId(ctx))
return server.Write(client.Conn, data)
}
// Reply 回复消息
func (server *Server) Reply(ctx context.Context, data interface{}) (err error) {
user := GetCtx(ctx)
if user == nil {
err = gerror.New("获取回复用户信息失败")
return
}
MsgPkg(data, user.Auth, user.TraceID)
return server.Write(user.Conn, data)
}
// RpcRequest 向指定客户端发送消息并等待响应结果
func (server *Server) RpcRequest(ctx context.Context, client *ClientConn, data interface{}) (res interface{}, err error) {
var (
traceID = MsgPkg(data, client.Auth, gctx.CtxId(ctx))
key = server.rpc.GetCallId(client.Conn, traceID)
)
if traceID == "" {
err = gerror.New("traceID is required")
return
}
return server.rpc.Request(key, func() {
server.Write(client.Conn, data)
})
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/gogf/gf/v2/os/gcron"
"github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/consts"
)
func (server *Server) getCronKey(s string) string {
@@ -19,7 +20,7 @@ func (server *Server) stopCron() {
func (server *Server) startCron() {
// 心跳超时检查
if gcron.Search(server.getCronKey(cronHeartbeatVerify)) == nil {
if gcron.Search(server.getCronKey(consts.TCPCronHeartbeatVerify)) == nil {
gcron.AddSingleton(server.Ctx, "@every 300s", func(ctx context.Context) {
if server.clients == nil {
return
@@ -30,11 +31,11 @@ func (server *Server) startCron() {
server.Logger.Debugf(server.Ctx, "client heartbeat timeout, close conn. auth:%+v", client.Auth)
}
}
}, server.getCronKey(cronHeartbeatVerify))
}, server.getCronKey(consts.TCPCronHeartbeatVerify))
}
// 认证检查
if gcron.Search(server.getCronKey(cronAuthVerify)) == nil {
if gcron.Search(server.getCronKey(consts.TCPCronAuthVerify)) == nil {
gcron.AddSingleton(server.Ctx, "@every 300s", func(ctx context.Context) {
if server.clients == nil {
return
@@ -45,6 +46,6 @@ func (server *Server) startCron() {
server.Logger.Debugf(server.Ctx, "client auth expired, close conn. auth:%+v", client.Auth)
}
}
}, server.getCronKey(cronAuthVerify))
}, server.getCronKey(consts.TCPCronAuthVerify))
}
}

View File

@@ -1,8 +1,8 @@
package tcp
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
@@ -12,75 +12,73 @@ import (
"hotgo/utility/convert"
)
func (server *Server) onServerLogin(args ...interface{}) {
func (server *Server) onServerLogin(ctx context.Context, args ...interface{}) {
var (
in = new(msgin.ServerLogin)
conn = args[1].(*gtcp.Conn)
user = GetCtx(ctx)
res = new(msgin.ResponseServerLogin)
models *entity.SysServeLicense
)
if err := gconv.Scan(args[0], &in); err != nil {
server.Logger.Infof(server.Ctx, "onServerLogin message Scan failed:%+v, args:%+v", err, args)
server.Logger.Warningf(ctx, "onServerLogin message Scan failed:%+v, args:%+v", err, args)
return
}
server.Logger.Infof(server.Ctx, "onServerLogin in:%+v", *in)
err := g.Model("sys_serve_license").
Ctx(server.Ctx).
err := g.Model("sys_serve_license").Ctx(ctx).
Where("appid = ?", in.AppId).
Scan(&models)
if err != nil {
res.Code = 1
res.Message = err.Error()
server.Write(conn, res)
server.Write(user.Conn, res)
return
}
if models == nil {
res.Code = 2
res.Message = "授权信息不存在"
server.Write(conn, res)
server.Write(user.Conn, res)
return
}
// 验证签名
if err = VerifySign(in, models.Appid, models.SecretKey); err != nil {
if _, err = VerifySign(in, models.Appid, models.SecretKey); err != nil {
res.Code = 3
res.Message = "签名错误,请联系管理员"
server.Write(conn, res)
server.Write(user.Conn, res)
return
}
if models.Status != consts.StatusEnabled {
res.Code = 4
res.Message = "授权已禁用,请联系管理员"
server.Write(conn, res)
server.Write(user.Conn, res)
return
}
if models.Group != in.Group {
res.Code = 5
res.Message = "你登录的授权分组未得到授权,请联系管理员"
server.Write(conn, res)
server.Write(user.Conn, res)
return
}
if models.EndAt.Before(gtime.Now()) {
res.Code = 6
res.Message = "授权已过期,请联系管理员"
server.Write(conn, res)
server.Write(user.Conn, res)
return
}
allowedIps := convert.IpFilterStrategy(models.AllowedIps)
if _, ok := allowedIps["*"]; !ok {
ip := gstr.StrTillEx(conn.RemoteAddr().String(), ":")
ip := gstr.StrTillEx(user.Conn.RemoteAddr().String(), ":")
if _, ok2 := allowedIps[ip]; !ok2 {
res.Code = 7
res.Message = "IP(" + ip + ")未授权,请联系管理员"
server.Write(conn, res)
server.Write(user.Conn, res)
return
}
}
@@ -99,14 +97,14 @@ func (server *Server) onServerLogin(args ...interface{}) {
}
// 当前连接也踢掉
server.Write(conn, res2)
conn.Close()
server.Write(user.Conn, res2)
user.Conn.Close()
return
}
server.mutexConns.Lock()
server.clients[conn.RemoteAddr().String()] = &ClientConn{
Conn: conn,
server.clients[user.Conn.RemoteAddr().String()] = &ClientConn{
Conn: user.Conn,
Auth: &AuthMeta{
Group: in.Group,
Name: in.Name,
@@ -118,39 +116,46 @@ func (server *Server) onServerLogin(args ...interface{}) {
}
server.mutexConns.Unlock()
server.Write(conn, res)
_, err = g.Model("sys_serve_license").
Ctx(server.Ctx).
_, err = g.Model("sys_serve_license").Ctx(ctx).
Where("id = ?", models.Id).Data(g.Map{
"online": online,
"login_times": models.LoginTimes + 1,
"last_login_at": gtime.Now(),
"last_active_at": gtime.Now(),
"remote_addr": conn.RemoteAddr().String(),
"remote_addr": user.Conn.RemoteAddr().String(),
}).Update()
if err != nil {
server.Logger.Warningf(server.Ctx, "onServerLogin Update err:%+v", err)
server.Logger.Warningf(ctx, "onServerLogin Update err:%+v", err)
}
res.AppId = in.AppId
res.Code = consts.TCPMsgCodeSuccess
server.Write(user.Conn, res)
}
func (server *Server) onServerHeartbeat(args ...interface{}) {
var in *msgin.ServerHeartbeat
if err := gconv.Scan(args, &in); err != nil {
server.Logger.Infof(server.Ctx, "onServerHeartbeat message Scan failed:%+v, args:%+v", err, args)
func (server *Server) onServerHeartbeat(ctx context.Context, args ...interface{}) {
var (
in *msgin.ServerHeartbeat
res = new(msgin.ResponseServerHeartbeat)
)
if err := gconv.Scan(args[0], &in); err != nil {
server.Logger.Warningf(ctx, "onServerHeartbeat message Scan failed:%+v, args:%+v", err, args)
return
}
client := args[1].(*ClientConn)
client.heartbeat = gtime.Timestamp()
server.Write(client.Conn, &msgin.ResponseServerHeartbeat{})
_, err := g.Model("sys_serve_license").
Ctx(server.Ctx).
_, err := g.Model("sys_serve_license").Ctx(ctx).
Where("appid = ?", client.Auth.AppId).Data(g.Map{
"last_active_at": gtime.Now(),
}).Update()
if err != nil {
server.Logger.Warningf(server.Ctx, "onServerHeartbeat Update err:%+v", err)
server.Logger.Warningf(ctx, "onServerHeartbeat Update err:%+v", err)
}
res.Code = consts.TCPMsgCodeSuccess
server.Write(client.Conn, res)
}

View File

@@ -7,35 +7,38 @@ import (
)
type Sign interface {
SetSign(traceID, appId, secretKey string)
SetSign(appId, secretKey string) *msgin.RpcMsg
SetTraceID(traceID string)
}
// SetSign 设置签名
func SetSign(data interface{}, traceID, appId, secretKey string) {
// PkgSign 打包签名
func PkgSign(data interface{}, appId, secretKey, traceID string) *msgin.RpcMsg {
if c, ok := data.(Sign); ok {
c.SetSign(traceID, appId, secretKey)
return
c.SetTraceID(traceID)
return c.SetSign(appId, secretKey)
}
return nil
}
// VerifySign 验证签名
func VerifySign(data interface{}, appId, secretKey string) (err error) {
func VerifySign(data interface{}, appId, secretKey string) (in *msgin.RpcMsg, err error) {
// 无密钥,无需签名
if secretKey == "" {
return
}
var in *msgin.Request
if err = gconv.Scan(data, &in); err != nil {
return
}
if appId != in.AppId {
return gerror.New("appId invalid")
err = gerror.New("appId invalid")
return
}
if in.Sign != in.GetSign(secretKey) {
return gerror.New("sign invalid")
err = gerror.New("sign invalid")
return
}
return
}