170 lines
4.7 KiB
Go
170 lines
4.7 KiB
Go
|
|
package handler
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"crypto/rand"
|
|||
|
|
"encoding/hex"
|
|||
|
|
"encoding/json"
|
|||
|
|
"github.com/gin-gonic/gin"
|
|||
|
|
"github.com/gorilla/websocket"
|
|||
|
|
"log"
|
|||
|
|
"net/http"
|
|||
|
|
"strconv"
|
|||
|
|
"time"
|
|||
|
|
"videoplayer/proto"
|
|||
|
|
"videoplayer/worker"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
var (
|
|||
|
|
upgrader = websocket.Upgrader{
|
|||
|
|
ReadBufferSize: 1024,
|
|||
|
|
WriteBufferSize: 1024,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
func SetUpIMGroup(router *gin.Engine) {
|
|||
|
|
imGroup := router.Group("/im")
|
|||
|
|
imGroup.POST("/get_imKey", GetImKey)
|
|||
|
|
imGroup.GET("/ws", SRMessage)
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
func generateRandomHexString(length int) (string, error) {
|
|||
|
|
bytes := make([]byte, length/2) // 16字节的字符串需要32个十六进制字符,即16个字节
|
|||
|
|
if _, err := rand.Read(bytes); err != nil {
|
|||
|
|
return "", err
|
|||
|
|
}
|
|||
|
|
return hex.EncodeToString(bytes), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func GetImKey(c *gin.Context) {
|
|||
|
|
id, _ := c.Get("id")
|
|||
|
|
var req proto.ImKeyReq
|
|||
|
|
if err := c.ShouldBindJSON(&req); err == nil {
|
|||
|
|
id1 := int(id.(float64))
|
|||
|
|
var redis_key string
|
|||
|
|
if id1 < req.To_user_id {
|
|||
|
|
redis_key = strconv.Itoa(id1) + "_" + strconv.Itoa(req.To_user_id) + "_imKey"
|
|||
|
|
} else {
|
|||
|
|
redis_key = strconv.Itoa(req.To_user_id) + "_" + strconv.Itoa(id1) + "_imKey"
|
|||
|
|
}
|
|||
|
|
if worker.IsContainKey(redis_key) == true {
|
|||
|
|
res := worker.GetRedis(redis_key)
|
|||
|
|
var retrievedData map[string]interface{}
|
|||
|
|
err2 := json.Unmarshal([]byte(res), &retrievedData)
|
|||
|
|
if err2 != nil {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
if retrievedData["from_user_id"] == id1 {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": retrievedData, "message": "success"})
|
|||
|
|
return
|
|||
|
|
} else {
|
|||
|
|
retrievedData["is_read"] = 1
|
|||
|
|
res2 := worker.SetRedisWithExpire(redis_key+"_connection", retrievedData["im_session"].(string), time.Second*30)
|
|||
|
|
if res2 == false {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"error": "set key failed", "code": proto.OperationFailed, "message": "failed"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": retrievedData, "message": "success"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//生成随机字符串
|
|||
|
|
imkey, err2 := generateRandomHexString(16)
|
|||
|
|
imSession, err3 := generateRandomHexString(8)
|
|||
|
|
if err2 != nil || err3 != nil {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"error": "generate key failed", "code": proto.OperationFailed, "message": "failed"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
data := make(map[string]interface{})
|
|||
|
|
data["im_key"] = imkey
|
|||
|
|
data["from_user_id"] = id1
|
|||
|
|
data["to_user_id"] = req.To_user_id
|
|||
|
|
data["im_session"] = imSession
|
|||
|
|
data["is_read"] = 0
|
|||
|
|
str, _ := json.Marshal(data)
|
|||
|
|
//将key存入redis
|
|||
|
|
res := worker.SetRedisWithExpire(redis_key, string(str), time.Second*30)
|
|||
|
|
if res == false {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"error": "set key failed", "code": proto.OperationFailed, "message": "failed"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": data, "message": "success"})
|
|||
|
|
return
|
|||
|
|
} else {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 接收及发送消息
|
|||
|
|
func SRMessage(c *gin.Context) {
|
|||
|
|
id, _ := c.Get("id")
|
|||
|
|
id1 := int(id.(float64))
|
|||
|
|
var redis_key string
|
|||
|
|
to_user_id := c.Query("to_user_id")
|
|||
|
|
to_user_id_num, _ := strconv.ParseInt(to_user_id, 10, 64)
|
|||
|
|
if id1 < int(to_user_id_num) {
|
|||
|
|
redis_key = strconv.Itoa(id1) + "_" + to_user_id + "_imKey"
|
|||
|
|
} else {
|
|||
|
|
redis_key = to_user_id + "_" + strconv.Itoa(id1) + "_imKey"
|
|||
|
|
}
|
|||
|
|
if worker.IsContainKey(redis_key) == false {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"code": proto.OperationFailed, "message": "failed"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 升级HTTP连接为WebSocket连接
|
|||
|
|
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
|||
|
|
if err != nil {
|
|||
|
|
log.Println(err)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
defer ws.Close()
|
|||
|
|
res := worker.GetRedis(redis_key + "_connection")
|
|||
|
|
if res == "" {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 接收客户端消息并发送到指定用户
|
|||
|
|
go func(ws *websocket.Conn, session string, to_id string) {
|
|||
|
|
for {
|
|||
|
|
_, message, err := ws.ReadMessage()
|
|||
|
|
if err != nil {
|
|||
|
|
// 当连接关闭时
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 将接收到的消息解析为JSON
|
|||
|
|
var msg proto.Message
|
|||
|
|
if err2 := json.Unmarshal(message, &msg); err2 != nil {
|
|||
|
|
log.Println("unmarshal:", err2)
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
if msg.Type == "msg" {
|
|||
|
|
// 将消息发送到指定用户
|
|||
|
|
worker.PushRedisList(session+"_"+to_user_id, msg.Msg) //将消息存入redis
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}(ws, res, to_user_id)
|
|||
|
|
|
|||
|
|
// 从Redis中读取消息并发送到客户端
|
|||
|
|
go func(ws *websocket.Conn, session string, id int) {
|
|||
|
|
for {
|
|||
|
|
res2 := worker.PopRedisList(session + "_" + strconv.Itoa(id))
|
|||
|
|
if res2 != "" {
|
|||
|
|
var msg proto.Message
|
|||
|
|
msg.Type = "msg"
|
|||
|
|
msg.Msg = res2
|
|||
|
|
msg.From_user_id = id
|
|||
|
|
msg.Session = session
|
|||
|
|
res3, _ := json.Marshal(msg)
|
|||
|
|
err2 := ws.WriteMessage(websocket.TextMessage, res3)
|
|||
|
|
if err2 != nil {
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}(ws, res, id1)
|
|||
|
|
}
|