初始化项目
This commit is contained in:
76
trunk/framework/websocketServer/IServer.go
Normal file
76
trunk/framework/websocketServer/IServer.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// ************************************
|
||||
// @package: websocketServer
|
||||
// @description: WsServer/WssServer接口,以便统一调用
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-22 16:07:27
|
||||
// ************************************
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
webServer "Framework/webServer"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IServer
|
||||
// @description: WsServer/WssServer接口,以便统一调用
|
||||
type IServer interface {
|
||||
//-------------------------------------
|
||||
// HttpServer方法
|
||||
|
||||
// HttpServer接口
|
||||
webServer.IWebServer
|
||||
|
||||
// 设置地址
|
||||
SetAddr(addr string)
|
||||
|
||||
// 启动HttpServer
|
||||
Start(wg *sync.WaitGroup)
|
||||
|
||||
//-------------------------------------
|
||||
// websocket方法
|
||||
|
||||
// 注册websocket回调
|
||||
RegisterWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig)
|
||||
|
||||
// 注册正则websocket回调
|
||||
RegisterRegexWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig)
|
||||
|
||||
// 设置websocket参数结构
|
||||
SetUpgrader(upgrader *websocket.Upgrader)
|
||||
|
||||
// 获取websocket参数结构
|
||||
GetUpgrader() *websocket.Upgrader
|
||||
|
||||
// 设置接收到Ping消息时,是否自动回复Pong信息
|
||||
SetAutoPong(autuPong bool)
|
||||
|
||||
// 获取接收到Ping消息时,是否自动回复Pong信息
|
||||
GetAutoPong() bool
|
||||
|
||||
// 设置心跳检测信息
|
||||
SetHeartbeatDetectInfo(heartbeatCloseCount int, heartbeatCycle time.Duration)
|
||||
|
||||
// 获取心跳检测信息
|
||||
GetHeartbeatDetectInfo() (heartbeatCloseCount int, heartbeatCycle time.Duration)
|
||||
|
||||
// 设置广播并发数
|
||||
SetBroadcastConcurrent(n int)
|
||||
|
||||
// 允许新连接
|
||||
EnableNewConn()
|
||||
|
||||
// 禁用新连接
|
||||
DisableNewConn()
|
||||
|
||||
// 多播消息(给指定多用户发送消息)
|
||||
MulticastMessage(ctxs []*Context, messageType int, data []byte) (err error)
|
||||
|
||||
// 消息广播
|
||||
BroadcastMessage(messageType int, data []byte) (err error)
|
||||
|
||||
// 关闭所有连接
|
||||
CloseAll()
|
||||
}
|
||||
450
trunk/framework/websocketServer/connManager.go
Normal file
450
trunk/framework/websocketServer/connManager.go
Normal file
@@ -0,0 +1,450 @@
|
||||
// ************************************
|
||||
// @package: websocketServer
|
||||
// @description: websocket管理
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-18 15:38:17
|
||||
// ************************************
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gorilla/websocket"
|
||||
routineCtrlUtil "goutil/routineCtrlUtil"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// 默认广播并发数
|
||||
con_DEFAULT_BROADCAST_CONCURRENT = 10
|
||||
)
|
||||
|
||||
// connManager
|
||||
// @description: websocket连接管理
|
||||
type connManager struct {
|
||||
// 是否禁止新连接
|
||||
disableNewConn bool
|
||||
|
||||
// 广播并发数
|
||||
broadcastConcurrent int
|
||||
|
||||
// websocket服务端配置结构
|
||||
upgrader *websocket.Upgrader
|
||||
|
||||
// 广播锁-限制 消息广播/关闭所有连接 并发访问
|
||||
muBroadcast sync.Mutex
|
||||
|
||||
// 连接池map写锁(增加/删除)
|
||||
muAllConns sync.Mutex
|
||||
|
||||
// 连接池-所有已连接的websocket
|
||||
allConns map[*websocket.Conn]*Context
|
||||
|
||||
//-------------------
|
||||
// 心跳控制
|
||||
|
||||
// 接收到Ping消息时,是否自动回复Pong
|
||||
autuPong bool
|
||||
|
||||
// 心跳周期
|
||||
heartbeatCycle time.Duration
|
||||
|
||||
// 断连周期数(超过几个心跳周期即自动关闭连接);设置为0即关闭心跳检测功能
|
||||
heartbeatCloseCount int
|
||||
|
||||
// 是否已开启心跳检测协程
|
||||
isHeartbeatDetectStart bool
|
||||
}
|
||||
|
||||
// heartbeatDetect
|
||||
// @description: 开启心跳检测协程
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) heartbeatDetect() {
|
||||
// 限制每个websocket连接管理只开启一个心跳检测协程
|
||||
if !connMgr.isHeartbeatDetectStart {
|
||||
connMgr.isHeartbeatDetectStart = true
|
||||
|
||||
// 开启心跳检测协程
|
||||
go func() {
|
||||
for {
|
||||
if connMgr.heartbeatCloseCount <= 0 {
|
||||
// 心跳检测功能已关闭;每秒检测此标志
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
// 心跳检测功能已开启
|
||||
|
||||
connMgr.muAllConns.Lock() // 连接池map锁
|
||||
ctxs_timeout := make([]*Context, 0, len(connMgr.allConns)) // 存放心跳超时,需要关闭的websocket环境
|
||||
for _, ctx := range connMgr.allConns {
|
||||
if time.Since(ctx.heartbeat) > (connMgr.heartbeatCycle*time.Duration(connMgr.heartbeatCloseCount) + 1) {
|
||||
// 心跳超时,需要关闭的websocket环境加入列表
|
||||
ctxs_timeout = append(ctxs_timeout, ctx)
|
||||
}
|
||||
}
|
||||
connMgr.muAllConns.Unlock() // 连接池map及时解锁
|
||||
|
||||
// 关闭所有心跳超时的连接
|
||||
func() {
|
||||
// 获取广播并发数
|
||||
broadcastConcurrent := connMgr.broadcastConcurrent
|
||||
if broadcastConcurrent <= 0 {
|
||||
broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT
|
||||
}
|
||||
|
||||
// 协程并发限制
|
||||
rtCtrl := routineCtrlUtil.New(broadcastConcurrent)
|
||||
for _, ctx := range ctxs_timeout {
|
||||
ctxTemp := ctx
|
||||
rtCtrl.Run(func(arg interface{}) {
|
||||
// 执行受限并发函数
|
||||
ctxTemp.Close()
|
||||
}, nil)
|
||||
}
|
||||
|
||||
// 等待完成
|
||||
rtCtrl.Wait()
|
||||
}()
|
||||
|
||||
// 休眠半个心跳周期
|
||||
slpTime := time.Duration(connMgr.heartbeatCycle / 2)
|
||||
if slpTime < time.Second {
|
||||
slpTime = time.Second
|
||||
}
|
||||
time.Sleep(slpTime)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// upgrade
|
||||
// @description: 升级为websocket
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @ctx: websocket环境
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @*websocket.Conn: 建立的连接对象
|
||||
// @error:
|
||||
func (connMgr *connManager) upgrade(ctx *Context) (conn *websocket.Conn, err error) {
|
||||
if connMgr.disableNewConn {
|
||||
// 禁止新连接
|
||||
return nil, errors.New("connManager(disableNewConn)")
|
||||
}
|
||||
|
||||
// 建立websocket连接
|
||||
conn, err = connMgr.upgrader.Upgrade(ctx.GetWebServerContext().GetResponseWriter(), ctx.GetWebServerContext().GetRequest(), nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 添加到连接池
|
||||
ctx.conn = conn
|
||||
connMgr.addConn(conn, ctx)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// addConn
|
||||
// @description: 添加到连接池
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @conn:
|
||||
// @ctx:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) addConn(conn *websocket.Conn, ctx *Context) {
|
||||
connMgr.muAllConns.Lock()
|
||||
defer connMgr.muAllConns.Unlock()
|
||||
|
||||
connMgr.allConns[conn] = ctx
|
||||
}
|
||||
|
||||
// delConn
|
||||
// @description: 将连接从连接池删除
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @conn:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) delConn(conn *websocket.Conn) {
|
||||
connMgr.muAllConns.Lock()
|
||||
defer connMgr.muAllConns.Unlock()
|
||||
|
||||
delete(connMgr.allConns, conn)
|
||||
}
|
||||
|
||||
// renewAllConnsMap
|
||||
// @description: 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @map[*websocket.Conn]*Context: 返回原内部使用的连接池(现内部已不再使用)
|
||||
func (connMgr *connManager) renewAllConnsMap() map[*websocket.Conn]*Context {
|
||||
connMgr.muAllConns.Lock()
|
||||
defer connMgr.muAllConns.Unlock()
|
||||
|
||||
// map拷贝
|
||||
allConnsCopy := make(map[*websocket.Conn]*Context, len(connMgr.allConns))
|
||||
for conn, ctx := range connMgr.allConns {
|
||||
allConnsCopy[conn] = ctx
|
||||
}
|
||||
// map替换;因map删除时只是标记,并非真正删除,使用一段时间后可能会出现大量未使用信息;这里顺便更新一下map
|
||||
connMgr.allConns, allConnsCopy = allConnsCopy, connMgr.allConns
|
||||
|
||||
return allConnsCopy
|
||||
}
|
||||
|
||||
// SetBroadcastConcurrent
|
||||
// @description: 设置广播并发数
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @n: 广播并发数
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) SetBroadcastConcurrent(n int) {
|
||||
connMgr.broadcastConcurrent = n
|
||||
}
|
||||
|
||||
// EnableNewConn
|
||||
// @description: 允许新连接
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) EnableNewConn() {
|
||||
connMgr.disableNewConn = false
|
||||
}
|
||||
|
||||
// DisableNewConn
|
||||
// @description: 禁用新连接
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) DisableNewConn() {
|
||||
connMgr.disableNewConn = true
|
||||
}
|
||||
|
||||
// MulticastMessage
|
||||
// @description: 多播消息(给指定多用户发送消息)
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @ctxs: 指定多用户的*Context切片
|
||||
// @messageType: websocket类型
|
||||
// @data: 发送的数据
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @err: 若有错误,则为最后一个错误
|
||||
func (connMgr *connManager) MulticastMessage(ctxs []*Context, messageType int, data []byte) (err error) {
|
||||
// 广播锁,防重入
|
||||
connMgr.muBroadcast.Lock()
|
||||
defer connMgr.muBroadcast.Unlock()
|
||||
|
||||
// 获取广播并发数
|
||||
broadcastConcurrent := connMgr.broadcastConcurrent
|
||||
if broadcastConcurrent <= 0 {
|
||||
broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT
|
||||
}
|
||||
|
||||
// 协程并发限制
|
||||
rtCtrl := routineCtrlUtil.New(broadcastConcurrent)
|
||||
var mu sync.Mutex
|
||||
for _, ctx := range ctxs {
|
||||
// 执行受限并发函数
|
||||
// 注意:这里的ctx需要使用参数传入Run;否则随时变化的ctx在闭包内使用时,会出现不符合程序要求逻辑的结果
|
||||
rtCtrl.Run(func(arg interface{}) {
|
||||
ctxTemp, _ := arg.(*Context)
|
||||
e := ctxTemp.SendMessage(messageType, data)
|
||||
if e != nil {
|
||||
mu.Lock()
|
||||
err = e
|
||||
mu.Unlock()
|
||||
}
|
||||
}, ctx)
|
||||
}
|
||||
|
||||
// 等待完成
|
||||
rtCtrl.Wait()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// BroadcastMessage
|
||||
// @description: 消息广播
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @messageType: websocket类型
|
||||
// @data: 发送的数据
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @err: 若有错误,则为最后一个错误
|
||||
func (connMgr *connManager) BroadcastMessage(messageType int, data []byte) (err error) {
|
||||
// 广播锁,防重入
|
||||
connMgr.muBroadcast.Lock()
|
||||
defer connMgr.muBroadcast.Unlock()
|
||||
|
||||
// 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题
|
||||
allConnsCopy := connMgr.renewAllConnsMap()
|
||||
|
||||
// 获取广播并发数
|
||||
broadcastConcurrent := connMgr.broadcastConcurrent
|
||||
if broadcastConcurrent <= 0 {
|
||||
broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT
|
||||
}
|
||||
|
||||
// 协程并发限制
|
||||
rtCtrl := routineCtrlUtil.New(broadcastConcurrent)
|
||||
var mu sync.Mutex
|
||||
for _, ctx := range allConnsCopy {
|
||||
// 执行受限并发函数
|
||||
// 注意:这里的ctx需要使用参数传入Run;否则随时变化的ctx在闭包内使用时,会出现不符合程序要求逻辑的结果
|
||||
rtCtrl.Run(func(arg interface{}) {
|
||||
ctxTemp, _ := arg.(*Context)
|
||||
e := ctxTemp.SendMessage(messageType, data)
|
||||
if e != nil {
|
||||
mu.Lock()
|
||||
err = e
|
||||
mu.Unlock()
|
||||
}
|
||||
}, ctx)
|
||||
}
|
||||
|
||||
// 等待完成
|
||||
rtCtrl.Wait()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CloseAll
|
||||
// @description: 关闭所有连接
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) CloseAll() {
|
||||
// 广播锁,防重入
|
||||
connMgr.muBroadcast.Lock()
|
||||
defer connMgr.muBroadcast.Unlock()
|
||||
|
||||
// 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题
|
||||
allConnsCopy := connMgr.renewAllConnsMap()
|
||||
|
||||
// 获取广播并发数
|
||||
broadcastConcurrent := connMgr.broadcastConcurrent
|
||||
if broadcastConcurrent <= 0 {
|
||||
broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT
|
||||
}
|
||||
|
||||
// 协程并发限制
|
||||
rtCtrl := routineCtrlUtil.New(broadcastConcurrent)
|
||||
for _, ctx := range allConnsCopy {
|
||||
rtCtrl.Run(func(arg interface{}) {
|
||||
ctxTemp, _ := arg.(*Context)
|
||||
// 执行受限并发函数
|
||||
ctxTemp.Close()
|
||||
}, ctx)
|
||||
}
|
||||
|
||||
// 等待完成
|
||||
rtCtrl.Wait()
|
||||
}
|
||||
|
||||
// SetUpgrader
|
||||
// @description: 设置websocket参数结构
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @upgrader: websocket中的websocket.Upgrader结构体指针(可以设置握手超时/读写缓存/是否允许跨域等)
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) SetUpgrader(upgrader *websocket.Upgrader) {
|
||||
connMgr.upgrader = upgrader
|
||||
}
|
||||
|
||||
// GetUpgrader
|
||||
// @description: 获取websocket参数结构
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @*websocket.Upgrader: websocket中的websocket.Upgrader结构体指针(可以设置握手超时/读写缓存/是否允许跨域等)
|
||||
func (connMgr *connManager) GetUpgrader() *websocket.Upgrader {
|
||||
return connMgr.upgrader
|
||||
}
|
||||
|
||||
// SetAutoPong
|
||||
// @description: 设置接收到Ping消息时,是否自动回复Pong信息
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @autuPong:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) SetAutoPong(autuPong bool) {
|
||||
connMgr.autuPong = autuPong
|
||||
}
|
||||
|
||||
// GetAutoPong
|
||||
// @description: 获取接收到Ping消息时,是否自动回复Pong信息
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @bool:
|
||||
func (connMgr *connManager) GetAutoPong() bool {
|
||||
return connMgr.autuPong
|
||||
}
|
||||
|
||||
// SetHeartbeatDetectInfo
|
||||
// @description: 设置心跳检测信息
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @heartbeatCloseCount: 断连周期数(超过几个心跳周期即自动关闭连接);设置为0即关闭心跳检测功能
|
||||
// @heartbeatCycle: 心跳周期
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) SetHeartbeatDetectInfo(heartbeatCloseCount int, heartbeatCycle time.Duration) {
|
||||
connMgr.heartbeatCycle = heartbeatCycle
|
||||
connMgr.heartbeatCloseCount = heartbeatCloseCount
|
||||
}
|
||||
|
||||
// GetHeartbeatDetectInfo
|
||||
// @description: 获取心跳检测信息
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @heartbeatCloseCount: 断连周期数(超过几个心跳周期即自动关闭连接)
|
||||
// @heartbeatCycle: 心跳周期
|
||||
func (connMgr *connManager) GetHeartbeatDetectInfo() (heartbeatCloseCount int, heartbeatCycle time.Duration) {
|
||||
return connMgr.heartbeatCloseCount, connMgr.heartbeatCycle
|
||||
}
|
||||
163
trunk/framework/websocketServer/context.go
Normal file
163
trunk/framework/websocketServer/context.go
Normal file
@@ -0,0 +1,163 @@
|
||||
// ************************************
|
||||
// @package: websocketServer
|
||||
// @description: websocket环境
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-18 15:59:08
|
||||
// ************************************
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
webServer "Framework/webServer"
|
||||
)
|
||||
|
||||
// Context
|
||||
// @description: websocket环境
|
||||
type Context struct {
|
||||
ctx context.Context
|
||||
|
||||
// web_server环境
|
||||
webServerCtx *webServer.Context
|
||||
|
||||
// 存放用户自定义数据
|
||||
userData interface{}
|
||||
|
||||
// websocket连接
|
||||
conn *websocket.Conn
|
||||
|
||||
// 防止多协程同时写/关闭
|
||||
mu sync.Mutex
|
||||
|
||||
// 最近一次收到心跳包的时间
|
||||
heartbeat time.Time
|
||||
|
||||
// 指示是否已经关闭
|
||||
isClosed bool
|
||||
|
||||
// 关闭连接信号
|
||||
cls chan<- struct{}
|
||||
}
|
||||
|
||||
// GetWebServerContext
|
||||
// @description: 获取web_server环境
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ctx:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @*web_server.Context: web_server环境
|
||||
func (ctx *Context) GetWebServerContext() *webServer.Context {
|
||||
return ctx.webServerCtx
|
||||
}
|
||||
|
||||
// GetUserData
|
||||
// @description: 获取用户自定义数据
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ctx:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @interface{}:
|
||||
func (ctx *Context) GetUserData() interface{} {
|
||||
return ctx.userData
|
||||
}
|
||||
|
||||
// SetUserData
|
||||
// @description: 设置用户自定义数据
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ctx:
|
||||
// @userData:
|
||||
//
|
||||
// return:
|
||||
func (ctx *Context) SetUserData(userData interface{}) {
|
||||
ctx.userData = userData
|
||||
}
|
||||
|
||||
// SendMessage
|
||||
// @description: 发送websocket数据
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ctx:
|
||||
// @messageType:
|
||||
// @data:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @err:
|
||||
func (ctx *Context) SendMessage(messageType int, data []byte) (err error) {
|
||||
ctx.mu.Lock()
|
||||
defer ctx.mu.Unlock()
|
||||
|
||||
return ctx.conn.WriteMessage(messageType, data)
|
||||
}
|
||||
|
||||
// Close
|
||||
// @description: 关闭websocket连接
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ctx:
|
||||
//
|
||||
// return:
|
||||
func (ctx *Context) Close() {
|
||||
ctx.mu.Lock()
|
||||
defer ctx.mu.Unlock()
|
||||
|
||||
if !ctx.isClosed {
|
||||
// 设置已关闭标志
|
||||
ctx.isClosed = true
|
||||
// 发送退出信号
|
||||
// 所有向cls写入,都使用select超时结构,以保证这儿不会一直阻塞,确保此协程能退出
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case ctx.cls <- struct{}{}:
|
||||
}
|
||||
//ctx.cls <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Ctx
|
||||
// @description: 返回Context
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ctx:
|
||||
//
|
||||
// return:
|
||||
func (ctx *Context) Ctx() context.Context {
|
||||
ctx.mu.Lock()
|
||||
defer ctx.mu.Unlock()
|
||||
|
||||
return ctx.ctx
|
||||
}
|
||||
|
||||
// SetCtx
|
||||
// @description: 设置新的Ctx
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ctx:
|
||||
//
|
||||
// return:
|
||||
func (ctx *Context) SetCtx(c context.Context) {
|
||||
ctx.mu.Lock()
|
||||
defer ctx.mu.Unlock()
|
||||
|
||||
ctx.ctx = c
|
||||
}
|
||||
|
||||
// GetConnType
|
||||
// @description: 获取连接类型
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ctx:
|
||||
//
|
||||
// return:
|
||||
func (ctx *Context) GetConnType() string {
|
||||
return "websocket"
|
||||
}
|
||||
73
trunk/framework/websocketServer/doc.go
Normal file
73
trunk/framework/websocketServer/doc.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package websocketServer
|
||||
|
||||
/*
|
||||
此包是对web_server包的封装,并扩展出websocket相关功能
|
||||
|
||||
使用方法如下:
|
||||
初始化一个WsServer/WssServer
|
||||
server := NewWsServer(addr string, isCheckIP bool)
|
||||
或
|
||||
server := NewWssServer(addr, certFileName, keyFileName string, isCheckIP bool)
|
||||
|
||||
其它调用方法见 webServer
|
||||
|
||||
websocket扩展方法:
|
||||
// 注册websocket回调
|
||||
server.RegisterWebsocketHandler(path string, eventCallback *eventCallbackFuncs, configObj *web_server.HandlerConfig)
|
||||
server.RegisterRegexWebsocketHandler(path string, eventCallback *eventCallbackFuncs, configObj *web_server.HandlerConfig)
|
||||
|
||||
// 设置websocket配置信息(可以设置握手超时/读写缓存/是否允许跨域等)
|
||||
server.SetUpgrader(upgrader *websocket.Upgrader)
|
||||
|
||||
// 获取websocket配置信息
|
||||
server.GetUpgrader() *websocket.Upgrader
|
||||
|
||||
// 设置接收到Ping消息时,是否自动回复Pong信息
|
||||
server.SetAutoPong(autuPong bool)
|
||||
|
||||
// 获取接收到Ping消息时,是否自动回复Pong信息
|
||||
server.GetAutoPong() bool
|
||||
|
||||
// 设置心跳检测信息
|
||||
server.SetHeartbeatDetectInfo(heartbeatCloseCount int, heartbeatCycle time.Duration)
|
||||
|
||||
// 获取心跳检测信息
|
||||
server.GetHeartbeatDetectInfo() (heartbeatCloseCount int, heartbeatCycle time.Duration)
|
||||
|
||||
// 设置广播并发数
|
||||
server.SetBroadcastConcurrent(n int)
|
||||
|
||||
// 允许新连接
|
||||
server.EnableNewConn()
|
||||
|
||||
// 禁用新连接
|
||||
server.DisableNewConn()
|
||||
|
||||
// 消息广播
|
||||
server.BroadcastMessage(messageType int, data []byte)
|
||||
|
||||
// 关闭所有连接
|
||||
server.CloseAll()
|
||||
|
||||
eventCallbackFuncs 回调:
|
||||
// websocket连接事件
|
||||
OnConnFunc func(ctx *Context)
|
||||
|
||||
// websocket关闭事件
|
||||
OnCloseFunc func(ctx *Context)
|
||||
|
||||
// websocket接收事件
|
||||
OnMsgFunc func(ctx *Context, msgType int, msgData []byte)
|
||||
|
||||
回调参数说明:
|
||||
ctx - websocket环境,提供了以下方法:
|
||||
GetWebServerContext() *web_server.Context - 获取web_server环境
|
||||
GetUserData() interface{} - 获取用户自定义数据
|
||||
SetUserData(userData interface{}) - 设置用户自定义数据
|
||||
SendMessage(messageType int, data []byte) (err error) - 发送websocket数据
|
||||
Close() - 关闭websocket连接
|
||||
msgType - 接收到的websocket类型
|
||||
msgData - 接收到的websocket数据
|
||||
|
||||
使用示例,见 wsServer_test.go
|
||||
*/
|
||||
206
trunk/framework/websocketServer/hookHandler.go
Normal file
206
trunk/framework/websocketServer/hookHandler.go
Normal file
@@ -0,0 +1,206 @@
|
||||
// ************************************
|
||||
// @package: websocketServer
|
||||
// @description:
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-16 18:13:45
|
||||
// ************************************
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
webServer "Framework/webServer"
|
||||
logUtil "goutil/logUtil"
|
||||
)
|
||||
|
||||
// 事件回调函数
|
||||
type EventCallbackFuncs struct {
|
||||
// websocket连接事件
|
||||
OnConnFunc func(ctx *Context)
|
||||
|
||||
// websocket关闭事件
|
||||
OnCloseFunc func(ctx *Context)
|
||||
|
||||
// websocket接收事件
|
||||
OnMsgFunc func(ctx *Context, msgType int, msgData []byte)
|
||||
}
|
||||
|
||||
// 用户自定义数据结构
|
||||
type userDatas struct {
|
||||
// WsServer 或 WssServer 指针
|
||||
server interface{}
|
||||
|
||||
// 事件回调函数
|
||||
eventCallback *EventCallbackFuncs
|
||||
}
|
||||
|
||||
// iServerMgr
|
||||
// @description: WsServer/WssServer内部管理接口,以便hookHandler中统一访问
|
||||
type iServerMgr interface {
|
||||
// 升级为websocket
|
||||
upgrade(ctx *Context) (conn *websocket.Conn, err error)
|
||||
|
||||
// 将连接从连接池删除
|
||||
delConn(conn *websocket.Conn)
|
||||
|
||||
// 获取接收到Ping消息时,是否自动回复Pong信息
|
||||
GetAutoPong() bool
|
||||
}
|
||||
|
||||
// 回调勾子,将http/https升级为websocket
|
||||
func hookHandler(webServerCtx *webServer.Context) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logUtil.LogUnknownError(r)
|
||||
}
|
||||
}()
|
||||
|
||||
userDataI := webServerCtx.GetUserData()
|
||||
if userDataI == nil {
|
||||
return
|
||||
}
|
||||
|
||||
userData, ok := userDataI.(*userDatas)
|
||||
if !ok {
|
||||
logUtil.ErrorLog("userData type error")
|
||||
return
|
||||
}
|
||||
|
||||
// 通信结束信号
|
||||
cls := make(chan struct{})
|
||||
ctx := &Context{
|
||||
webServerCtx: webServerCtx, // web_server环境
|
||||
cls: cls, // 关闭连接信号
|
||||
}
|
||||
|
||||
var serverMgr iServerMgr
|
||||
var conn *websocket.Conn
|
||||
var err error
|
||||
|
||||
// 转为iServerMgr
|
||||
switch userData.server.(type) {
|
||||
case *WsServer:
|
||||
if svr, ok := userData.server.(*WsServer); ok {
|
||||
serverMgr = svr
|
||||
} else {
|
||||
logUtil.ErrorLog("server type not WsServer")
|
||||
return
|
||||
}
|
||||
case *WssServer:
|
||||
if svr, ok := userData.server.(*WssServer); ok {
|
||||
serverMgr = svr
|
||||
} else {
|
||||
logUtil.ErrorLog("server type not WssServer")
|
||||
return
|
||||
}
|
||||
default:
|
||||
logUtil.ErrorLog("server type not WsServer or WssServer")
|
||||
return
|
||||
}
|
||||
|
||||
// 升级为websocket
|
||||
conn, err = serverMgr.upgrade(ctx)
|
||||
if err != nil {
|
||||
if err.Error() == "connManager(disableNewConn)" {
|
||||
// 禁用新连接。正常功能,直接返回
|
||||
return
|
||||
}
|
||||
|
||||
logUtil.ErrorLog("websocket Upgrade failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 将连接从连接池删除
|
||||
defer serverMgr.delConn(conn)
|
||||
|
||||
// 关闭连接
|
||||
defer conn.Close()
|
||||
|
||||
// 默认情况下,ReadMessage不会读取到ping/pong/close消息(内部有专门的处理函数)
|
||||
// 设置心跳包处理函数
|
||||
conn.SetPingHandler(func(msg string) error {
|
||||
// 只要收到消息,都需要更新最近一次收到心跳包的时间
|
||||
ctx.heartbeat = time.Now()
|
||||
|
||||
if serverMgr.GetAutoPong() {
|
||||
// 自动回应一个Pong心跳
|
||||
go ctx.SendMessage(websocket.PongMessage, []byte(msg))
|
||||
}
|
||||
|
||||
// 接收消息回调
|
||||
if userData.eventCallback.OnMsgFunc != nil {
|
||||
userData.eventCallback.OnMsgFunc(ctx, websocket.PingMessage, []byte(msg))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
// 设置关闭包处理函数
|
||||
conn.SetCloseHandler(func(code int, text string) error {
|
||||
// 所有向cls写入,都使用select超时结构,以保证这儿不会一直阻塞,确保此协程能退出
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case cls <- struct{}{}:
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// 设置最近一次收到心跳包的时间
|
||||
ctx.heartbeat = time.Now()
|
||||
|
||||
// 新连接回调
|
||||
if userData.eventCallback.OnConnFunc != nil {
|
||||
userData.eventCallback.OnConnFunc(ctx)
|
||||
}
|
||||
|
||||
// 开启读协程
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logUtil.LogUnknownError(r)
|
||||
|
||||
// 有异常出现(可能是用户回调中出现异常);执行到这儿,需要关闭连接
|
||||
// 所有向cls写入,都使用select超时结构,以保证这儿不会一直阻塞,确保此协程能退出
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case cls <- struct{}{}:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
// 注意:ReadMessage不会读取到心跳包和关闭包数据;心跳包/关闭包需要设置专门的处理函数
|
||||
// 但内部对心跳包/关闭包的处理,也是由ReadMessage函数触发的(也就是不调用ReadMessage函数,可能也不会触发对心跳包/关闭包的处理);
|
||||
// 经测试和内部代码确认:调用心跳包/关闭包处理函数时,ReadMessage不会返回;心跳包/关闭包处理函数调用完毕后ReadMessage才可能返回
|
||||
mt, msg, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
// 所有向cls写入,都使用select超时结构,以保证这儿不会一直阻塞,确保此协程能退出
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case cls <- struct{}{}:
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// 只要收到消息,都需要更新最近一次收到心跳包的时间
|
||||
ctx.heartbeat = time.Now()
|
||||
|
||||
// 接收消息回调
|
||||
if userData.eventCallback.OnMsgFunc != nil {
|
||||
userData.eventCallback.OnMsgFunc(ctx, mt, msg)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 等待退出
|
||||
<-cls
|
||||
|
||||
// 设置已关闭标志
|
||||
ctx.isClosed = true
|
||||
|
||||
// 关闭回调
|
||||
if userData.eventCallback.OnCloseFunc != nil {
|
||||
userData.eventCallback.OnCloseFunc(ctx)
|
||||
}
|
||||
}
|
||||
80
trunk/framework/websocketServer/websocketTestClient.html
Normal file
80
trunk/framework/websocketServer/websocketTestClient.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>go websocket</title>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var wsUri ="ws://127.0.0.1:22222/websocket";
|
||||
var output;
|
||||
|
||||
function init() {
|
||||
output = document.getElementById("output");
|
||||
testWebSocket();
|
||||
}
|
||||
|
||||
function testWebSocket() {
|
||||
websocket = new WebSocket(wsUri);
|
||||
websocket.onopen = function(evt) {
|
||||
onOpen(evt)
|
||||
};
|
||||
websocket.onclose = function(evt) {
|
||||
onClose(evt)
|
||||
};
|
||||
websocket.onmessage = function(evt) {
|
||||
onMessage(evt)
|
||||
};
|
||||
websocket.onerror = function(evt) {
|
||||
onError(evt)
|
||||
};
|
||||
}
|
||||
|
||||
function onOpen(evt) {
|
||||
writeToScreen("CONNECTED");
|
||||
// doSend("WebSocket rocks");
|
||||
}
|
||||
|
||||
function onClose(evt) {
|
||||
writeToScreen("DISCONNECTED");
|
||||
}
|
||||
|
||||
function onMessage(evt) {
|
||||
writeToScreen('<span style="color: blue;">RESPONSE: '+ evt.data+'</span>');
|
||||
// websocket.close();
|
||||
}
|
||||
|
||||
function onError(evt) {
|
||||
writeToScreen('<span style="color: red;">ERROR:</span> '+ evt.data);
|
||||
}
|
||||
|
||||
function doSend(message) {
|
||||
writeToScreen("SENT: " + message);
|
||||
websocket.send(message);
|
||||
}
|
||||
|
||||
function writeToScreen(message) {
|
||||
var pre = document.createElement("p");
|
||||
pre.style.wordWrap = "break-word";
|
||||
pre.innerHTML = message;
|
||||
output.appendChild(pre);
|
||||
}
|
||||
|
||||
window.addEventListener("load", init, false);
|
||||
function sendBtnClick(){
|
||||
var msg = document.getElementById("input").value;
|
||||
doSend(msg);
|
||||
document.getElementById("input").value = '';
|
||||
}
|
||||
function closeBtnClick(){
|
||||
websocket.close();
|
||||
}
|
||||
</script>
|
||||
<h2>WebSocket Test</h2>
|
||||
<input type="text" id="input"></input>
|
||||
<button onclick="sendBtnClick()" >send</button>
|
||||
<button onclick="closeBtnClick()" >close</button>
|
||||
<div id="output"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
100
trunk/framework/websocketServer/wsServer.go
Normal file
100
trunk/framework/websocketServer/wsServer.go
Normal file
@@ -0,0 +1,100 @@
|
||||
// ************************************
|
||||
// @package: websocketServer
|
||||
// @description: websocket服务端
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-15 14:10:51
|
||||
// ************************************
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
webServer "Framework/webServer"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WsServer struct {
|
||||
*webServer.HttpServer
|
||||
|
||||
// websocket连接管理
|
||||
*connManager
|
||||
}
|
||||
|
||||
// RegisterWebsocketHandler
|
||||
// @description: 注册websocket回调
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ws:
|
||||
// @path:注册的访问路径
|
||||
// @handlerFuncObj:回调方法
|
||||
// @configObj:Handler配置对象
|
||||
//
|
||||
// return:
|
||||
func (ws *WsServer) RegisterWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) {
|
||||
ws.RegisterHandlerWithUserData(path, hookHandler, configObj, &userDatas{
|
||||
server: ws,
|
||||
eventCallback: eventCallback,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterRegexWebsocketHandler
|
||||
// @description: 注册正则websocket回调
|
||||
// parameter:
|
||||
//
|
||||
// @receiver wss:
|
||||
// @path:注册的正则访问路径
|
||||
// @eventCallback:回调方法
|
||||
// @configObj:Handler配置对象
|
||||
//
|
||||
// return:
|
||||
func (ws *WsServer) RegisterRegexWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) {
|
||||
ws.RegisterRegexHandlerWithUserData(path, hookHandler, configObj, &userDatas{
|
||||
server: ws,
|
||||
eventCallback: eventCallback,
|
||||
})
|
||||
}
|
||||
|
||||
func NewWsServer(addr string, isCheckIP bool) (server *WsServer) {
|
||||
server = &WsServer{
|
||||
HttpServer: webServer.NewHttpServer(addr, isCheckIP),
|
||||
connManager: &connManager{
|
||||
upgrader: &websocket.Upgrader{},
|
||||
allConns: make(map[*websocket.Conn]*Context),
|
||||
},
|
||||
}
|
||||
|
||||
// 开启心跳检测协程
|
||||
server.connManager.heartbeatDetect()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func NewWsServer2(addr string, webServerObj webServer.IWebServer) (server *WsServer) {
|
||||
server = &WsServer{
|
||||
HttpServer: webServer.NewHttpServer2(addr, webServerObj),
|
||||
connManager: &connManager{
|
||||
upgrader: &websocket.Upgrader{},
|
||||
allConns: make(map[*websocket.Conn]*Context),
|
||||
},
|
||||
}
|
||||
|
||||
// 开启心跳检测协程
|
||||
server.connManager.heartbeatDetect()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func NewWsServer3(addr string, isCheckIP bool, readTimeout time.Duration, readHeaderTimeout time.Duration, writeTimeout time.Duration) (server *WsServer) {
|
||||
server = &WsServer{
|
||||
HttpServer: webServer.NewHttpServer3(addr, isCheckIP, readTimeout, readHeaderTimeout, writeTimeout),
|
||||
connManager: &connManager{
|
||||
upgrader: &websocket.Upgrader{},
|
||||
allConns: make(map[*websocket.Conn]*Context),
|
||||
},
|
||||
}
|
||||
|
||||
// 开启心跳检测协程
|
||||
server.connManager.heartbeatDetect()
|
||||
|
||||
return
|
||||
}
|
||||
100
trunk/framework/websocketServer/wsServer_test.go
Normal file
100
trunk/framework/websocketServer/wsServer_test.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
"net/http"
|
||||
webServer "Framework/webServer"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 处理HTTP请求
|
||||
func httpHandler(cxt *webServer.Context) {
|
||||
msg := "test msg"
|
||||
cxt.GetResponseWriter().Write([]byte(msg))
|
||||
}
|
||||
|
||||
// websocket连接事件
|
||||
func onConnFunc(ctx *Context) {
|
||||
fmt.Printf("new conn, ip: %s %p\n", ctx.GetWebServerContext().GetRequestIP(), ctx)
|
||||
ctx.SendMessage(websocket.TextMessage, []byte("Hello")) // 返回数据
|
||||
}
|
||||
|
||||
// websocket关闭事件
|
||||
func onCloseFunc(ctx *Context) {
|
||||
fmt.Printf("close conn, ip: %s %p\n", ctx.GetWebServerContext().GetRequestIP(), ctx)
|
||||
}
|
||||
|
||||
// websocket接收事件
|
||||
func onMsgFunc(ctx *Context, msgType int, msgData []byte) {
|
||||
fmt.Printf("%p ", ctx)
|
||||
fmt.Println("msg ip:", ctx.GetWebServerContext().GetRequestIP(), "msg type:", msgType, "msg:", string(msgData))
|
||||
ctx.SendMessage(msgType, []byte("SVR: "+string(msgData))) // 返回数据
|
||||
|
||||
// 主动关闭连接测试
|
||||
if string(msgData) == "close" {
|
||||
ctx.SendMessage(msgType, []byte("close")) // 返回数据
|
||||
//time.Sleep(time.Microsecond * 100)
|
||||
ctx.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsServer(t *testing.T) {
|
||||
var ssl bool = false
|
||||
var server IServer
|
||||
if ssl {
|
||||
server = NewWssServer(":22222", "cert.pem", "key.pem", false)
|
||||
} else {
|
||||
server = NewWsServer(":22222", false)
|
||||
}
|
||||
|
||||
server.SetIfDelegate(false)
|
||||
|
||||
// 注册HTTP处理函数
|
||||
server.RegisterHandler("/http", httpHandler, &webServer.HandlerConfig{})
|
||||
|
||||
// 设置websocket允许跨域访问
|
||||
server.GetUpgrader().CheckOrigin = func(r *http.Request) bool {
|
||||
return true
|
||||
}
|
||||
//upgrader := &websocket.Upgrader{
|
||||
// // 允许跨域
|
||||
// CheckOrigin: func(r *http.Request) bool {
|
||||
// return true
|
||||
// },
|
||||
//}
|
||||
//server.SetUpgrader(upgrader)
|
||||
|
||||
// 注册websocket处理事件
|
||||
server.RegisterWebsocketHandler("/websocket", &EventCallbackFuncs{
|
||||
OnConnFunc: onConnFunc,
|
||||
OnCloseFunc: onCloseFunc,
|
||||
OnMsgFunc: onMsgFunc,
|
||||
}, &webServer.HandlerConfig{})
|
||||
|
||||
// 设置广播并发数
|
||||
server.SetBroadcastConcurrent(2)
|
||||
|
||||
// 设置接收到Ping消息时,自动回复Pong信息
|
||||
server.SetAutoPong(true)
|
||||
|
||||
// 设置心跳检测信息(心跳检测周期10秒;缺少2个心跳周期断开连接)
|
||||
server.SetHeartbeatDetectInfo(2, time.Second*10)
|
||||
|
||||
// 广播测试
|
||||
go func() {
|
||||
var i = 0
|
||||
for {
|
||||
time.Sleep(time.Second * 10)
|
||||
// 广播测试
|
||||
server.BroadcastMessage(websocket.TextMessage, []byte(strconv.Itoa(i)))
|
||||
i++
|
||||
}
|
||||
}()
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
server.Start(&wg)
|
||||
}
|
||||
84
trunk/framework/websocketServer/wssServer.go
Normal file
84
trunk/framework/websocketServer/wssServer.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// ************************************
|
||||
// @package: websocketServer
|
||||
// @description: websocket加密服务端
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-15 16:18:45
|
||||
// ************************************
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
webServer "Framework/webServer"
|
||||
)
|
||||
|
||||
type WssServer struct {
|
||||
*webServer.HttpsServer
|
||||
|
||||
// websocket连接管理
|
||||
*connManager
|
||||
}
|
||||
|
||||
// RegisterWebsocketHandler
|
||||
// @description: 注册websocket回调
|
||||
// parameter:
|
||||
//
|
||||
// @receiver ws:
|
||||
// @path:注册的访问路径
|
||||
// @handlerFuncObj:回调方法
|
||||
// @configObj:Handler配置对象
|
||||
//
|
||||
// return:
|
||||
func (wss *WssServer) RegisterWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) {
|
||||
wss.RegisterHandlerWithUserData(path, hookHandler, configObj, &userDatas{
|
||||
server: wss,
|
||||
eventCallback: eventCallback,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterRegexWebsocketHandler
|
||||
// @description: 注册正则websocket回调
|
||||
// parameter:
|
||||
//
|
||||
// @receiver wss:
|
||||
// @path:注册的正则访问路径
|
||||
// @eventCallback:回调方法
|
||||
// @configObj:Handler配置对象
|
||||
//
|
||||
// return:
|
||||
func (wss *WssServer) RegisterRegexWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) {
|
||||
wss.RegisterRegexHandlerWithUserData(path, hookHandler, configObj, &userDatas{
|
||||
server: wss,
|
||||
eventCallback: eventCallback,
|
||||
})
|
||||
}
|
||||
|
||||
func NewWssServer(addr, certFileName, keyFileName string, isCheckIP bool) (server *WssServer) {
|
||||
server = &WssServer{
|
||||
HttpsServer: webServer.NewHttpsServer(addr, certFileName, keyFileName, isCheckIP),
|
||||
connManager: &connManager{
|
||||
upgrader: &websocket.Upgrader{},
|
||||
allConns: make(map[*websocket.Conn]*Context),
|
||||
},
|
||||
}
|
||||
|
||||
// 开启心跳检测协程
|
||||
server.connManager.heartbeatDetect()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func NewHttpsServer2(addr, certFileName, keyFileName string, webServerObj webServer.IWebServer) (server *WssServer) {
|
||||
server = &WssServer{
|
||||
HttpsServer: webServer.NewHttpsServer2(addr, certFileName, keyFileName, webServerObj),
|
||||
connManager: &connManager{
|
||||
upgrader: &websocket.Upgrader{},
|
||||
allConns: make(map[*websocket.Conn]*Context),
|
||||
},
|
||||
}
|
||||
|
||||
// 开启心跳检测协程
|
||||
server.connManager.heartbeatDetect()
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user