长连接接口增加玩家信息绑定
This commit is contained in:
31
cmd/make.go
31
cmd/make.go
@@ -26,7 +26,8 @@ var (
|
|||||||
},
|
},
|
||||||
Examples: "make -m act -i 1: 创建活动1的接口与服务文件 \n" +
|
Examples: "make -m act -i 1: 创建活动1的接口与服务文件 \n" +
|
||||||
"make -m logic -n test: 创建test的服务文件 \n" +
|
"make -m logic -n test: 创建test的服务文件 \n" +
|
||||||
"make -m config -n test: 创建配置文件",
|
"make -m config -n test: 创建配置文件 \n" +
|
||||||
|
"make -m socket -n test: 创建socket文件 \n",
|
||||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||||
|
|
||||||
//g.Dump(parser.GetOptAll(), parser.GetArgAll())
|
//g.Dump(parser.GetOptAll(), parser.GetArgAll())
|
||||||
@@ -53,6 +54,12 @@ var (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = this.Config(name)
|
err = this.Config(name)
|
||||||
|
case "socket":
|
||||||
|
var name = parser.GetOpt("name").String()
|
||||||
|
if name == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = this.Socket(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -116,3 +123,25 @@ func (c *cMake) Config(name string) (err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *cMake) Socket(name string) (err error) {
|
||||||
|
var filePath = fmt.Sprintf("internal/socket/%s/%s_new.go", name, gstr.CaseSnake(name))
|
||||||
|
//生成文件不覆盖
|
||||||
|
if !gfile.Exists(filePath) {
|
||||||
|
// 生成目录文件
|
||||||
|
get, _ := fs.ReadFile(ConfigFiles, "make/socket")
|
||||||
|
fileStr := string(get)
|
||||||
|
fileStr = gstr.Replace(fileStr, "{name}", name)
|
||||||
|
err = gfile.PutContents(filePath, fileStr)
|
||||||
|
|
||||||
|
//生成方法文件
|
||||||
|
var filePath2 = fmt.Sprintf("internal/socket/%s/%s.go", name, gstr.CaseSnake(name))
|
||||||
|
get, _ = fs.ReadFile(ConfigFiles, "make/socket2")
|
||||||
|
fileStr = string(get)
|
||||||
|
fileStr = gstr.Replace(fileStr, "{name}", name)
|
||||||
|
fileStr = gstr.Replace(fileStr, "{func}", gstr.CaseCamel(name))
|
||||||
|
err = gfile.PutContents(filePath2, fileStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
10
cmd/make/socket
Normal file
10
cmd/make/socket
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package {name}
|
||||||
|
|
||||||
|
type {name} struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *{name} {
|
||||||
|
return &{name}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {}
|
||||||
19
cmd/make/socket2
Normal file
19
cmd/make/socket2
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package {name}
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ayflying/utility_go/pkg"
|
||||||
|
"github.com/ayflying/utility_go/pkg/websocket"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *{name}) {func}Handler(conn *websocket.WebsocketData, req any) (err error) {
|
||||||
|
var data = &v1.{func}2S{}
|
||||||
|
err = proto.Unmarshal(req.([]byte), data)
|
||||||
|
|
||||||
|
var res = &v1.{func}2C{}
|
||||||
|
|
||||||
|
resp, err := proto.Marshal(res)
|
||||||
|
pkg.Websocket().Send(000000, conn.Uid, resp)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,14 +1,24 @@
|
|||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
|
import "google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
// 定义一个处理方法的类型
|
// 定义一个处理方法的类型
|
||||||
type Handler func(conn *WebsocketData, req any) (err error)
|
type Handler func(conn *WebsocketData, req any) (err error)
|
||||||
type OnConnectHandler func(conn *WebsocketData)
|
type Handler2 func(conn *WebsocketData)
|
||||||
|
|
||||||
|
type HandlerMessage func(conn *WebsocketData, req any)
|
||||||
|
|
||||||
|
type PbType func(code int32, data []byte) proto.Message
|
||||||
|
type PbType2 func(data []byte) (int, []byte)
|
||||||
|
|
||||||
// 路由器的处理映射
|
// 路由器的处理映射
|
||||||
var (
|
var (
|
||||||
handlers = make(map[int]Handler)
|
handlers = make(map[int]Handler)
|
||||||
OnConnectHandlers = make([]OnConnectHandler, 0)
|
OnConnectHandlers = make([]Handler2, 0)
|
||||||
OnCloseHandlers = make([]OnConnectHandler, 0)
|
OnCloseHandlers = make([]Handler2, 0)
|
||||||
|
onMessageHandlers = make([]HandlerMessage, 0)
|
||||||
|
Byte2Pb = make([]PbType, 0)
|
||||||
|
Pb2Bytes = make([]PbType2, 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 注册方法,将某个消息路由器ID和对应的处理方法关联起来
|
// 注册方法,将某个消息路由器ID和对应的处理方法关联起来
|
||||||
@@ -17,10 +27,23 @@ func (s *SocketV1) RegisterRouter(cmd int, handler Handler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//注册方法,讲长连接登陆方法进行注册
|
//注册方法,讲长连接登陆方法进行注册
|
||||||
func (s *SocketV1) RegisterOnConnect(_func OnConnectHandler) {
|
func (s *SocketV1) RegisterOnConnect(_func Handler2) {
|
||||||
OnConnectHandlers = append(OnConnectHandlers, _func)
|
OnConnectHandlers = append(OnConnectHandlers, _func)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocketV1) RegisterOnClose(_func OnConnectHandler) {
|
func (s *SocketV1) RegisterOnClose(_func Handler2) {
|
||||||
OnCloseHandlers = append(OnCloseHandlers, _func)
|
OnCloseHandlers = append(OnCloseHandlers, _func)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//注册方法长连接消息体
|
||||||
|
func (s *SocketV1) RegisterMessage(_func HandlerMessage) {
|
||||||
|
onMessageHandlers = append(onMessageHandlers, _func)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocketV1) RegisterByte2Pb(_func PbType) {
|
||||||
|
Byte2Pb = append(Byte2Pb, _func)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocketV1) RegisterPb2Byte(_func PbType2) {
|
||||||
|
Pb2Bytes = append(Pb2Bytes, _func)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ package websocket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"github.com/gogf/gf/v2/container/gmap"
|
"github.com/gogf/gf/v2/container/gmap"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/net/ghttp"
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
"github.com/gogf/gf/v2/os/glog"
|
"github.com/gogf/gf/v2/os/glog"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/guid"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -22,19 +24,19 @@ var (
|
|||||||
//Conn map[uuid.UUID]*WebsocketData
|
//Conn map[uuid.UUID]*WebsocketData
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
|
|
||||||
m = gmap.New(true)
|
m = gmap.NewHashMap(true)
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebsocketData struct {
|
type WebsocketData struct {
|
||||||
Ws *websocket.Conn
|
Ws *websocket.Conn
|
||||||
Uuid uuid.UUID
|
Uuid string
|
||||||
Uid int64
|
Uid int64
|
||||||
Ctx context.Context
|
Ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewV1() *SocketV1 {
|
func NewV1() *SocketV1 {
|
||||||
return &SocketV1{
|
return &SocketV1{
|
||||||
Type: 1,
|
Type: 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,11 +79,9 @@ func (s *SocketV1) Load(serv *ghttp.Server, prefix string) {
|
|||||||
// @receiver s
|
// @receiver s
|
||||||
// @param conn
|
// @param conn
|
||||||
func (s *SocketV1) OnConnect(ctx context.Context, conn *websocket.Conn) {
|
func (s *SocketV1) OnConnect(ctx context.Context, conn *websocket.Conn) {
|
||||||
//lock.Lock()
|
|
||||||
//defer lock.Unlock()
|
|
||||||
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
id, _ := uuid.NewUUID()
|
id := guid.S()
|
||||||
ip := conn.RemoteAddr().String()
|
ip := conn.RemoteAddr().String()
|
||||||
data := &WebsocketData{
|
data := &WebsocketData{
|
||||||
Uuid: id,
|
Uuid: id,
|
||||||
@@ -103,8 +103,10 @@ func (s *SocketV1) OnConnect(ctx context.Context, conn *websocket.Conn) {
|
|||||||
for {
|
for {
|
||||||
//进入当前连接线程拥堵
|
//进入当前连接线程拥堵
|
||||||
msgType, msg, err := conn.ReadMessage()
|
msgType, msg, err := conn.ReadMessage()
|
||||||
|
s.Type = msgType
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//客户端断开返回错误,断开当前连接
|
//客户端断开返回错误,断开当前连接
|
||||||
|
//g.Log().Error(ctx, err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s.OnMessage(m.Get(id).(*WebsocketData), msg, msgType)
|
s.OnMessage(m.Get(id).(*WebsocketData), msg, msgType)
|
||||||
@@ -121,53 +123,142 @@ func (s *SocketV1) OnConnect(ctx context.Context, conn *websocket.Conn) {
|
|||||||
// @param msg
|
// @param msg
|
||||||
// @param msgType
|
// @param msgType
|
||||||
func (s *SocketV1) OnMessage(conn *WebsocketData, req []byte, msgType int) {
|
func (s *SocketV1) OnMessage(conn *WebsocketData, req []byte, msgType int) {
|
||||||
s.Type = msgType
|
s.Type = 2
|
||||||
//g.Log().Debugf(ctx, "收到消息:%v,type=%v,conn=%v", string(req), msgType, conn)
|
|
||||||
//s.Send(conn.Uuid, msg)
|
var cmd int
|
||||||
//s.SendAll(msg)
|
var msg []byte
|
||||||
|
//uid := conn.Uid
|
||||||
|
for _, v := range Pb2Bytes {
|
||||||
|
cmd, msg = v(req)
|
||||||
|
}
|
||||||
|
|
||||||
//msgStr := string(req)
|
//msgStr := string(req)
|
||||||
msg := req[8:]
|
//cmd = gconv.Int(msgStr[:8])
|
||||||
cmd := gconv.Int(req[:8])
|
//msg = []byte(msgStr[8:])
|
||||||
//GetRouter(cmd, conn.Uid, msg)
|
|
||||||
handler, exist := handlers[cmd]
|
handler, exist := handlers[cmd]
|
||||||
if exist {
|
if exist {
|
||||||
//匹配上路由器
|
//匹配上路由器
|
||||||
err := handler(conn, msg)
|
err := handler(conn, msg)
|
||||||
|
if err != nil {
|
||||||
g.Log().Error(conn.Ctx, err)
|
g.Log().Error(conn.Ctx, err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//fmt.Println("未注册的路由器ID:", cmd)
|
//fmt.Println("未注册的路由器ID:", cmd)
|
||||||
s.Send(conn.Uuid, []byte("未注册的协议号:"+strconv.Itoa(cmd)))
|
s.Send(20000000, conn.Uid, []byte("未注册的协议号:"+strconv.Itoa(cmd)))
|
||||||
s.OnClose(conn)
|
s.OnClose(conn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//绑定用户编号
|
||||||
|
func (s *SocketV1) BindUid(conn *WebsocketData, uid int64) {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
cacheKey := fmt.Sprintf("socket:uid:%d", uid)
|
||||||
|
g.Redis().Set(nil, cacheKey, conn.Uuid)
|
||||||
|
|
||||||
|
if conn.Uid == 0 {
|
||||||
|
conn.Uid = uid
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//解绑用户
|
||||||
|
func (s *SocketV1) UnBindUid(uid int64) {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
cacheKey := fmt.Sprintf("socket:uid:%d", uid)
|
||||||
|
g.Redis().Del(nil, cacheKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uid2Uuid 用户编号转uuid唯一标识
|
||||||
|
func (s *SocketV1) Uid2Uuid(uid int64) (uuid string) {
|
||||||
|
cacheKey := fmt.Sprintf("socket:uid:%d", uid)
|
||||||
|
get, _ := g.Redis().Get(nil, cacheKey)
|
||||||
|
if get.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uuid = get.String()
|
||||||
|
|
||||||
|
//如果不在线了
|
||||||
|
if !m.Contains(uuid) {
|
||||||
|
// 解绑用户编号
|
||||||
|
s.UnBindUid(uid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendUuid
|
||||||
|
//
|
||||||
|
// @Description:
|
||||||
|
// @receiver s
|
||||||
|
// @param uid
|
||||||
|
// @param data
|
||||||
|
func (s *SocketV1) SendUuid(code int32, id uuid.UUID, data []byte) {
|
||||||
|
if !m.Contains(id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := m.Get(id).(*WebsocketData)
|
||||||
|
|
||||||
|
//前置方法
|
||||||
|
|
||||||
|
for _, v := range Byte2Pb {
|
||||||
|
temp := v(code, data)
|
||||||
|
data, _ = proto.Marshal(temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.Ws.WriteMessage(s.Type, data)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Send
|
// Send
|
||||||
//
|
//
|
||||||
// @Description:
|
// @Description:
|
||||||
// @receiver s
|
// @receiver s
|
||||||
// @param uid
|
// @param uid
|
||||||
// @param data
|
// @param data
|
||||||
// @return err
|
func (s *SocketV1) Send(code int32, uid int64, data []byte) {
|
||||||
func (s *SocketV1) Send(id uuid.UUID, data []byte) (err error) {
|
uuid := s.Uid2Uuid(uid)
|
||||||
if !m.Contains(id) {
|
if uuid == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := m.Get(id).(*WebsocketData)
|
if !m.Contains(uuid) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := m.Get(uuid).(*WebsocketData)
|
||||||
|
|
||||||
|
//前置方法
|
||||||
|
|
||||||
|
for _, v := range Byte2Pb {
|
||||||
|
temp := v(code, data)
|
||||||
|
data, _ = proto.Marshal(temp)
|
||||||
|
}
|
||||||
conn.Ws.WriteMessage(s.Type, data)
|
conn.Ws.WriteMessage(s.Type, data)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量发送
|
// 批量发送
|
||||||
func (s *SocketV1) SendAll(data []byte) {
|
func (s *SocketV1) SendAll(code int32, data []byte) {
|
||||||
|
for _, v := range Byte2Pb {
|
||||||
|
temp := v(code, data)
|
||||||
|
data, _ = proto.Marshal(temp)
|
||||||
|
}
|
||||||
|
|
||||||
m.Iterator(func(k interface{}, v interface{}) bool {
|
m.Iterator(func(k interface{}, v interface{}) bool {
|
||||||
//fmt.Printf("%v:%v ", k, v)
|
|
||||||
conn := v.(*WebsocketData)
|
conn := v.(*WebsocketData)
|
||||||
conn.Ws.WriteMessage(s.Type, data)
|
conn.Ws.WriteMessage(s.Type, data)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -185,11 +276,14 @@ func (s *SocketV1) OnClose(conn *WebsocketData) {
|
|||||||
for _, connect := range OnCloseHandlers {
|
for _, connect := range OnCloseHandlers {
|
||||||
connect(conn)
|
connect(conn)
|
||||||
}
|
}
|
||||||
|
uid := conn.Uid
|
||||||
// 可能的后续操作:
|
// 可能的后续操作:
|
||||||
// 1. 更新连接状态或从连接池移除
|
// 1. 更新连接状态或从连接池移除
|
||||||
// 2. 发送通知或清理关联资源
|
// 2. 发送通知或清理关联资源
|
||||||
// 3. 执行特定于业务的断开处理
|
// 3. 执行特定于业务的断开处理
|
||||||
m.Remove(conn.Uuid)
|
m.Remove(conn.Uuid)
|
||||||
|
if uid > 0 {
|
||||||
|
s.UnBindUid(uid)
|
||||||
|
}
|
||||||
conn.Ws.Close()
|
conn.Ws.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user