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

110 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 string // 用户ID
SceneSID string // 场景服ID
InstanceID int32 // 副本ID副本类型
UniqueNo string // 副本唯一编号
}
func NewClient(usn string, conn socket.ISocketConn) *Client {
client := &Client{
USN: usn,
conn: conn,
logger: log.GetLogger().Named(fmt.Sprintf("usn:%v", usn)),
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) 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()
}