go语言开源客服系统代码,im及时通讯长链接代码

znkefu · · 1249 次点击 · 开始浏览    置顶

/** 保持心跳 * <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 }

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1249 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传