/**
保持心跳
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func wsping() error {
for {
time.Sleep(time.Duration(HandshakeTimeout) * time.Second)
WsSendToAll(Message{Type: "ping", Message: Now()})
}
return nil
}
/**
初始化连接
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func ConnectInit(ws *websocket.Conn) string {
client := clientOne{Send: make(chan Message)}
client.Conn = ws
client_id := fmt.Sprintf("%p", unsafe.Pointer(ws))
clientsList.Set(client_id, client)
go readMsg(&client)
go writeMsg(&client)
Msg <- Message{Clientid: client_id, Type: "join", Message: "用户加入"}
return client_id
}
/**
在client通道发送消息
*/
func writeMsg(client *clientOne) {
client_id := fmt.Sprintf("%p", unsafe.Pointer(client.Conn))
defer func() {
//取出该clien_id绑定的group和uid
message := map[string]interface{}{"uid": WsGetUidByClientId(client_id), "group": WsGetGroupCountByClientId(client_id)}
Msg <- Message{Clientid: client_id, Type: "level", Message: JsonEncode(message)}
client.Conn.Close()
close(client_id)
err := recover()
if err != nil {
fmt.Println(err)
}
}()
for {
select {
case data := <-client.Send:
err := client.Conn.WriteJSON(data)
if err != nil {
break
}
}
}
}
/**
在client通道读取消息
*/
func readMsg(client *clientOne) {
client_id := fmt.Sprintf("%p", unsafe.Pointer(client.Conn))
defer func() {
//取出该clien_id绑定的group和uid
message := map[string]interface{}{"uid": WsGetUidByClientId(client_id), "group": WsGetGroupCountByClientId(client_id)}
Msg <- Message{Clientid: client_id, Type: "level", Message: JsonEncode(message)}
client.Conn.Close()
close(client_id)
err := recover()
if err != nil {
fmt.Println(err)
}
}()
for {
// 读取消息。如果连接断开,则会返回错误 // 由于WebSocket一旦连接,便可以保持长时间通讯,则该接口函数可以一直运行下去,直到连接断开
var msg Message
err := client.Conn.ReadJSON(&msg)
if err != nil { // 如果返回错误,就退出循环
break
}
msg.Clientid = client_id
Msg <- msg
}
}
/**
发送消息到所有客户端
clientids 不发消息的客户端
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsSendToAll(msg Message, clientids ...interface{}) {
var noClientids []string
if len(clientids) > 0 {
for _, c := range clientids {
noClientids = append(noClientids, c.(string))
}
}
go func() {
clientsList.Iterator(func(clientid interface{}, client interface{}) bool {
if len(noClientids) > 0 {
if !InArray(clientid.(string), noClientids) {
client.(clientOne).Send <- msg
}
} else {
client.(clientOne).Send <- msg
}
return true
})
}()
}
/**
发送消息到客户端
client_id 客户端地址 字符串
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsSendToClient(client_id string, msg Message) error {
client := clientsList.Get(client_id)
if client == nil {
return errors.New("客户端不存在")
}
client.(clientOne).Send <- msg
return nil
}
/**
关闭客户端
client_id 客户端地址 字符串
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsCloseClient(client_id string) error {
client := clientsList.Get(client_id)
if client == nil {
return errors.New("客户端不存在")
}
//取出该clien_id绑定的group和uid
message := map[string]interface{}{"uid": WsGetUidByClientId(client_id), "group": WsGetGroupCountByClientId(client_id)}
Msg <- Message{Clientid: client_id, Type: "level", Message: JsonEncode(message)}
return close(client_id, client)
}
/**
关闭用户绑定的客户端
uid 字符串
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsCloseUid(uid string) error {
clients := WsGetClientIdByUid(uid)
if len(clients) == 0 {
return errors.New("该ID没有绑定ws")
}
for _, client_id := range clients {
WsCloseClient(client_id)
}
return nil
}
/**
判断客户端是否在线
bool true 在线 false 不在线
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsIsOnline(client_id string) bool {
client := clientsList.Get(client_id)
return client != nil
}
/**
将client_id与uid绑定,以便通过WsSendToUid($uid)发送数据,通过WsIsUidOnline($uid)用户是否在线。
uid解释:这里uid泛指用户id或者设备id,用来唯一确定一个客户端用户或者设备。
1、uid与client_id是一对多的关系,系统允许一个uid下有多个client_id。
2、但是一个client_id只能绑定一个uid,如果绑定多次uid,则只有最后一次绑定有效。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsBindUid(client_id, uid string) error {
if clientsList.Get(client_id) == nil {
return errors.New("客户端不存在")
}
clientUids.Set(client_id, uid)
return nil
}
//获取所有链接的client_id 数据 map为client_id和绑定的uid
func WsUGetClientsList() map[string]string {
var clientList = make(map[string]string)
clientsList.Iterator(func(client_id interface{}, clientone interface{}) bool {
clientList[client_id.(string)] = WsGetUidByClientId(client_id.(string))
return true
})
return clientList
}
/**
将client_id与uid解绑。
注意:当client_id下线(连接断开)时会自动与uid解绑
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsUnBindUid(client_id, uid string) error {
clientUids.Iterator(func(c interface{}, u interface{}) bool {
if Equal(client_id, c) && Equal(uid, u) {
clientUids.Remove(client_id)
return false
}
return true
})
return nil
}
/**
uid绑定的client_id是否在线
判断$uid是否在线,此方法需要配合BindUid($client_uid, $uid)使用。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsIsUidOnline(uid string) bool {
if len(WsGetClientIdByUid(uid)) > 0 {
return true
}
return false
}
/**
返回一个数组,数组元素为与uid绑定的所有在线的client_id。如果没有在线的client_id则返回一个空数组。
此方法可以判断一个uid是否在线。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsGetClientIdByUid(uid string) []string {
var clientids []string
clientUids.Iterator(func(client_id interface{}, cuid interface{}) bool {
if Equal(uid, cuid) {
if WsIsOnline(client_id.(string)) {
clientids = append(clientids, client_id.(string))
} else {
clientUids.Remove(client_id)
}
}
return true
})
return clientids
}
/**
返回client_id绑定的uid,如果client_id没有绑定uid,则返回空。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsGetUidByClientId(client_id string) string {
uid := clientUids.Get(client_id)
if uid != nil {
return uid.(string)
}
return ""
}
/**
向uid绑定的所有在线client_id发送数据。
注意:默认uid与client_id是一对多的关系,如果当前uid下绑定了多个client_id,则多个client_id对应的客户端都会收到消息,这类似于PC QQ和手机QQ同时在线接收消息。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsSendToUid(uid string, msg Message) error {
var err error
for _, client_id := range WsGetClientIdByUid(uid) {
err = WsSendToClient(client_id, msg)
}
return err
}
/**
将client_id加入某个组,以便通过sendToGroup发送数据。
1、同一个client_id可以加入多个分组,以便接收不同组发来的数据。
2、当client_id下线(连接断开)后,该client_id会自动从该分组中删除,开发者无需调用Gateway::leaveGroup。
3、如果对应分组的所有client_id都下线,则对应分组会被自动删除
client_id 加入群组
group_id 群组id
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsJoinGroup(client_id, group_id string) error {
if group_id == "" {
return errors.New("分组不存在")
}
if !WsIsOnline(client_id) {
return errors.New("当前用户不在线")
}
groupsListInfo := groupsList.Get(group_id)
if groupsListInfo == nil {
g := garray.NewArray(true)
g.Append(client_id)
groupsList.Set(group_id, g)
} else {
gs := (groupsListInfo).(*garray.Array)
gsId := gs.Search(client_id)
if gsId == -1 {
gs.Append(client_id)
groupsList.Set(group_id, gs)
}
}
Msg <- Message{Clientid: client_id, Type: "joingroup", Message: group_id}
return nil
}
/**
将client_id从某个组中删除,不再接收该分组广播(sendToGroup)发送的数据。
当client_id下线(连接断开)时,client_id会自动从它所属的各个分组中删除
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsLeaveGroup(client_id, group_id string) error {
groupsListInfo := groupsList.Get(group_id)
if groupsListInfo == nil {
return errors.New("分组不存在")
} else {
gs := (groupsListInfo).(*garray.Array)
gsId := gs.Search(client_id)
if gsId > -1 {
gs.Remove(gsId)
if gs.Len() > 0 {
groupsList.Set(group_id, gs)
} else {
groupsList.Remove(group_id)
Msg <- Message{Type: "ungroup", Message: group_id}
}
} else {
return errors.New("客户端不存在")
}
}
Msg <- Message{Clientid: client_id, Type: "levelgroup", Message: group_id}
return nil
}
/**
取消分组,或者说解散分组。 取消分组后所有属于这个分组的用户的连接将被移出分组,此分组将不再存在
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsUngroup(group_id string) error {
if groupsList.Get(group_id) == nil {
return errors.New("分组不存在")
} else {
groupsList.Remove(group_id)
}
Msg <- Message{Type: "ungroup", Message: group_id}
return nil
}
/**
发送消息到所有分组
clientids 不发消息的客户端
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsSendToGroup(msg Message, group_id string, clientids ...interface{}) error {
groupsListInfo := groupsList.Get(group_id)
if groupsListInfo == nil {
return errors.New("分组不存在")
}
gs := (groupsListInfo).(*garray.Array)
if gs.Len() == 0 {
return errors.New("分组成员不存在")
}
var noClientids []string
if len(clientids) > 0 {
for _, c := range clientids {
noClientids = append(noClientids, c.(string))
}
}
go func() {
for _, clientid := range gs.Slice() {
if len(noClientids) > 0 && InArray(clientid, noClientids) {
continue
}
clientOneInfo := clientsList.Get(clientid)
if clientOneInfo != nil {
clientOneInfo.(clientOne).Send <- msg
}
}
}()
return nil
}
/**
获取某分组当前在线成连接数(多少client_id在线)。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsGetClientIdCountByGroup(group_id string) int {
groupsListInfo := groupsList.Get(group_id)
if groupsListInfo == nil {
return 0
}
gs := (groupsListInfo).(*garray.Array)
return gs.Len()
}
/**
通过client_id 获取该client_id所在分组。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsGetGroupCountByClientId(client_id string) []string {
var groups []string
groupsList.Iterator(func(group_id interface{}, clientids interface{}) bool {
if (clientids.(*garray.Array)).Search(client_id) >= 0 {
groups = append(groups, group_id.(string))
}
return true
})
return groups
}
/**
获取当前在线连接总数(多少client_id在线)。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsGetAllClientIdCount() int {
return clientsList.Size()
}
/**
获取当前在线client_id信息。
* <a href="/user/Author" title="@Author">@Author</a> chenzhenhui <971688607@qq.com>
* @Copyright 2020~2030 http://www.znkefu.cn All rights reserved.
*/
func WsGetClientSessions(client_id string) interface{} {
return (clientsList.Get(client_id)).(clientOne).Session
}
有疑问加站长微信联系(非本文作者)