This commit is contained in:
2026-01-18 18:20:40 +08:00
commit 20ed44aa74
178 changed files with 13789 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
package controller
import (
"leke/internal/controller/containment"
"leke/internal/controller/department"
"leke/internal/controller/forum"
"leke/internal/controller/login"
"leke/internal/controller/room"
"leke/internal/controller/user"
"leke/internal/middleware"
"github.com/gogf/gf/v2/net/ghttp"
)
// RegisterControllers 将所有控制器绑定到路由组
func RegisterControllers(group *ghttp.RouterGroup) {
// 登录相关接口不需要JWT验证
group.Group("/", func(g *ghttp.RouterGroup) {
g.Bind(
login.NewV1(),
)
})
// 其他需要JWT验证的接口
group.Group("/", func(g *ghttp.RouterGroup) {
g.Middleware(middleware.JWTAuth)
g.Bind(
user.NewV1(),
user.NewRoleV1(),
department.NewV1(),
containment.NewV1(),
room.NewV1(),
forum.NewV1(),
)
})
}

View File

@@ -0,0 +1,72 @@
package containment
import (
"context"
"leke/api/containment"
"leke/api/containment/v1"
"leke/internal/service"
)
// ControllerV1 控制器结构体
type ControllerV1 struct{}
// NewV1 创建一个新的v1版本控制器实例
//
// 返回:
// - containment.IContainmentV1: v1版本控制器接口实现
func NewV1() containment.IContainmentV1 {
return &ControllerV1{}
}
// ContainmentRepoList 获取收容库列表
//
// 参数:
// - ctx context.Context: 上下文信息
// - req *v1.ContainmentRepoListReq: 收容库列表请求参数
//
// 返回:
// - res *v1.ContainmentRepoListRes: 收容库列表响应结果
// - err error: 错误信息
func (c *ControllerV1) ContainmentRepoList(ctx context.Context, req *v1.ContainmentRepoListReq) (res *v1.ContainmentRepoListRes, err error) {
return service.Containment().ContainmentRepoList(ctx, req)
}
// ContainmentRepoView 查看收容库详情
//
// 参数:
// - ctx context.Context: 上下文信息
// - req *v1.ContainmentRepoViewReq: 收容库详情请求参数
//
// 返回:
// - res *v1.ContainmentRepoViewRes: 收容库详情响应结果
// - err error: 错误信息
func (c *ControllerV1) ContainmentRepoView(ctx context.Context, req *v1.ContainmentRepoViewReq) (res *v1.ContainmentRepoViewRes, err error) {
return service.Containment().ContainmentRepoView(ctx, req)
}
// ContainmentRepoUpdate 更新收容库信息
//
// 参数:
// - ctx context.Context: 上下文信息
// - req *v1.ContainmentRepoUpdateReq: 收容库更新请求参数
//
// 返回:
// - res *v1.ContainmentRepoUpdateRes: 收容库更新响应结果
// - err error: 错误信息
func (c *ControllerV1) ContainmentRepoUpdate(ctx context.Context, req *v1.ContainmentRepoUpdateReq) (res *v1.ContainmentRepoUpdateRes, err error) {
return service.Containment().ContainmentRepoUpdate(ctx, req)
}
// ContainmentRepoDelete 删除收容库
//
// 参数:
// - ctx context.Context: 上下文信息
// - req *v1.ContainmentRepoDeleteReq: 收容库删除请求参数
//
// 返回:
// - res *v1.ContainmentRepoDeleteRes: 收容库删除响应结果
// - err error: 错误信息
func (c *ControllerV1) ContainmentRepoDelete(ctx context.Context, req *v1.ContainmentRepoDeleteReq) (res *v1.ContainmentRepoDeleteRes, err error) {
return service.Containment().ContainmentRepoDelete(ctx, req)
}

View File

@@ -0,0 +1,35 @@
package department
import (
"context"
"leke/api/department"
v1 "leke/api/department/v1"
"leke/internal/service"
)
type ControllerV1 struct{}
func NewV1() department.IDepartmentV1 {
return &ControllerV1{}
}
func (c *ControllerV1) DepartmentList(ctx context.Context, req *v1.DepartmentListReq) (res *v1.DepartmentListRes, err error) {
return service.Department().DepartmentList(ctx, req)
}
func (c *ControllerV1) DepartmentView(ctx context.Context, req *v1.DepartmentViewReq) (res *v1.DepartmentViewRes, err error) {
return service.Department().DepartmentView(ctx, req)
}
func (c *ControllerV1) DepartmentCreate(ctx context.Context, req *v1.DepartmentCreateReq) (res *v1.DepartmentCreateRes, err error) {
return service.Department().DepartmentCreate(ctx, req)
}
func (c *ControllerV1) DepartmentUpdate(ctx context.Context, req *v1.DepartmentUpdateReq) (res *v1.DepartmentUpdateRes, err error) {
return service.Department().DepartmentUpdate(ctx, req)
}
func (c *ControllerV1) DepartmentDelete(ctx context.Context, req *v1.DepartmentDeleteReq) (res *v1.DepartmentDeleteRes, err error) {
return service.Department().DepartmentDelete(ctx, req)
}

View File

@@ -0,0 +1,32 @@
package forum
import (
"context"
v1 "leke/api/forum/v1"
"leke/internal/service"
)
// ForumCommentsCreate 创建评论
func (c *ControllerV1) ForumCommentsCreate(ctx context.Context, req *v1.ForumCommentsCreateReq) (res *v1.ForumCommentsCreateRes, err error) {
return service.ForumComments().Create(ctx, req)
}
// ForumCommentsUpdate 更新评论
func (c *ControllerV1) ForumCommentsUpdate(ctx context.Context, req *v1.ForumCommentsUpdateReq) (res *v1.ForumCommentsUpdateRes, err error) {
return service.ForumComments().Update(ctx, req)
}
// ForumCommentsDelete 删除评论
func (c *ControllerV1) ForumCommentsDelete(ctx context.Context, req *v1.ForumCommentsDeleteReq) (res *v1.ForumCommentsDeleteRes, err error) {
return service.ForumComments().Delete(ctx, req)
}
// ForumCommentsView 查看评论详情
func (c *ControllerV1) ForumCommentsView(ctx context.Context, req *v1.ForumCommentsViewReq) (res *v1.ForumCommentsViewRes, err error) {
return service.ForumComments().View(ctx, req)
}
// ForumCommentsList 获取评论列表
func (c *ControllerV1) ForumCommentsList(ctx context.Context, req *v1.ForumCommentsListReq) (res *v1.ForumCommentsListRes, err error) {
return service.ForumComments().List(ctx, req)
}

View File

@@ -0,0 +1,38 @@
package forum
import (
"context"
v1 "leke/api/forum/v1"
"leke/internal/service"
)
type ControllerV1 struct{}
func NewV1() *ControllerV1 {
return &ControllerV1{}
}
// ForumPostsCreate 创建帖子
func (c *ControllerV1) Create(ctx context.Context, req *v1.ForumPostsCreateReq) (res *v1.ForumPostsCreateRes, err error) {
return service.ForumPosts().Create(ctx, req)
}
// ForumPostsUpdate 更新帖子
func (c *ControllerV1) Update(ctx context.Context, req *v1.ForumPostsUpdateReq) (res *v1.ForumPostsUpdateRes, err error) {
return service.ForumPosts().Update(ctx, req)
}
// ForumPostsDelete 删除帖子
func (c *ControllerV1) Delete(ctx context.Context, req *v1.ForumPostsDeleteReq) (res *v1.ForumPostsDeleteRes, err error) {
return service.ForumPosts().Delete(ctx, req)
}
// ForumPostsView 查看帖子详情
func (c *ControllerV1) View(ctx context.Context, req *v1.ForumPostsViewReq) (res *v1.ForumPostsViewRes, err error) {
return service.ForumPosts().View(ctx, req)
}
// ForumPostsList 获取帖子列表
func (c *ControllerV1) List(ctx context.Context, req *v1.ForumPostsListReq) (res *v1.ForumPostsListRes, err error) {
return service.ForumPosts().List(ctx, req)
}

View File

@@ -0,0 +1,60 @@
// internal/controller/login/login_v1_login.go
package login
import (
"context"
"leke/api/login"
v1 "leke/api/login/v1"
"leke/internal/service"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
)
type ControllerV1 struct{}
func NewV1() login.ILoginV1 {
return &ControllerV1{}
}
// Login 登录接口
func (c *ControllerV1) Login(ctx context.Context, req *v1.LoginReq) (res *v1.LoginRes, err error) {
res, err = service.Login().Login(ctx, req)
if err != nil {
return nil, err
}
res = &v1.LoginRes{
Token: res.Token,
Account: res.Account,
}
return res, nil
}
func (c *ControllerV1) Register(ctx context.Context, req *v1.RegisterReq) (res *v1.RegisterRes, err error) {
_, err = service.Login().Register(ctx, req)
if err != nil {
return nil, err
}
return &v1.RegisterRes{
Account: req.Account,
}, nil
}
func (c *ControllerV1) Logout(ctx context.Context, req *v1.LogoutReq) (res *v1.LogoutRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}
// 通过邮箱注册
func (c *ControllerV1) RegisterByEmail(ctx context.Context, req *v1.RegisterByEmailReq) (res *v1.RegisterByEmailRes, err error) {
return service.Login().RegisterByEmail(ctx, req)
}
// 通过邮箱登录
func (c *ControllerV1) LoginByEmail(ctx context.Context, req *v1.LoginByEmailReq) (res *v1.LoginByEmailRes, err error) {
return service.Login().LoginByEmail(ctx, req)
}
// 发送验证码
func (c *ControllerV1) SendVerificationCode(ctx context.Context, req *v1.SendVerificationCodeReq) (res *v1.SendVerificationCodeRes, err error) {
return service.Login().SendVerificationCode(ctx, req)
}

View File

@@ -0,0 +1,35 @@
package room
import (
"context"
"leke/api/room"
v1 "leke/api/room/v1"
"leke/internal/service"
)
type ControllerV1 struct{}
func NewV1() room.IRoomV1 {
return &ControllerV1{}
}
func (c *ControllerV1) RoomList(ctx context.Context, req *v1.RoomListReq) (res *v1.RoomListRes, err error) {
return service.Room().RoomList(ctx, req)
}
func (c *ControllerV1) RoomView(ctx context.Context, req *v1.RoomViewReq) (res *v1.RoomViewRes, err error) {
return service.Room().RoomView(ctx, req)
}
func (c *ControllerV1) RoomUpdate(ctx context.Context, req *v1.RoomUpdateReq) (res *v1.RoomUpdateRes, err error) {
return service.Room().RoomUpdate(ctx, req)
}
func (c *ControllerV1) RoomDelete(ctx context.Context, req *v1.RoomDeleteReq) (res *v1.RoomDeleteRes, err error) {
return service.Room().RoomDelete(ctx, req)
}
func (c *ControllerV1) RoomCreate(ctx context.Context, req *v1.RoomCreateReq) (res *v1.RoomCreateRes, err error) {
return service.Room().RoomCreate(ctx, req)
}
func (c *ControllerV1) RoomJoin(ctx context.Context, req *v1.RoomJoinReq) (res *v1.RoomJoinRes, err error) {
return service.Room().RoomJoin(ctx, req)
}

View File

@@ -0,0 +1,37 @@
package user
import (
"context"
v1 "leke/api/user/v1"
"leke/internal/service"
)
type RoleControllerV1 struct{}
func NewRoleV1() *RoleControllerV1 {
return &RoleControllerV1{}
}
func (c *RoleControllerV1) RoleCreate(ctx context.Context, req *v1.RoleCreateReq) (res *v1.RoleCreateRes, err error) {
return service.User().RoleCreate(ctx, req)
}
func (c *RoleControllerV1) RoleUpdate(ctx context.Context, req *v1.RoleUpdateReq) (res *v1.RoleUpdateRes, err error) {
return service.User().RoleUpdate(ctx, req)
}
func (c *RoleControllerV1) RoleView(ctx context.Context, req *v1.RoleViewReq) (res *v1.RoleViewRes, err error) {
return service.User().RoleView(ctx, req)
}
func (c *RoleControllerV1) RoleList(ctx context.Context, req *v1.RoleListReq) (res *v1.RoleListRes, err error) {
return service.User().RoleList(ctx, req)
}
func (c *RoleControllerV1) RoleDelete(ctx context.Context, req *v1.RoleDeleteReq) (res *v1.RoleDeleteRes, err error) {
return service.User().RoleDelete(ctx, req)
} // RolePermissionCheck 权限查询
func (c *RoleControllerV1) RolePermissionCheck(ctx context.Context, req *v1.RolePermissionCheckReq) (res *v1.RolePermissionCheckRes, err error) {
return service.User().RolePermissionCheck(ctx, req)
}

View File

@@ -0,0 +1,86 @@
package user
import (
"context"
v1 "leke/api/user/v1"
"leke/internal/service"
)
type ControllerV1 struct{}
func NewV1() *ControllerV1 {
return &ControllerV1{}
}
func (c *ControllerV1) UserList(ctx context.Context, req *v1.UserListReq) (res *v1.UserListRes, err error) {
return service.User().UserList(ctx, req)
}
func (c *ControllerV1) UserView(ctx context.Context, req *v1.UserViewReq) (res *v1.UserViewRes, err error) {
return service.User().UserView(ctx, req)
}
func (c *ControllerV1) UserUpdate(ctx context.Context, req *v1.UserUpdateReq) (res *v1.UserUpdateRes, err error) {
return service.User().UserUpdate(ctx, req)
}
func (c *ControllerV1) UserDelete(ctx context.Context, req *v1.UserDeleteReq) (res *v1.UserDeleteRes, err error) {
return service.User().UserDelete(ctx, req)
}
// Fans 相关方法
func (c *ControllerV1) FansList(ctx context.Context, req *v1.FansListReq) (res *v1.FansListRes, err error) {
return service.Fans().FansList(ctx, req)
}
func (c *ControllerV1) FansView(ctx context.Context, req *v1.FansViewReq) (res *v1.FansViewRes, err error) {
return service.Fans().FansView(ctx, req)
}
func (c *ControllerV1) FansUpdate(ctx context.Context, req *v1.FansUpdateReq) (res *v1.FansUpdateRes, err error) {
return service.Fans().FansUpdate(ctx, req)
}
func (c *ControllerV1) FansDelete(ctx context.Context, req *v1.FansDeleteReq) (res *v1.FansDeleteRes, err error) {
return service.Fans().FansDelete(ctx, req)
}
func (c *ControllerV1) FansCreate(ctx context.Context, req *v1.FansCreateReq) (res *v1.FansCreateRes, err error) {
return service.Fans().FansCreate(ctx, req)
}
// Subscribe 相关方法
func (c *ControllerV1) SubscribeList(ctx context.Context, req *v1.SubscribeListReq) (res *v1.SubscribeListRes, err error) {
return service.Subscribe().SubscribeList(ctx, req)
}
func (c *ControllerV1) SubscribeView(ctx context.Context, req *v1.SubscribeViewReq) (res *v1.SubscribeViewRes, err error) {
return service.Subscribe().SubscribeView(ctx, req)
}
func (c *ControllerV1) SubscribeUpdate(ctx context.Context, req *v1.SubscribeUpdateReq) (res *v1.SubscribeUpdateRes, err error) {
return service.Subscribe().SubscribeUpdate(ctx, req)
}
func (c *ControllerV1) SubscribeDelete(ctx context.Context, req *v1.SubscribeDeleteReq) (res *v1.SubscribeDeleteRes, err error) {
return service.Subscribe().SubscribeDelete(ctx, req)
}
func (c *ControllerV1) SubscribeCreate(ctx context.Context, req *v1.SubscribeCreateReq) (res *v1.SubscribeCreateRes, err error) {
return service.Subscribe().SubscribeCreate(ctx, req)
}
// Trace 相关方法
func (c *ControllerV1) TraceList(ctx context.Context, req *v1.TraceListReq) (res *v1.TraceListRes, err error) {
return service.Trace().TraceList(ctx, req)
}
func (c *ControllerV1) TraceView(ctx context.Context, req *v1.TraceViewReq) (res *v1.TraceViewRes, err error) {
return service.Trace().TraceView(ctx, req)
}
func (c *ControllerV1) TraceUpdate(ctx context.Context, req *v1.TraceUpdateReq) (res *v1.TraceUpdateRes, err error) {
return service.Trace().TraceUpdate(ctx, req)
}
func (c *ControllerV1) TraceReduce(ctx context.Context, req *v1.TraceReduceReq) (res *v1.TraceReduceRes, err error) {
return service.Trace().TraceReduce(ctx, req)
}

View File

@@ -0,0 +1,119 @@
package websocket
import (
"log"
"net/http"
"sync"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gorilla/websocket"
)
type ChatMessage struct {
RoomId string `json:"roomId"`
UserId string `json:"userId"`
Message string `json:"message"`
Type string `json:"type"`
}
var upgrader = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
var clients = make(map[*websocket.Conn]bool)
var roomClients = make(map[string]map[*websocket.Conn]bool)
var broadcast = make(chan ChatMessage, 256)
var mutex = sync.RWMutex{}
var once sync.Once
func HandleChatConnections(r *ghttp.Request) {
once.Do(func() {
go handleBroadcast()
})
ws, err := upgrader.Upgrade(r.Response.Writer, r.Request, nil)
if err != nil {
log.Printf("upgrade error: %v", err)
return
}
mutex.Lock()
clients[ws] = true
mutex.Unlock()
defer func() {
mutex.Lock()
delete(clients, ws)
for roomId, members := range roomClients {
if _, ok := members[ws]; ok {
delete(members, ws)
if len(members) == 0 {
delete(roomClients, roomId)
}
}
}
mutex.Unlock()
ws.Close()
}()
for {
var msg ChatMessage
err := ws.ReadJSON(&msg)
if err != nil {
log.Printf("read error: %v", err)
break
}
switch msg.Type {
case "join":
mutex.Lock()
members, ok := roomClients[msg.RoomId]
if !ok {
members = make(map[*websocket.Conn]bool)
roomClients[msg.RoomId] = members
}
members[ws] = true
mutex.Unlock()
case "leave":
mutex.Lock()
if members, ok := roomClients[msg.RoomId]; ok {
delete(members, ws)
if len(members) == 0 {
delete(roomClients, msg.RoomId)
}
}
mutex.Unlock()
}
select {
case broadcast <- msg:
default:
log.Printf("broadcast channel full, dropping message")
}
}
}
func handleBroadcast() {
for {
msg := <-broadcast
mutex.RLock()
members, ok := roomClients[msg.RoomId]
if !ok {
mutex.RUnlock()
continue
}
for client := range members {
err := client.WriteJSON(msg)
if err != nil {
log.Printf("write error: %v", err)
client.Close()
mutex.RUnlock()
mutex.Lock()
delete(members, client)
if len(members) == 0 {
delete(roomClients, msg.RoomId)
}
mutex.Unlock()
mutex.RLock()
}
}
mutex.RUnlock()
}
}

View File

@@ -0,0 +1,65 @@
package websocket
//
//import (
// "net/http"
//
// "github.com/gogf/gf/v2/frame/g"
// "github.com/gogf/gf/v2/net/ghttp"
// "github.com/gorilla/websocket"
//)
//
//// WebSocketController WebSocket 控制器
//type WebSocketController struct{}
//
//// New 创建 WebSocket 控制器实例
//func New() *WebSocketController {
// return &WebSocketController{}
//}
//
//// wsUpgrader WebSocket 升级器配置
//var wsUpgrader = websocket.Upgrader{
// // CheckOrigin 允许任何来源(开发环境)
// // 生产环境中应该实现适当的来源检查以确保安全
// CheckOrigin: func(r *http.Request) bool {
// return true
// },
// // Error 处理升级失败的错误
// Error: func(w http.ResponseWriter, r *http.Request, status int, reason error) {
// // 在这里实现错误处理逻辑
// g.Log().Errorf(r.Context(), "WebSocket upgrade error: %v", reason)
// },
//}
//
//// Echo WebSocket Echo 服务器处理器
//// 路径: /ws
//func (c *WebSocketController) Echo(r *ghttp.Request) {
// // 将 HTTP 连接升级为 WebSocket
// ws, err := wsUpgrader.Upgrade(r.Response.Writer, r.Request, nil)
// if err != nil {
// r.Response.Write(err.Error())
// return
// }
// defer ws.Close()
//
// // 获取请求上下文用于日志记录
// var ctx = r.Context()
// logger := g.Log()
//
// // 消息处理循环
// for {
// // 读取传入的 WebSocket 消息
// msgType, msg, err := ws.ReadMessage()
// if err != nil {
// break // 连接关闭或发生错误
// }
// // 记录接收到的消息
// logger.Infof(ctx, "received message: %s", msg)
// // 将消息回显给客户端
// if err = ws.WriteMessage(msgType, msg); err != nil {
// break // 写入消息时出错
// }
// }
// // 记录连接关闭
// logger.Info(ctx, "websocket connection closed")
//}

View File

@@ -0,0 +1,88 @@
package websocket
//
//import (
// "log"
// "net/http"
// "sync"
//
// "github.com/gogf/gf/v2/net/ghttp"
// "github.com/gorilla/websocket"
//)
//
//// 定义 WebSocket 升级器
//var upgrader = websocket.Upgrader{
// CheckOrigin: func(r *http.Request) bool {
// return true
// },
//}
//
//// 存储客户端连接
//var (
// clients = make(map[*websocket.Conn]bool)
// clientsMu sync.Mutex // 保护 clients map 的互斥锁
// broadcast = make(chan string, 256) // 广播信息通道,带缓冲
//)
//
//// 初始化广播处理(只启动一次)
//var once sync.Once
//
//// HandlerConnection 处理websocket连接
//func HandlerConnectionV1(r *ghttp.Request) {
// // 启动广播处理 goroutine只启动一次
// once.Do(func() {
// go handleBroadcast()
// })
//
// ws, err := upgrader.Upgrade(r.Response.Writer, r.Request, nil)
// if err != nil {
// log.Printf("upgrade error: %v", err)
// return
// }
// defer func() {
// clientsMu.Lock()
// delete(clients, ws)
// clientsMu.Unlock()
// ws.Close()
// }()
//
// // 注册新客户端
// clientsMu.Lock()
// clients[ws] = true
// clientsMu.Unlock()
//
// for {
// var message string
// err := ws.ReadJSON(&message)
// if err != nil {
// log.Printf("read error: %v", err)
// clientsMu.Lock()
// delete(clients, ws)
// clientsMu.Unlock()
// break
// }
// // 将消息发送到广播通道
// select {
// case broadcast <- message:
// default:
// log.Printf("broadcast channel full, dropping message")
// }
// }
//}
//
//// 将广播通道给所有的用户
//func handleBroadcast() {
// for {
// message := <-broadcast
// clientsMu.Lock()
// for client := range clients {
// err := client.WriteJSON(message)
// if err != nil {
// log.Printf("write error: %v", err)
// client.Close()
// delete(clients, client)
// }
// }
// clientsMu.Unlock()
// }
//}

View File

@@ -0,0 +1,66 @@
package websocket
//
//import (
// "github.com/gorilla/websocket"
// "log"
// "net/http"
// "sync"
//)
//
//var upgraderv2 = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
//var clientsV2 = make(map[*websocket.Conn]bool) //
//var mutex = sync.RWMutex{} // 读写锁 // 保护 clientsV2 并发访问
//
////var bufferPool = sync.Pool{
//// New: func() interface{} {
//// return make([]byte, 1024)
//// },
////}
//
//var bufferPool = sync.Pool{
// New: func() interface{} {
// return make([]byte, 1024)
// },
//}
//
//func readMessage(ws *websocket.Conn) ([]byte, error) {
// buf := bufferPool.Get().([]byte)
// defer bufferPool.Put(buf)
// _, data, err := ws.ReadMessage()
// return data, err
//}
//
//func HandlerConnectionV2(w http.ResponseWriter, r *http.Request) {
// ws, err := upgraderv2.Upgrade(w, r, nil)
// if err != nil {
// log.Printf("upgrade error: %v", err)
// return
// }
// // 注册客户端
// mutex.Lock()
// clientsV2[ws] = true
// mutex.Unlock()
//
// defer func() {
// mutex.Lock()
// delete(clientsV2, ws)
// mutex.Unlock()
// ws.Close()
// }()
//
// for {
// var message string
// err := ws.ReadJSON(&message)
// if err != nil {
// log.Printf("read json error: %v", err)
// return
// }
// // 广播消息(简化示例)
// mutex.RLock()
// for client := range clientsV2 {
// client.WriteJSON(message)
// }
// mutex.RUnlock()
// }
//}