mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-08-28 05:12:32 +08:00
168 lines
4.3 KiB
Go
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)
|
|
}
|