first commit

This commit is contained in:
ytc1012
2025-11-18 18:08:48 +08:00
commit de90ad79ea
162 changed files with 28098 additions and 0 deletions

287
net/serverconn.go Normal file
View File

@@ -0,0 +1,287 @@
package net
import (
"errors"
"fmt"
"log/slog"
"slgserver/util"
"sync"
"time"
"github.com/go-think/openssl"
"github.com/mitchellh/mapstructure"
"github.com/gorilla/websocket"
)
// 客户端连接
type ServerConn struct {
wsSocket *websocket.Conn // 底层websocket
outChan chan *WsMsgRsp // 写队列
isClosed bool
needSecret bool
Seq int64
router *Router
beforeClose func(conn WSConn)
onClose func(conn WSConn)
//链接属性
property map[string]interface{}
//保护链接属性修改的锁
propertyLock sync.RWMutex
closeChan chan struct{}
closeOnce sync.Once
}
func NewServerConn(wsSocket *websocket.Conn, needSecret bool) *ServerConn {
conn := &ServerConn{
wsSocket: wsSocket,
outChan: make(chan *WsMsgRsp, 1000),
isClosed: false,
property: make(map[string]interface{}),
needSecret: needSecret,
Seq: 0,
closeChan: make(chan struct{}),
}
return conn
}
// 开启异步
func (this *ServerConn) Start() {
go this.wsReadLoop()
go this.wsWriteLoop()
}
func (this *ServerConn) Addr() string {
return this.wsSocket.RemoteAddr().String()
}
func (this *ServerConn) Push(name string, data interface{}) {
rsp := &WsMsgRsp{Body: &RspBody{Name: name, Msg: data, Seq: 0}}
this.enqueue(rsp)
}
func (this *ServerConn) Send(name string, data interface{}) {
this.Seq += 1
rsp := &WsMsgRsp{Body: &RspBody{Name: name, Msg: data, Seq: this.Seq}}
this.enqueue(rsp)
}
func (this *ServerConn) wsReadLoop() {
defer func() {
if err := recover(); err != nil {
e := fmt.Sprintf("%v", err)
slog.Error("wsReadLoop error", "err", e)
this.Close()
}
}()
for {
select {
case <-this.closeChan:
return
default:
}
// 读一个message
_, data, err := this.wsSocket.ReadMessage()
slog.Debug("ws read message", "size", len(data))
if err != nil {
break
}
data, err = util.UnZip(data)
if err != nil {
slog.Error("wsReadLoop UnZip error", "error", err)
continue
}
body := &ReqBody{}
if this.needSecret {
//检测是否有加密没有加密发起Handshake
if secretKey, err := this.GetProperty("secretKey"); err == nil {
key := secretKey.(string)
d, err := util.AesCBCDecrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING)
if err != nil {
slog.Error("AesDecrypt error", "error", err)
this.Handshake()
} else {
data = d
}
} else {
slog.Info("secretKey not found client need handshake", "error", err)
this.Handshake()
return
}
}
if err := util.Unmarshal(data, body); err == nil {
req := &WsMsgReq{Conn: this, Body: body}
rsp := &WsMsgRsp{Body: &RspBody{Name: body.Name, Seq: req.Body.Seq}}
if req.Body.Name == HeartbeatMsg {
h := &Heartbeat{}
mapstructure.Decode(body.Msg, h)
h.STime = time.Now().UnixNano() / 1e6
rsp.Body.Msg = h
} else {
if this.router != nil {
this.router.Run(req, rsp)
}
}
this.outChan <- rsp
} else {
slog.Error("wsReadLoop Unmarshal error", "error", err)
this.Handshake()
}
}
this.Close()
}
func (this *ServerConn) wsWriteLoop() {
defer func() {
if err := recover(); err != nil {
slog.Error("wsWriteLoop error")
this.Close()
}
}()
for {
select {
case <-this.closeChan:
return
case msg := <-this.outChan:
if msg == nil {
continue
}
// 写给websocket
this.write(msg.Body)
}
}
}
func (this *ServerConn) write(msg interface{}) error {
data, err := util.Marshal(msg)
slog.Debug("ws write message", "size", len(data))
if err == nil {
if this.needSecret {
if secretKey, err := this.GetProperty("secretKey"); err == nil {
key := secretKey.(string)
data, _ = util.AesCBCEncrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING)
}
}
} else {
slog.Error("wsWriteLoop Marshal body error", "error", err)
return err
}
if data, err := util.Zip(data); err == nil {
if err := this.wsSocket.WriteMessage(websocket.BinaryMessage, data); err != nil {
this.Close()
return err
}
} else {
return err
}
return nil
}
func (this *ServerConn) Close() {
this.closeOnce.Do(func() {
this.wsSocket.Close()
close(this.closeChan)
if !this.isClosed {
this.isClosed = true
if this.beforeClose != nil {
this.beforeClose(this)
}
if this.onClose != nil {
this.onClose(this)
}
}
})
}
// 设置链接属性
func (this *ServerConn) SetProperty(key string, value interface{}) {
this.propertyLock.Lock()
defer this.propertyLock.Unlock()
this.property[key] = value
}
// 获取链接属性
func (this *ServerConn) GetProperty(key string) (interface{}, error) {
this.propertyLock.RLock()
defer this.propertyLock.RUnlock()
if value, ok := this.property[key]; ok {
return value, nil
} else {
return nil, errors.New("no property found")
}
}
func (this *ServerConn) SetRouter(router *Router) {
this.router = router
}
func (this *ServerConn) SetOnClose(hookFunc func(WSConn)) {
this.onClose = hookFunc
}
func (this *ServerConn) SetOnBeforeClose(hookFunc func(WSConn)) {
this.beforeClose = hookFunc
}
// 移除链接属性
func (this *ServerConn) RemoveProperty(key string) {
this.propertyLock.Lock()
defer this.propertyLock.Unlock()
delete(this.property, key)
}
// 握手协议
func (this *ServerConn) Handshake() {
secretKey := ""
if this.needSecret {
key, err := this.GetProperty("secretKey")
if err == nil {
secretKey = key.(string)
} else {
secretKey = util.RandSeq(16)
}
}
handshake := &Handshake{Key: secretKey}
body := &RspBody{Name: HandshakeMsg, Msg: handshake}
if data, err := util.Marshal(body); err == nil {
if secretKey != "" {
this.SetProperty("secretKey", secretKey)
} else {
this.RemoveProperty("secretKey")
}
slog.Info("handshake secretKey",
"secretKey", secretKey)
if data, err = util.Zip(data); err == nil {
this.wsSocket.WriteMessage(websocket.BinaryMessage, data)
}
} else {
slog.Error("handshake Marshal body error", "error", err)
}
}
func (this *ServerConn) enqueue(rsp *WsMsgRsp) {
select {
case <-this.closeChan:
return
case this.outChan <- rsp:
}
}