fix
This commit is contained in:
parent
88ae58c9d8
commit
ae80cf12f3
|
@ -5,7 +5,7 @@ type Websocket string
|
||||||
// websocket消息类型(主类别)
|
// websocket消息类型(主类别)
|
||||||
const (
|
const (
|
||||||
WEBSOCKET_UNAUTH Websocket = "WEBSOCKET_UNAUTH" //鉴权失败 (1级消息,单向通信)
|
WEBSOCKET_UNAUTH Websocket = "WEBSOCKET_UNAUTH" //鉴权失败 (1级消息,单向通信)
|
||||||
WEBSOCKET_GEN_UNIQUE_ID_ERR Websocket = "WEBSOCKET_GEN_UNIQUE_ID_ERR" //获取ws连接标识错误 (1级消息,单向通信)
|
WEBSOCKET_CONNECT_ERR Websocket = "WEBSOCKET_CONNECT_ERR" //ws连接错误 (1级消息,单向通信)
|
||||||
WEBSOCKET_CONNECT_SUCCESS Websocket = "WEBSOCKET_CONNECT_SUCCESS" //ws连接成功 (1级消息,单向通信)
|
WEBSOCKET_CONNECT_SUCCESS Websocket = "WEBSOCKET_CONNECT_SUCCESS" //ws连接成功 (1级消息,单向通信)
|
||||||
WEBSOCKET_REQUEST_REUSE_LAST_CONNECT Websocket = "WEBSOCKET_REQUEST_REUSE_LAST_CONNECT" //请求恢复为上次连接的标识 (1级消息,单向通信)
|
WEBSOCKET_REQUEST_REUSE_LAST_CONNECT Websocket = "WEBSOCKET_REQUEST_REUSE_LAST_CONNECT" //请求恢复为上次连接的标识 (1级消息,单向通信)
|
||||||
WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR Websocket = "WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR" //请求恢复为上次连接的标识错误 (1级消息,单向通信)
|
WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR Websocket = "WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR" //请求恢复为上次连接的标识错误 (1级消息,单向通信)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"fusenapi/constants"
|
"fusenapi/constants"
|
||||||
"fusenapi/utils/auth"
|
"fusenapi/utils/auth"
|
||||||
"fusenapi/utils/basic"
|
"fusenapi/utils/basic"
|
||||||
|
@ -66,6 +67,10 @@ var (
|
||||||
}
|
}
|
||||||
//websocket连接存储
|
//websocket连接存储
|
||||||
mapConnPool = sync.Map{}
|
mapConnPool = sync.Map{}
|
||||||
|
//用户标识的连接(白板用户不存)
|
||||||
|
mapUserConnPool = make(map[string]map[string]struct{}) //key是user_id +"_"+guest_id (val是个普通map,存储这个用户的所有连接标识)
|
||||||
|
//用户标识的连接增删操作队列
|
||||||
|
mapUserConnPoolCtlChan = make(chan userConnPoolChanItem, 2000)
|
||||||
//每个websocket连接入口缓冲队列长度
|
//每个websocket连接入口缓冲队列长度
|
||||||
websocketInChanLen = 1000
|
websocketInChanLen = 1000
|
||||||
//每个websocket连接出口缓冲队列长度
|
//每个websocket连接出口缓冲队列长度
|
||||||
|
@ -76,6 +81,16 @@ var (
|
||||||
renderChanLen = 500
|
renderChanLen = 500
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 用户标识的连接增删操作队列传输的值的结构
|
||||||
|
type userConnPoolChanItem struct {
|
||||||
|
userId int64 //必须(两个用户id任意一个不为0)
|
||||||
|
guestId int64 //必须(两个用户id任意一个不为0)
|
||||||
|
uniqueId string //主连接池唯一标识(添加/删除时候必须)
|
||||||
|
message []byte //消息(发送消息传的,格式是经过标准输出序列化后的数据)
|
||||||
|
messageType constants.Websocket //消息类型(发送消息传的)
|
||||||
|
option int64 //操作 2发消息 1增加 0删除
|
||||||
|
}
|
||||||
|
|
||||||
// 每个连接的连接基本属性
|
// 每个连接的连接基本属性
|
||||||
type wsConnectItem struct {
|
type wsConnectItem struct {
|
||||||
conn *websocket.Conn //websocket的连接(基本属性)
|
conn *websocket.Conn //websocket的连接(基本属性)
|
||||||
|
@ -133,6 +148,8 @@ func (l *DataTransferLogic) DataTransfer(w http.ResponseWriter, r *http.Request)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
//消费用户索引控制chan的数据
|
||||||
|
go consumeUserPoolData()
|
||||||
//循环读客户端信息
|
//循环读客户端信息
|
||||||
go ws.acceptBrowserMessage()
|
go ws.acceptBrowserMessage()
|
||||||
//消费出口数据并发送浏览器端
|
//消费出口数据并发送浏览器端
|
||||||
|
@ -176,6 +193,15 @@ func (l *DataTransferLogic) setConnPool(conn *websocket.Conn, userInfo *auth.Use
|
||||||
}
|
}
|
||||||
//保存连接
|
//保存连接
|
||||||
mapConnPool.Store(uniqueId, ws)
|
mapConnPool.Store(uniqueId, ws)
|
||||||
|
//非白板用户,需要为这个用户建立map索引便于通过用户查询
|
||||||
|
if userInfo.IsUser() || userInfo.IsGuest() {
|
||||||
|
createUserConnPoolElement(userConnPoolChanItem{
|
||||||
|
userId: userInfo.UserId,
|
||||||
|
guestId: userInfo.GuestId,
|
||||||
|
uniqueId: uniqueId,
|
||||||
|
option: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
if isFirefoxBrowser {
|
if isFirefoxBrowser {
|
||||||
time.Sleep(time.Second * 1) //兼容下火狐(直接发回去收不到第一条消息:有待研究)
|
time.Sleep(time.Second * 1) //兼容下火狐(直接发回去收不到第一条消息:有待研究)
|
||||||
}
|
}
|
||||||
|
@ -183,6 +209,101 @@ func (l *DataTransferLogic) setConnPool(conn *websocket.Conn, userInfo *auth.Use
|
||||||
return ws, nil
|
return ws, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加用户索引池ws连接
|
||||||
|
func createUserConnPoolElement(data userConnPoolChanItem) {
|
||||||
|
data.option = 1
|
||||||
|
select {
|
||||||
|
case mapUserConnPoolCtlChan <- data:
|
||||||
|
return
|
||||||
|
case <-time.After(time.Millisecond * 200):
|
||||||
|
logx.Error("向用户索引池中连接任务放入增加操作超时失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从用户索引池删除ws连接
|
||||||
|
func deleteUserConnPoolElement(data userConnPoolChanItem) {
|
||||||
|
data.option = 0
|
||||||
|
select {
|
||||||
|
case mapUserConnPoolCtlChan <- data:
|
||||||
|
return
|
||||||
|
case <-time.After(time.Millisecond * 200):
|
||||||
|
logx.Error("向用户索引池中连接任务放入删除操作超时失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据用户索引发现链接并发送消息到出口队列
|
||||||
|
func sendToOutChanByUserIndex(data userConnPoolChanItem) {
|
||||||
|
data.option = 0
|
||||||
|
select {
|
||||||
|
case mapUserConnPoolCtlChan <- data:
|
||||||
|
return
|
||||||
|
case <-time.After(time.Millisecond * 200):
|
||||||
|
logx.Error("通过用户索引找连接发送消息失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 消费用户索引池中的任务(单例)
|
||||||
|
var consumeUserPoolDataOnce sync.Once
|
||||||
|
|
||||||
|
func consumeUserPoolData() {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
logx.Error("consumeUserPoolData panic:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
consumeUserPoolDataOnce.Do(func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case data := <-mapUserConnPoolCtlChan:
|
||||||
|
key := getmapUserConnPoolUniqueId(data.userId, data.guestId)
|
||||||
|
switch data.option {
|
||||||
|
case 2: //发送消息
|
||||||
|
logx.Info("通过用户id索引发送消息:", data.uniqueId)
|
||||||
|
mapUserUniqueId, ok := mapUserConnPool[key]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, uniqueId := range mapUserUniqueId {
|
||||||
|
//根据uniqueId查询原始池中连接
|
||||||
|
mapConnPoolVal, ok := mapConnPool.Load(uniqueId)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
originConn, ok := mapConnPoolVal.(wsConnectItem)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
originConn.sendToOutChan(data.message)
|
||||||
|
}
|
||||||
|
case 1: //添加
|
||||||
|
logx.Info("添加用户id索引标识:", data.uniqueId)
|
||||||
|
if mapUserUniqueId, ok := mapUserConnPool[key]; ok {
|
||||||
|
mapUserUniqueId[data.uniqueId] = struct{}{}
|
||||||
|
} else {
|
||||||
|
mapUserConnPool[key] = make(map[string]struct{})
|
||||||
|
mapUserConnPool[key][data.uniqueId] = struct{}{}
|
||||||
|
}
|
||||||
|
case 0: //删除
|
||||||
|
logx.Info("删除用户id索引标识:", data.uniqueId)
|
||||||
|
if mapUserUniqueId, ok := mapUserConnPool[key]; ok {
|
||||||
|
delete(mapUserUniqueId, data.uniqueId)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取mapUserConnPool唯一id
|
||||||
|
func getmapUserConnPoolUniqueId(userId, guestId int64) (uniqueId string) {
|
||||||
|
return fmt.Sprintf("%d_%d", userId, guestId)
|
||||||
|
}
|
||||||
|
|
||||||
// 获取唯一id
|
// 获取唯一id
|
||||||
func (l *DataTransferLogic) getUniqueId(userInfo *auth.UserInfo, userAgent string, retryTimes int) (uniqueId string, err error) {
|
func (l *DataTransferLogic) getUniqueId(userInfo *auth.UserInfo, userAgent string, retryTimes int) (uniqueId string, err error) {
|
||||||
if retryTimes < 0 {
|
if retryTimes < 0 {
|
||||||
|
@ -236,7 +357,7 @@ func (l *DataTransferLogic) unAuthResponse(conn *websocket.Conn, isFirefoxBrowse
|
||||||
func (l *DataTransferLogic) sendGetUniqueIdErrResponse(conn *websocket.Conn) {
|
func (l *DataTransferLogic) sendGetUniqueIdErrResponse(conn *websocket.Conn) {
|
||||||
time.Sleep(time.Second * 1) //兼容下火狐(直接发回去收不到第一条消息:有待研究)
|
time.Sleep(time.Second * 1) //兼容下火狐(直接发回去收不到第一条消息:有待研究)
|
||||||
rsp := websocket_data.DataTransferData{
|
rsp := websocket_data.DataTransferData{
|
||||||
T: constants.WEBSOCKET_GEN_UNIQUE_ID_ERR,
|
T: constants.WEBSOCKET_CONNECT_ERR,
|
||||||
D: "err to gen unique id ",
|
D: "err to gen unique id ",
|
||||||
}
|
}
|
||||||
b, _ := json.Marshal(rsp)
|
b, _ := json.Marshal(rsp)
|
||||||
|
@ -276,6 +397,13 @@ func (w *wsConnectItem) close() {
|
||||||
if !w.isClose {
|
if !w.isClose {
|
||||||
w.isClose = true
|
w.isClose = true
|
||||||
close(w.closeChan)
|
close(w.closeChan)
|
||||||
|
//删除用户级索引
|
||||||
|
deleteUserConnPoolElement(userConnPoolChanItem{
|
||||||
|
userId: w.userId,
|
||||||
|
guestId: w.guestId,
|
||||||
|
uniqueId: w.uniqueId,
|
||||||
|
option: 0,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
logx.Info("###websocket:", w.uniqueId, " uid:", w.userId, " gid:", w.guestId, " is closed")
|
logx.Info("###websocket:", w.uniqueId, " uid:", w.userId, " gid:", w.guestId, " is closed")
|
||||||
}
|
}
|
||||||
|
@ -284,7 +412,7 @@ func (w *wsConnectItem) close() {
|
||||||
func (w *wsConnectItem) consumeOutChanData() {
|
func (w *wsConnectItem) consumeOutChanData() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
logx.Error("write loop panic:", err)
|
logx.Error("consumeOutChanData panic:", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
|
@ -305,7 +433,7 @@ func (w *wsConnectItem) consumeOutChanData() {
|
||||||
func (w *wsConnectItem) consumeInChanData() {
|
func (w *wsConnectItem) consumeInChanData() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
logx.Error("send loop panic:", err)
|
logx.Error("consumeInChanData:", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
|
@ -323,7 +451,7 @@ func (w *wsConnectItem) consumeInChanData() {
|
||||||
func (w *wsConnectItem) acceptBrowserMessage() {
|
func (w *wsConnectItem) acceptBrowserMessage() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
logx.Error("read loop panic:", err)
|
logx.Error("acceptBrowserMessage panic:", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user