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

254
net/clientconn.go Normal file
View File

@@ -0,0 +1,254 @@
package net
import (
"context"
"errors"
"fmt"
"github.com/go-think/openssl"
"github.com/mitchellh/mapstructure"
"github.com/gorilla/websocket"
"log/slog"
"slgserver/constant"
"slgserver/util"
"sync"
"time"
)
// 客户端连接
type ClientConn struct {
wsSocket *websocket.Conn // 底层websocket
isClosed bool
Seq int64
onClose func(conn*ClientConn)
onPush func(conn*ClientConn, body*RspBody)
//链接属性
property map[string]interface{}
//保护链接属性修改的锁
propertyLock sync.RWMutex
syncCtxs map[int64]*syncCtx
syncLock sync.RWMutex
handshakeChan chan bool
handshake bool
}
func NewClientConn(wsSocket *websocket.Conn) *ClientConn {
conn := &ClientConn{
wsSocket: wsSocket,
isClosed: false,
property: make(map[string]interface{}),
Seq: 0,
syncCtxs: make(map[int64]*syncCtx),
handshakeChan: make(chan bool),
}
return conn
}
func (this *ClientConn) waitHandshake() bool{
if this.handshake == false{
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
select {
case _ = <-this.handshakeChan:{
slog.Info("recv handshakeChan")
return true
}
case <-ctx.Done():{
slog.Info("recv handshakeChan timeout")
return false
}
}
}
return true
}
func (this *ClientConn) Start() bool{
this.handshake = false
go this.wsReadLoop()
return this.waitHandshake()
}
func (this *ClientConn) Addr() string {
return this.wsSocket.RemoteAddr().String()
}
func (this *ClientConn) Push(name string, data interface{}) {
rsp := &WsMsgRsp{Body: &RspBody{Name: name, Msg: data, Seq: 0}}
this.write(rsp.Body)
}
func (this *ClientConn) Send(name string, data interface{}) *RspBody{
this.syncLock.Lock()
sync := newSyncCtx()
this.Seq += 1
seq := this.Seq
req := ReqBody{Name: name, Msg: data, Seq: seq}
this.syncCtxs[this.Seq] = sync
this.syncLock.Unlock()
rsp := &RspBody{Code: constant.OK, Name: name, Seq: seq }
err := this.write(req)
if err != nil{
sync.cancel()
}else{
r := sync.wait()
if r == nil{
rsp.Code = constant.ProxyConnectError
}else{
rsp = r
}
}
this.syncLock.Lock()
delete(this.syncCtxs, seq)
this.syncLock.Unlock()
return rsp
}
func (this *ClientConn) wsReadLoop() {
defer func() {
if err := recover(); err != nil {
e := fmt.Sprintf("%v", err)
slog.Error("wsReadLoop error", "err", e)
this.Close()
}
}()
for {
// 读一个message
_, data, err := this.wsSocket.ReadMessage()
if err != nil {
break
}
data, err = util.UnZip(data)
if err != nil {
slog.Error("wsReadLoop UnZip error", "error", err)
continue
}
//需要检测是否有加密
body := &RspBody{}
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)
}else{
data = d
}
}
if err := util.Unmarshal(data, body); err == nil {
if body.Seq == 0 {
if body.Name == HandshakeMsg{
h := Handshake{}
mapstructure.Decode(body.Msg, &h)
slog.Info("client 收到握手协议", "data", string(data))
if h.Key != ""{
this.SetProperty("secretKey", h.Key)
}else{
this.RemoveProperty("secretKey")
}
this.handshake = true
this.handshakeChan <- true
}else{
//推送,需要推送到指定的代理连接
if this.onPush != nil{
this.onPush(this, body)
}else{
slog.Warn("clientconn not deal push")
}
}
}else{
this.syncLock.RLock()
s, ok := this.syncCtxs[body.Seq]
this.syncLock.RUnlock()
if ok {
s.outChan <- body
}else{
slog.Warn("seq not found sync",
"seq", body.Seq,
"msgName", body.Name)
}
}
}else{
slog.Error("wsReadLoop Unmarshal error", "error", err)
}
}
this.Close()
}
func (this *ClientConn) write(msg interface{}) error{
data, err := util.Marshal(msg)
if err == nil {
if secretKey, err:= this.GetProperty("secretKey"); err == nil {
key := secretKey.(string)
slog.Info("secretKey", "secretKey", key)
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 *ClientConn) Close() {
this.wsSocket.Close()
if !this.isClosed {
this.isClosed = true
if this.onClose != nil{
this.onClose(this)
}
}
}
//设置链接属性
func (this *ClientConn) SetProperty(key string, value interface{}) {
this.propertyLock.Lock()
defer this.propertyLock.Unlock()
this.property[key] = value
}
//获取链接属性
func (this *ClientConn) 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 *ClientConn) RemoveProperty(key string) {
this.propertyLock.Lock()
defer this.propertyLock.Unlock()
delete(this.property, key)
}
func (this *ClientConn) SetOnClose(hookFunc func (*ClientConn)) {
this.onClose = hookFunc
}
func (this *ClientConn) SetOnPush(hookFunc func (*ClientConn, *RspBody)) {
this.onPush = hookFunc
}

70
net/conn.go Normal file
View File

@@ -0,0 +1,70 @@
package net
import (
"context"
"time"
)
type ReqBody struct {
Seq int64 `json:"seq"`
Name string `json:"name"`
Msg interface{} `json:"msg"`
Proxy string `json:"proxy"`
}
type RspBody struct {
Seq int64 `json:"seq"`
Name string `json:"name"`
Code int `json:"code"`
Msg interface{} `json:"msg"`
}
type WsMsgReq struct {
Body *ReqBody
Conn WSConn
}
type WsMsgRsp struct {
Body* RspBody
}
const HandshakeMsg = "handshake"
const HeartbeatMsg = "heartbeat"
type Handshake struct {
Key string `json:"key"`
}
type Heartbeat struct {
CTime int64 `json:"ctime"`
STime int64 `json:"stime"`
}
type WSConn interface {
SetProperty(key string, value interface{})
GetProperty(key string) (interface{}, error)
RemoveProperty(key string)
Addr() string
Push(name string, data interface{})
}
type syncCtx struct {
ctx context.Context
cancel context.CancelFunc
outChan chan *RspBody
}
func newSyncCtx() *syncCtx {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
return &syncCtx{ctx: ctx, cancel: cancel, outChan: make(chan *RspBody)}
}
func (this* syncCtx) wait() *RspBody{
defer this.cancel()
select {
case data := <- this.outChan:
return data
case <-this.ctx.Done():
return nil
}
}

202
net/connMgr.go Normal file
View File

@@ -0,0 +1,202 @@
package net
import (
"github.com/gorilla/websocket"
"log/slog"
"slgserver/server/slgserver/conn"
"slgserver/server/slgserver/pos"
"sync"
"sync/atomic"
)
var ConnMgr = Mgr{}
var cid int64 = 0
type Mgr struct {
cm sync.RWMutex
um sync.RWMutex
rm sync.RWMutex
connCache map[int64]WSConn
userCache map[int]WSConn
roleCache map[int]WSConn
}
func (this *Mgr) NewConn(wsSocket *websocket.Conn, needSecret bool) *ServerConn {
this.cm.Lock()
defer this.cm.Unlock()
id := atomic.AddInt64(&cid, 1)
if this.connCache == nil {
this.connCache = make(map[int64]WSConn)
}
if this.userCache == nil {
this.userCache = make(map[int]WSConn)
}
if this.roleCache == nil {
this.roleCache = make(map[int]WSConn)
}
c := NewServerConn(wsSocket, needSecret)
c.SetProperty("cid", id)
this.connCache[id] = c
return c
}
func (this *Mgr) UserLogin(conn WSConn, session string, uid int) {
this.um.Lock()
defer this.um.Unlock()
oldConn, ok := this.userCache[uid]
if ok {
if conn != oldConn {
slog.Warn("rob login",
"uid", uid,
"oldAddr", oldConn.Addr(),
"newAddr", conn.Addr())
//这里需要通知旧端被抢登录
oldConn.Push("robLogin", nil)
}
}
this.userCache[uid] = conn
conn.SetProperty("session", session)
conn.SetProperty("uid", uid)
}
func (this *Mgr) UserLogout(conn WSConn) {
this.removeUser(conn)
}
func (this *Mgr) removeUser(conn WSConn) {
this.um.Lock()
uid, err := conn.GetProperty("uid")
if err == nil {
//只删除自己的conn
id := uid.(int)
c, ok := this.userCache[id]
if ok && c == conn {
delete(this.userCache, id)
}
}
this.um.Unlock()
this.rm.Lock()
rid, err := conn.GetProperty("rid")
if err == nil {
//只删除自己的conn
id := rid.(int)
c, ok := this.roleCache[id]
if ok && c == conn {
delete(this.roleCache, id)
}
}
this.rm.Unlock()
conn.RemoveProperty("session")
conn.RemoveProperty("uid")
conn.RemoveProperty("role")
conn.RemoveProperty("rid")
}
func (this *Mgr) RoleEnter(conn WSConn, rid int) {
this.rm.Lock()
defer this.rm.Unlock()
conn.SetProperty("rid", rid)
this.roleCache[rid] = conn
}
func (this *Mgr) RemoveConn(conn WSConn) {
this.cm.Lock()
cid, err := conn.GetProperty("cid")
if err == nil {
delete(this.connCache, cid.(int64))
conn.RemoveProperty("cid")
}
this.cm.Unlock()
this.removeUser(conn)
}
func (this *Mgr) PushByRoleId(rid int, msgName string, data interface{}) bool {
if rid <= 0 {
return false
}
this.rm.Lock()
defer this.rm.Unlock()
conn, ok := this.roleCache[rid]
if ok {
conn.Push(msgName, data)
return true
} else {
return false
}
}
func (this *Mgr) Count() int {
this.cm.RLock()
defer this.cm.RUnlock()
return len(this.connCache)
}
func (this *Mgr) Push(pushSync conn.PushSync) {
proto := pushSync.ToProto()
belongRIds := pushSync.BelongToRId()
isCellView := pushSync.IsCellView()
x, y := pushSync.Position()
cells := make(map[int]int)
//推送给开始位置
if isCellView {
cellRIds := pos.RPMgr.GetCellRoleIds(x, y, 8, 6)
for _, rid := range cellRIds {
//是否能出现在视野
if can := pushSync.IsCanView(rid, x, y); can {
this.PushByRoleId(rid, pushSync.PushMsgName(), proto)
cells[rid] = rid
}
}
}
//推送给目标位置
tx, ty := pushSync.TPosition()
if tx >= 0 && ty >= 0 {
var cellRIds []int
if isCellView {
cellRIds = pos.RPMgr.GetCellRoleIds(tx, ty, 8, 6)
} else {
cellRIds = pos.RPMgr.GetCellRoleIds(tx, ty, 0, 0)
}
for _, rid := range cellRIds {
if _, ok := cells[rid]; !ok {
if can := pushSync.IsCanView(rid, tx, ty); can {
this.PushByRoleId(rid, pushSync.PushMsgName(), proto)
cells[rid] = rid
}
}
}
}
//推送给自己
for _, rid := range belongRIds {
if _, ok := cells[rid]; !ok {
this.PushByRoleId(rid, pushSync.PushMsgName(), proto)
}
}
}
func (this *Mgr) pushAll(msgName string, data interface{}) {
this.rm.Lock()
defer this.rm.Unlock()
for _, conn := range this.roleCache {
conn.Push(msgName, data)
}
}

68
net/proxyClient.go Normal file
View File

@@ -0,0 +1,68 @@
package net
import (
"errors"
"github.com/gorilla/websocket"
"time"
)
type ProxyClient struct {
proxy string
conn *ClientConn
}
func (this*ProxyClient) Connect() error {
var dialer = websocket.Dialer{
Subprotocols: []string{"p1", "p2"},
ReadBufferSize: 1024,
WriteBufferSize: 1024,
HandshakeTimeout: 30 * time.Second,
}
ws, _, err := dialer.Dial(this.proxy, nil)
if err == nil{
this.conn = NewClientConn(ws)
if this.conn.Start() == false{
return errors.New("handshake fail")
}
}
return err
}
func (this*ProxyClient) Send(msgName string, msg interface{}) (*RspBody, error){
if this.conn != nil {
return this.conn.Send(msgName, msg), nil
}
return nil, errors.New("conn not found")
}
func (this *ProxyClient) SetOnPush(hookFunc func (*ClientConn, *RspBody)) {
if this.conn != nil {
this.conn.SetOnPush(hookFunc)
}
}
func (this *ProxyClient) SetOnClose(hookFunc func (*ClientConn)) {
if this.conn != nil {
this.conn.SetOnClose(hookFunc)
}
}
func (this *ProxyClient) SetProperty(key string, value interface{}) {
if this.conn != nil {
this.conn.SetProperty(key, value)
}
}
func (this *ProxyClient) Close() {
if this.conn != nil {
this.conn.Close()
}
}
func NewProxyClient(proxy string) *ProxyClient {
return & ProxyClient{
proxy: proxy,
}
}

95
net/router.go Normal file
View File

@@ -0,0 +1,95 @@
package net
import (
"encoding/json"
"log/slog"
"strings"
)
type HandlerFunc func(req *WsMsgReq, rsp *WsMsgRsp)
type MiddlewareFunc func(HandlerFunc) HandlerFunc
type Group struct {
prefix string
hMap map[string]HandlerFunc
hMapMidd map[string][]MiddlewareFunc
middleware []MiddlewareFunc
}
func (this *Group) AddRouter(name string, handlerFunc HandlerFunc, middleware ...MiddlewareFunc) {
this.hMap[name] = handlerFunc
this.hMapMidd[name] = middleware
}
func (this *Group) Use(middleware ...MiddlewareFunc) *Group {
this.middleware = append(this.middleware, middleware...)
return this
}
func (this *Group) applyMiddleware(name string) HandlerFunc {
h, ok := this.hMap[name]
if !ok {
//通配符
h, ok = this.hMap["*"]
}
if ok {
for i := len(this.middleware) - 1; i >= 0; i-- {
h = this.middleware[i](h)
}
for i := len(this.hMapMidd[name]) - 1; i >= 0; i-- {
h = this.hMapMidd[name][i](h)
}
}
return h
}
func (this *Group) exec(name string, req *WsMsgReq, rsp *WsMsgRsp) {
slog.Debug("route exec", "group", this.prefix, "name", name)
h := this.applyMiddleware(name)
if h == nil {
slog.Warn("Group has not",
"msgName", req.Body.Name)
} else {
h(req, rsp)
}
if dd, err := json.Marshal(rsp.Body); err == nil {
slog.Debug("route response", "group", this.prefix, "name", name, "size", len(dd))
}
}
type Router struct {
groups []*Group
}
func (this *Router) Group(prefix string) *Group {
g := &Group{prefix: prefix,
hMap: make(map[string]HandlerFunc),
hMapMidd: make(map[string][]MiddlewareFunc),
}
this.groups = append(this.groups, g)
return g
}
func (this *Router) Run(req *WsMsgReq, rsp *WsMsgRsp) {
name := req.Body.Name
msgName := name
sArr := strings.Split(name, ".")
prefix := ""
if len(sArr) == 2 {
prefix = sArr[0]
msgName = sArr[1]
}
for _, g := range this.groups {
if g.prefix == prefix {
g.exec(msgName, req, rsp)
} else if g.prefix == "*" {
g.exec(msgName, req, rsp)
}
}
}

137
net/server.go Normal file
View File

@@ -0,0 +1,137 @@
package net
import (
"context"
"github.com/gorilla/websocket"
"log/slog"
"net/http"
"os"
"os/signal"
"slgserver/config"
"strings"
"syscall"
"time"
)
// http升级websocket协议的配置
var wsUpgrader = websocket.Upgrader{
// 允许配置的 CORS 请求
CheckOrigin: checkOrigin,
}
var allowedOrigins = loadAllowedOrigins()
type server struct {
addr string
router *Router
needSecret bool
beforeClose func(WSConn)
httpServer *http.Server
}
func NewServer(addr string, needSecret bool) *server {
s := server{
addr: addr,
needSecret: needSecret,
}
return &s
}
func (this *server) Router(router *Router) {
this.router = router
}
func (this *server) Start() {
mux := http.NewServeMux()
mux.HandleFunc("/", this.wsHandler)
this.httpServer = &http.Server{
Addr: this.addr,
Handler: mux,
}
slog.Info("server starting", "addr", this.addr)
go func() {
if err := this.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
slog.Error("server start failed", "error", err, "addr", this.addr)
}
}()
this.waitForShutdown()
}
func (this *server) waitForShutdown() {
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
slog.Info("server shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := this.httpServer.Shutdown(ctx); err != nil {
slog.Error("server shutdown error", "error", err)
} else {
slog.Info("server shutdown gracefully")
}
}
func (this *server) SetOnBeforeClose(hookFunc func(WSConn)) {
this.beforeClose = hookFunc
}
func (this *server) wsHandler(resp http.ResponseWriter, req *http.Request) {
wsSocket, err := wsUpgrader.Upgrade(resp, req, nil)
if err != nil {
slog.Warn("websocket upgrade failed", "error", err, "remote", req.RemoteAddr)
return
}
conn := ConnMgr.NewConn(wsSocket, this.needSecret)
slog.Info("client connect", "addr", wsSocket.RemoteAddr().String())
conn.SetRouter(this.router)
conn.SetOnClose(ConnMgr.RemoveConn)
conn.SetOnBeforeClose(this.beforeClose)
conn.Start()
conn.Handshake()
}
func checkOrigin(r *http.Request) bool {
if len(allowedOrigins) == 0 {
return true
}
origin := strings.ToLower(strings.TrimSpace(r.Header.Get("Origin")))
if origin == "" {
return true
}
if _, ok := allowedOrigins[origin]; ok {
return true
}
slog.Warn("origin not allowed", "origin", origin)
return false
}
func loadAllowedOrigins() map[string]struct{} {
origins := config.GetString("server.allowed_origins", "")
if origins == "" {
return nil
}
originMap := make(map[string]struct{})
items := strings.Split(origins, ",")
for _, item := range items {
val := strings.ToLower(strings.TrimSpace(item))
if val == "" {
continue
}
if val == "*" {
return nil
}
originMap[val] = struct{}{}
}
return originMap
}

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:
}
}