Files
hotgo/server/internal/logic/tcpserver/server_handle.go
2023-07-24 09:35:30 +08:00

168 lines
4.3 KiB
Go

// Package tcpserver
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package tcpserver
import (
"context"
"fmt"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/network/tcp"
"hotgo/internal/model/entity"
"hotgo/utility/convert"
"hotgo/utility/encrypt"
)
// onServerLogin 处理客户端登录
func (s *sTCPServer) onServerLogin(ctx context.Context, req *tcp.ServerLoginReq) {
var (
conn = tcp.ConnFromCtx(ctx)
models *entity.SysServeLicense
res = new(tcp.ServerLoginRes)
cols = dao.SysServeLicense.Columns()
)
if conn == nil {
g.Log().Warningf(ctx, "conn is nil.")
return
}
if err := dao.SysServeLicense.Ctx(ctx).Where(cols.Appid, req.AppId).Scan(&models); err != nil {
return
}
if models == nil {
res.SetError(gerror.New("授权信息不存在"))
_ = conn.Send(ctx, res)
return
}
// 验证签名
sign := encrypt.Md5ToString(fmt.Sprintf("%v%v%v", models.Appid, req.Timestamp, models.SecretKey))
if sign != req.Sign {
res.SetError(gerror.New("签名错误,请检查!"))
_ = conn.Send(ctx, res)
return
}
if models.Status != consts.StatusEnabled {
res.SetError(gerror.New("授权已禁用,请联系管理员"))
_ = conn.Send(ctx, res)
return
}
if models.Group != req.Group {
res.SetError(gerror.New("你登录的授权分组未得到授权,请联系管理员"))
_ = conn.Send(ctx, res)
return
}
if models.EndAt.Before(gtime.Now()) {
res.SetError(gerror.New("授权已过期,请联系管理员"))
_ = conn.Send(ctx, res)
return
}
ip := gstr.StrTillEx(conn.RemoteAddr().String(), ":")
if !convert.MatchIpStrategy(models.AllowedIps, ip) {
res.SetError(gerror.New("IP(" + ip + ")未授权,请联系管理员"))
_ = conn.Send(ctx, res)
return
}
var routes []string
if err := models.Routes.Scan(&routes); err != nil {
res.SetError(gerror.New("授权路由解析失败,请联系管理员"))
_ = conn.Send(ctx, res)
return
}
// 拿出当前登录应用的所有客户端
clients := s.serv.GetAppIdClients(models.Appid)
// 检查多地登录,如果连接超过上限,则断开当前许可证下的所有连接
if len(clients)+1 > models.OnlineLimit {
for _, client := range clients {
client.Close()
}
res.SetError(gerror.New("授权登录端超出上限,请勿多地登录"))
_ = conn.Send(ctx, res)
return
}
for _, client := range clients {
if client.Auth.Name == req.Name {
res.SetError(gerror.Newf("应用名称[%v]已存在登录用户,当前连接已被拒绝。", req.Name))
_ = conn.Send(ctx, res)
return
}
}
auth := &tcp.AuthMeta{
Name: req.Name,
Extra: req.Extra,
Group: models.Group,
AppId: models.Appid,
SecretKey: models.SecretKey,
EndAt: models.EndAt,
Routes: routes,
}
s.serv.AuthClient(conn, auth)
update := g.Map{
cols.LoginTimes: models.LoginTimes + 1,
cols.LastLoginAt: gtime.Now(),
cols.LastActiveAt: gtime.Now(),
cols.RemoteAddr: conn.RemoteAddr().String(),
}
if _, err := dao.SysServeLicense.Ctx(ctx).Where(cols.Id, models.Id).Data(update).Update(); err != nil {
res.SetError(err)
_ = conn.Send(ctx, res)
return
}
g.Log().Debugf(ctx, "onServerLogin succeed. appid:%v, group:%v, name:%v", auth.AppId, auth.Group, auth.Name)
_ = conn.Send(ctx, res)
}
// onServerHeartbeat 处理客户端心跳
func (s *sTCPServer) onServerHeartbeat(ctx context.Context, req *tcp.ServerHeartbeatReq) {
var (
conn = tcp.ConnFromCtx(ctx)
res = new(tcp.ServerHeartbeatRes)
)
if conn == nil {
g.Log().Warningf(ctx, "conn is nil.")
return
}
client := s.serv.GetClient(conn.Conn)
if client == nil {
res.SetError(gerror.New("登录异常,请重新登录"))
_ = conn.Send(ctx, res)
return
}
// 更新心跳
client.Heartbeat = gtime.Timestamp()
// 更新活跃时间
update := g.Map{
dao.SysServeLicense.Columns().LastActiveAt: gtime.Now(),
}
if _, err := dao.SysServeLicense.Ctx(ctx).Where(dao.SysServeLicense.Columns().Appid, client.Auth.AppId).Data(update).Update(); err != nil {
res.SetError(err)
_ = conn.Send(ctx, res)
return
}
_ = conn.Send(ctx, res)
}