Files
service-gateway/internal/handler/ws_handler/client/client.go

114 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package client
import (
"context"
"fmt"
"git.hlsq.asia/mmorpg/service-common/db/redis"
"git.hlsq.asia/mmorpg/service-common/log"
"git.hlsq.asia/mmorpg/service-common/net/socket"
"git.hlsq.asia/mmorpg/service-gateway/internal/global"
"go.uber.org/zap"
"runtime/debug"
"sync"
"time"
)
type Client struct {
sync.WaitGroup
conn socket.ISocketConn // Socket
mailChan chan Event // 邮箱队列
logger *zap.SugaredLogger // 日志
ctx context.Context // 上下文
cancel context.CancelFunc // 取消上下文
heartBeat time.Time // 最后一次心跳
Status int32 // 状态0 登陆中 1 正常 2 离线
USN int64 // 用户ID
SceneSID int64 // 场景服ID
InstanceID int32 // 副本ID副本类型
UniqueNo int64 // 副本唯一编号
}
func NewClient(conn socket.ISocketConn) *Client {
client := &Client{
conn: conn,
logger: log.GetLogger(),
heartBeat: time.Now(),
mailChan: make(chan Event, 1024),
}
client.ctx, client.cancel = context.WithCancel(context.Background())
client.Add(1)
go client.Loop()
return client
}
func (c *Client) SetUSN(usn int64) {
c.USN = usn
c.logger = log.GetLogger().Named(fmt.Sprintf("usn:%v", usn))
}
func (c *Client) Loop() {
defer func() {
if err := recover(); err != nil {
c.logger.Errorf("Client Loop err: %v", err)
debug.PrintStack()
}
}()
defer c.onClose()
t := time.NewTicker(20 * time.Second)
defer t.Stop()
for {
select {
case <-c.ctx.Done():
return
case evt, ok := <-c.mailChan:
if ok {
c.handle(evt)
}
case <-t.C:
_ = c.conn.Ping()
if time.Now().Sub(c.heartBeat) > 60*time.Second {
return
}
}
}
}
func (c *Client) OnEvent(event Event) {
defer func() {
if err := recover(); err != nil {
c.logger.Warnf(fmt.Sprintf("send event chan error: %v", err))
}
}()
select {
case c.mailChan <- event:
default:
c.logger.Warnf("Client mailChan full")
}
}
// CloseClient 关闭客户端同步会等待onClose执行完成
func (c *Client) CloseClient() {
if c.cancel != nil {
c.cancel()
c.Wait()
}
}
// onClose 客户端关闭自动触发
func (c *Client) onClose() {
if c.conn != nil {
_ = c.conn.Close()
c.conn = nil
}
if c.mailChan != nil {
close(c.mailChan)
c.mailChan = nil
}
c.Status = 2
UserMgr.Delete(c.USN)
redis.GetClient().HDel(c.ctx, fmt.Sprintf(global.KeyGatewayInfo, c.USN), global.HFieldInfoGatewaySID)
c.onLeave()
c.Done()
}