From 261ea9a0e0ffc3eecc5a61d6f94c8b736f03a6fe Mon Sep 17 00:00:00 2001 From: junleea <354425203@qq.com> Date: Fri, 2 Aug 2024 09:47:33 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=88=9B=E5=BB=BA=E5=8F=8A=E9=83=A8=E5=88=86?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dao/db.go | 5 +++++ dao/im.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ handler/im.go | 6 +++++- 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 dao/im.go diff --git a/dao/db.go b/dao/db.go index 5bf9c7f..bf432cc 100644 --- a/dao/db.go +++ b/dao/db.go @@ -40,6 +40,11 @@ func Init() { if err != nil { fmt.Println("cidrunlog table:", err) } // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表 + + err = db.AutoMigrate(&Message{}) + if err != nil { + fmt.Println("message table:", err) + } // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表 DB = db } diff --git a/dao/im.go b/dao/im.go new file mode 100644 index 0000000..f17944a --- /dev/null +++ b/dao/im.go @@ -0,0 +1,56 @@ +package dao + +import "gorm.io/gorm" + +type Message struct { + gorm.Model + FromUserID int `gorm:"column:from_user_id"` + ToUserID int `gorm:"column:to_user_id"` + GroupID int `gorm:"column:group_id"` + Msg string `gorm:"column:msg"` + Status int `gorm:"column:status"` //单聊时才有0,已读,2未读 + Type int `gorm:"column:type"` //1为单聊,2为群聊,3为系统消息 +} + +type Group struct { + gorm.Model + GroupName string `gorm:"column:group_name"` +} + +type GroupUser struct { + gorm.Model + GroupID int `gorm:"column:group_id"` + UserID int `gorm:"column:user_id"` + IsMaster int `gorm:"column:is_master"` +} + +type Friend struct { + gorm.Model + UserID int `gorm:"column:user_id"` + FriendID int `gorm:"column:friend_id"` +} + +// 创建单聊消息 +func CreateSimpleMessage(from_user_id, to_user_id int, message string) error { + msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: 1, Status: 0} + res := DB.Debug().Create(msg) + return res.Error +} + +// 每20个消息一组,请求index*20 +func GetMsgUserByIndex(from_user_id, to_user_id, index int) ([]Message, error) { + var msgs []Message + res := DB.Debug().Where("from_user_id = ? and to_user_id = ?", from_user_id, to_user_id).Find(&msgs).Order("order by createAt DESC").Limit(20 * index) + return msgs, res.Error +} + +// 修改信息 +func UpdateMessage() { + +} + +func FindMessageByID(id uint) []Message { + var msgs []Message + DB.Debug().Where("id = ?", id).Find(msgs) + return msgs +} diff --git a/handler/im.go b/handler/im.go index 4fc96ee..32eaf08 100644 --- a/handler/im.go +++ b/handler/im.go @@ -37,7 +37,7 @@ func SetUpIMGroup(router *gin.Engine) { imGroup := router.Group("/im") imGroup.POST("/get_imKey", GetImKey) imGroup.GET("/ws", SRMessage) - + imGroup.POST("/send_message", SendMessage) } func generateRandomHexString(length int) (string, error) { bytes := make([]byte, length/2) // 16字节的字符串需要32个十六进制字符,即16个字节 @@ -47,6 +47,10 @@ func generateRandomHexString(length int) (string, error) { return hex.EncodeToString(bytes), nil } +func SendMessage(c *gin.Context) { + +} + func GetImKey(c *gin.Context) { id, _ := c.Get("id") var req proto.ImKeyReq From c4404caf4903055cb30d7a23885bf8573b4e6203 Mon Sep 17 00:00:00 2001 From: junleea <354425203@qq.com> Date: Fri, 2 Aug 2024 10:30:41 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dao/db.go | 26 ++++++++++++++++++++++++-- main.go | 10 ++++++++-- worker/redis.go | 3 ++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/dao/db.go b/dao/db.go index bf432cc..13b1e58 100644 --- a/dao/db.go +++ b/dao/db.go @@ -9,7 +9,7 @@ import ( var DB *gorm.DB -func Init() { +func Init() error { dsn := proto.MYSQL_DSN db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) @@ -19,18 +19,22 @@ func Init() { err = db.AutoMigrate(&User{}) if err != nil { fmt.Println("user table:", err) + return err } // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表 err = db.AutoMigrate(&Video{}) if err != nil { fmt.Println("video table:", err) + return err } // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表 err = db.AutoMigrate(&Device{}) if err != nil { fmt.Println("device table:", err) + return err } // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表 err = db.AutoMigrate(&Logger{}) if err != nil { fmt.Println("logger table:", err) + return err } // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表 err = db.AutoMigrate(&CID{}) if err != nil { @@ -44,8 +48,26 @@ func Init() { err = db.AutoMigrate(&Message{}) if err != nil { fmt.Println("message table:", err) - } // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表 + } + + err = db.AutoMigrate(&Group{}) + if err != nil { + fmt.Println("usergroup table:", err) + } + + err = db.AutoMigrate(&GroupUser{}) + if err != nil { + fmt.Println("groupuser table:", err) + return err + } + + err = db.AutoMigrate(&Friend{}) + if err != nil { + fmt.Println("friend table:", err) + } + DB = db + return err } func Close() { diff --git a/main.go b/main.go index 60a2d38..81b5adf 100644 --- a/main.go +++ b/main.go @@ -18,8 +18,14 @@ func main() { r := gin.Default() gin.SetMode(gin.ReleaseMode) - dao.Init() - worker.InitRedis() + err := dao.Init() + if err != nil { + panic("failed to connect database:" + err.Error()) + } + err = worker.InitRedis() + if err != nil { + panic("failed to connect redis:" + err.Error()) + } r.Use(handler.CrosHandler()) r.Use(JWTAuthMiddleware()) // 使用 JWT 认证中间件 handler.SetUpVideoGroup(r) // Video diff --git a/worker/redis.go b/worker/redis.go index a05fc21..bc19b5f 100644 --- a/worker/redis.go +++ b/worker/redis.go @@ -13,7 +13,7 @@ import ( ) var redisClient *redis.Client // Redis 客户端, 用于连接 Redis 服务器 -func InitRedis() { +func InitRedis() error { ctx := context.Background() // 连接redis redisClient = redis.NewClient(&redis.Options{ @@ -27,6 +27,7 @@ func InitRedis() { if err != nil { fmt.Println("Error connecting to Redis: %v", err) } + return err } func CloseRedis() { From 7cef0ec8db5393dfccbabf1adaa94a207693604d Mon Sep 17 00:00:00 2001 From: junleea <354425203@qq.com> Date: Fri, 2 Aug 2024 15:02:56 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dao/im.go | 104 +++++++++++++++++++++++++++++++++++++++++++++++--- proto/conf.go | 12 ++++++ 2 files changed, 111 insertions(+), 5 deletions(-) diff --git a/dao/im.go b/dao/im.go index f17944a..9af0c27 100644 --- a/dao/im.go +++ b/dao/im.go @@ -1,6 +1,9 @@ package dao -import "gorm.io/gorm" +import ( + "gorm.io/gorm" + "videoplayer/proto" +) type Message struct { gorm.Model @@ -15,13 +18,16 @@ type Message struct { type Group struct { gorm.Model GroupName string `gorm:"column:group_name"` + GroupInfo string `gorm:"column:group_info"` + GroupType int `gorm:"column:group_type"` + GroupIcon string `gorm:"column:group_icon"` } type GroupUser struct { gorm.Model - GroupID int `gorm:"column:group_id"` - UserID int `gorm:"column:user_id"` - IsMaster int `gorm:"column:is_master"` + GroupID int `gorm:"column:group_id"` + UserID int `gorm:"column:user_id"` + IsMaster bool `gorm:"column:is_master"` } type Friend struct { @@ -32,7 +38,13 @@ type Friend struct { // 创建单聊消息 func CreateSimpleMessage(from_user_id, to_user_id int, message string) error { - msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: 1, Status: 0} + msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: proto.MSG_TYPE_SIMPLE, Status: proto.MSG_STATUS_UNREAD} + res := DB.Debug().Create(msg) + return res.Error +} + +func CreateGeneralMessage(from_user_id, to_user_id, msg_type, status int, message string) error { + msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: msg_type, Status: status} res := DB.Debug().Create(msg) return res.Error } @@ -49,8 +61,90 @@ func UpdateMessage() { } +// 添加好友 +func AddFriend(user_id, friend_id int) error { + friend := Friend{UserID: user_id, FriendID: friend_id} + friend2 := Friend{UserID: friend_id, FriendID: user_id} + + //开启事务 + tx := DB.Begin() + if err := tx.Create(&friend); err.Error != nil { + tx.Rollback() + return err.Error + } + if err := tx.Create(&friend2); err.Error != nil { + tx.Rollback() + return err.Error + } + //提交事务 + if err := tx.Commit().Error; err != nil { + return err + } + return error(nil) +} + +// 删除好友,删除后双方都不是好友 +func DeleteFriend(user_id, friend_id int) error { + //开启事务 + tx := DB.Begin() + if err := tx.Delete(&Friend{}, "user_id = ? and friend_id = ?", user_id, friend_id); err.Error != nil { + tx.Rollback() + return err.Error + } + if err := tx.Delete(&Friend{}, "user_id = ? and friend_id = ?", friend_id, user_id); err.Error != nil { + tx.Rollback() + return err.Error + } + //提交事务 + if err := tx.Commit().Error; err != nil { + return err + } + return error(nil) +} + +// 通过id查找消息 func FindMessageByID(id uint) []Message { var msgs []Message DB.Debug().Where("id = ?", id).Find(msgs) return msgs } + +// 更新消息状态 +func UpdateMessageStatus(id uint, status int) error { + res := DB.Debug().Model(&Message{}).Where("id = ?", id).Update("status", status) + return res.Error +} + +// 创建群聊,需要事务 +func CreateGroup(group_name string, master_user_id int) uint { + group := Group{GroupName: group_name} + //开启事务 + tx := DB.Begin() + if err := tx.Create(&group); err.Error != nil { + tx.Rollback() + return 0 + } + groupUser := GroupUser{GroupID: int(group.ID), UserID: master_user_id, IsMaster: true} + if err := tx.Create(&groupUser); err.Error != nil { + tx.Rollback() + return 0 + } + //提交事务 + if err := tx.Commit().Error; err != nil { + return 0 + } + return group.ID +} + +// 加入群聊 +func JoinGroup(group_id, user_id int) error { + groupUser := GroupUser{GroupID: group_id, UserID: user_id} + res := DB.Debug().Create(&groupUser) + return res.Error +} + +// 退出群聊 +func QuitGroup(group_id, user_id int) error { + res := DB.Debug().Delete(&GroupUser{}, "group_id = ? and user_id = ?", group_id, user_id) + return res.Error +} diff --git a/proto/conf.go b/proto/conf.go index 5130b5f..ee2e550 100644 --- a/proto/conf.go +++ b/proto/conf.go @@ -20,6 +20,18 @@ const ( CID_BASE_DIR = "/home/lijun/cid/" ) +const ( + // 以下是消息类型 + MSG_TYPE_SIMPLE = 1 // 单聊 + MSG_TYPE_GROUP = 2 // 群聊 + MSG_TYPE_SYSTEM = 3 // 系统消息 + MSG_TYPE_FRIEND = 4 // 好友请求 + + // 以下是消息状态 + MSG_STATUS_READ = 1 // 已读 + MSG_STATUS_UNREAD = 0 // 未读 +) + type User struct { gorm.Model Name string `gorm:"column:name"` From fc12e233ae490182f4098e9007e03475ac623244 Mon Sep 17 00:00:00 2001 From: junleea <354425203@qq.com> Date: Fri, 2 Aug 2024 16:33:52 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=8F=91=E9=80=81=E5=8F=8A=E8=8E=B7=E5=8F=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dao/im.go | 4 ++-- handler/im.go | 45 +++++++++++++++++++++++++++++++++++++++++++- proto/conf.go | 2 +- proto/status.go | 3 +++ service/imService.go | 37 ++++++++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 service/imService.go diff --git a/dao/im.go b/dao/im.go index 9af0c27..dd6c42e 100644 --- a/dao/im.go +++ b/dao/im.go @@ -50,9 +50,9 @@ func CreateGeneralMessage(from_user_id, to_user_id, msg_type, status int, messag } // 每20个消息一组,请求index*20 -func GetMsgUserByIndex(from_user_id, to_user_id, index int) ([]Message, error) { +func GetMsgUserByIndex(from_user_id, to_user_id, msg_type, index int) ([]Message, error) { var msgs []Message - res := DB.Debug().Where("from_user_id = ? and to_user_id = ?", from_user_id, to_user_id).Find(&msgs).Order("order by createAt DESC").Limit(20 * index) + res := DB.Debug().Where("from_user_id = ? and to_user_id = ? and type = ?", from_user_id, to_user_id, msg_type).Find(&msgs).Order("order by createAt DESC").Limit(20 * index) return msgs, res.Error } diff --git a/handler/im.go b/handler/im.go index 32eaf08..926774e 100644 --- a/handler/im.go +++ b/handler/im.go @@ -13,9 +13,23 @@ import ( "sync" "time" "videoplayer/proto" + "videoplayer/service" "videoplayer/worker" ) +type SMessage struct { + To_user_id int `json:"to_user_id" form:"to_user_id" binding:"required"` + Type int `json:"type" form:"type" binding:"required"` + Msg string `json:"msg" form:"msg" binding:"required"` +} + +type Message struct { + To_user_id int `json:"to_user_id"` + From_user_id int `json:"from_user_id"` + Index int `json:"index"` + Type int `json:"type"` +} + var ( upgrader = websocket.Upgrader{ ReadBufferSize: 1024, @@ -38,6 +52,7 @@ func SetUpIMGroup(router *gin.Engine) { imGroup.POST("/get_imKey", GetImKey) imGroup.GET("/ws", SRMessage) imGroup.POST("/send_message", SendMessage) + imGroup.POST("/get_message", GetMessage) } func generateRandomHexString(length int) (string, error) { bytes := make([]byte, length/2) // 16字节的字符串需要32个十六进制字符,即16个字节 @@ -46,9 +61,37 @@ func generateRandomHexString(length int) (string, error) { } return hex.EncodeToString(bytes), nil } +func GetMessage(c *gin.Context) { + var req Message + user_id, _ := c.Get("id") + id := int(user_id.(float64)) + if err := c.ShouldBind(&req); err == nil { + msgs, err2 := service.GetMsgUserByIndexService(id, req.To_user_id, req.Index, req.Type) + if err2 == nil { + c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": msgs, "message": "success"}) + } else { + c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"}) + } + } else { + c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"}) + } +} func SendMessage(c *gin.Context) { - + var req SMessage + user_id, _ := c.Get("id") + id := int(user_id.(float64)) + if err := c.ShouldBind(&req); err == nil { + var err2 error + err2 = service.CreateGeneralMessageService(id, req.To_user_id, req.Type, req.Msg) + if err2 == nil { + c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"}) + } else { + c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.MsgSendFailed, "message": "failed"}) + } + } else { + c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"}) + } } func GetImKey(c *gin.Context) { diff --git a/proto/conf.go b/proto/conf.go index ee2e550..d553741 100644 --- a/proto/conf.go +++ b/proto/conf.go @@ -11,7 +11,7 @@ const ( MYSQL_DSN = MYSQL_USER + ":" + MYSQL_PASSWORD + "@tcp(" + MYSQL_HOST + ":" + MYSQL_PORT + ")/" + MYSQL_DB + "?charset=utf8mb4&parseTime=True&loc=Local" REDIS_ADDR = "127.0.0.1:6379" - REDIS_PASSWORD = "lj502138" + REDIS_PASSWORD = "" REIDS_DB = 2 TOKEN_SECRET = "mfjurnc_32ndj9dfhj" diff --git a/proto/status.go b/proto/status.go index 51478e9..c3ad35f 100644 --- a/proto/status.go +++ b/proto/status.go @@ -41,4 +41,7 @@ const ( // UUID相关错误码 UUIDNotFound = 18 // uuid不存在 + + //消息错误码 + MsgSendFailed = 61 // 消息发送失败 ) diff --git a/service/imService.go b/service/imService.go new file mode 100644 index 0000000..f5f3ba3 --- /dev/null +++ b/service/imService.go @@ -0,0 +1,37 @@ +package service + +import ( + "errors" + "videoplayer/dao" +) + +func CreateGeneralMessageService(from_id, to_id, msg_type int, content string) error { + // 业务逻辑 + var err error + switch msg_type { + case 1: + err = dao.CreateSimpleMessage(from_id, to_id, content) + case 2, 3: + err = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, content) + case 4: + err = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, content) + default: + // 未知消息类型 + err = errors.New("unknown message type") + } + return err +} + +func GetMsgUserByIndexService(from_id, to_id, index, msq_type int) ([]dao.Message, error) { + // 业务逻辑 + if index <= 0 || index > 100 { + return nil, errors.New("index out of range") + } + msgs, err := dao.GetMsgUserByIndex(from_id, to_id, index, msq_type) + return msgs, err +} + +func GetFriendGroupReqService(user_id int) ([]dao.Message, error) { + // 业务逻辑 + return nil, nil +} From bd668c3ae62867fe5fa8c56989e41d8ce3868470 Mon Sep 17 00:00:00 2001 From: junleea <354425203@qq.com> Date: Sun, 4 Aug 2024 21:01:06 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E5=8A=9F=E8=83=BD=EF=BC=8C=E7=BE=A4=E7=BB=84?= =?UTF-8?q?=E6=9C=AA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dao/db.go | 1 + dao/im.go | 64 +++++++++++++++++++++++---------- handler/im.go | 57 +++++++++++++++++++++++++---- proto/conf.go | 9 ++--- service/imService.go | 85 ++++++++++++++++++++++++++++++++++++++------ 5 files changed, 178 insertions(+), 38 deletions(-) diff --git a/dao/db.go b/dao/db.go index 13b1e58..b25d46a 100644 --- a/dao/db.go +++ b/dao/db.go @@ -15,6 +15,7 @@ func Init() error { db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic("failed to connect database") + return err } err = db.AutoMigrate(&User{}) if err != nil { diff --git a/dao/im.go b/dao/im.go index dd6c42e..1e83c43 100644 --- a/dao/im.go +++ b/dao/im.go @@ -12,7 +12,7 @@ type Message struct { GroupID int `gorm:"column:group_id"` Msg string `gorm:"column:msg"` Status int `gorm:"column:status"` //单聊时才有0,已读,2未读 - Type int `gorm:"column:type"` //1为单聊,2为群聊,3为系统消息 + Type int `gorm:"column:type"` //1为单聊,2为群聊,3为系统消息,4为好友请求,5为加入群聊请求 } type Group struct { @@ -37,22 +37,37 @@ type Friend struct { } // 创建单聊消息 -func CreateSimpleMessage(from_user_id, to_user_id int, message string) error { +func CreateSimpleMessage(from_user_id, to_user_id int, message string) (error, uint) { msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: proto.MSG_TYPE_SIMPLE, Status: proto.MSG_STATUS_UNREAD} - res := DB.Debug().Create(msg) - return res.Error + res := DB.Debug().Create(&msg) + return res.Error, msg.ID } -func CreateGeneralMessage(from_user_id, to_user_id, msg_type, status int, message string) error { - msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: msg_type, Status: status} - res := DB.Debug().Create(msg) - return res.Error +func CreateGeneralMessage(from_user_id, to_user_id, msg_type, status, group_id int, message string) (error error, id uint) { + msg := Message{FromUserID: from_user_id, ToUserID: to_user_id, Msg: message, Type: msg_type, Status: status, GroupID: group_id} + res := DB.Debug().Create(&msg) + return res.Error, msg.ID } // 每20个消息一组,请求index*20 -func GetMsgUserByIndex(from_user_id, to_user_id, msg_type, index int) ([]Message, error) { +func GetMsgUserByIndex(from_user_id, to_user_id, msg_type, index, status int) ([]Message, error) { var msgs []Message - res := DB.Debug().Where("from_user_id = ? and to_user_id = ? and type = ?", from_user_id, to_user_id, msg_type).Find(&msgs).Order("order by createAt DESC").Limit(20 * index) + var res *gorm.DB + if msg_type == 4 { + res = DB.Debug().Where("from_user_id = ? and to_user_id = ? and type = ? and status = ? ", from_user_id, to_user_id, msg_type, status).Find(&msgs).Order("created_at DESC").Limit(20 * index) + } else if msg_type == 1 { + //单聊,只有两个人的消息 + res = DB.Debug().Where("((from_user_id = ? and to_user_id = ?) or (from_user_id = ? and to_user_id = ?)) and type = ? ", from_user_id, to_user_id, to_user_id, from_user_id, msg_type).Find(&msgs).Order("created_at DESC").Limit(20 * index) + } else { + res = DB.Debug().Where("from_user_id = ? and to_user_id = ? and type = ? ", from_user_id, to_user_id, msg_type).Find(&msgs).Order("created_at DESC").Limit(20 * index) + } + return msgs, res.Error +} + +// 获取邀请消息 +func GetFriendGroupReq(user_id int) ([]Message, error) { + var msgs []Message + res := DB.Debug().Where("to_user_id = ? and type = ?", user_id, proto.MSG_TYPE_FRIEND).Find(&msgs) return msgs, res.Error } @@ -105,7 +120,7 @@ func DeleteFriend(user_id, friend_id int) error { // 通过id查找消息 func FindMessageByID(id uint) []Message { var msgs []Message - DB.Debug().Where("id = ?", id).Find(msgs) + DB.Debug().Where("id = ?", id).Find(&msgs) return msgs } @@ -116,24 +131,31 @@ func UpdateMessageStatus(id uint, status int) error { } // 创建群聊,需要事务 -func CreateGroup(group_name string, master_user_id int) uint { - group := Group{GroupName: group_name} +func CreateGroup(groupName, groupInfo, groupType, groupIcon string, user_id int) (error, uint) { + group := Group{GroupName: groupName, GroupInfo: groupInfo, GroupType: proto.MSG_TYPE_GROUP, GroupIcon: groupIcon} //开启事务 tx := DB.Begin() if err := tx.Create(&group); err.Error != nil { tx.Rollback() - return 0 + return err.Error, 0 } - groupUser := GroupUser{GroupID: int(group.ID), UserID: master_user_id, IsMaster: true} + groupUser := GroupUser{GroupID: int(group.ID), UserID: user_id, IsMaster: true} if err := tx.Create(&groupUser); err.Error != nil { tx.Rollback() - return 0 + return err.Error, 0 } //提交事务 if err := tx.Commit().Error; err != nil { - return 0 + return err, 0 } - return group.ID + return nil, group.ID +} + +// 查找用户是否在群聊 +func FindGroupUser(user_id, group_id int) []GroupUser { + var groupUsers []GroupUser + DB.Debug().Where("user_id = ? and group_id = ?", user_id, group_id).Find(&groupUsers) + return groupUsers } // 加入群聊 @@ -148,3 +170,9 @@ func QuitGroup(group_id, user_id int) error { res := DB.Debug().Delete(&GroupUser{}, "group_id = ? and user_id = ?", group_id, user_id) return res.Error } + +func FindFriend(from_user_id, to_user_id int) []Friend { + var friends []Friend + DB.Debug().Where("user_id = ? and friend_id = ?", from_user_id, to_user_id).Find(&friends) + return friends +} diff --git a/handler/im.go b/handler/im.go index 926774e..0089b9e 100644 --- a/handler/im.go +++ b/handler/im.go @@ -18,18 +18,26 @@ import ( ) type SMessage struct { - To_user_id int `json:"to_user_id" form:"to_user_id" binding:"required"` - Type int `json:"type" form:"type" binding:"required"` - Msg string `json:"msg" form:"msg" binding:"required"` + To_user_id int `json:"to_user_id" form:"to_user_id"` + Type int `json:"type" form:"type"` + Msg string `json:"msg" form:"msg"` } type Message struct { + ID int `json:"id"` To_user_id int `json:"to_user_id"` From_user_id int `json:"from_user_id"` Index int `json:"index"` Type int `json:"type"` } +type CGroup struct { + Group_name string `json:"group_name" form:"group_name"` + Group_info string `json:"group_info" form:"group_info"` + Group_type string `json:"group_type" form:"group_type"` + Group_icon string `json:"group_icon" form:"group_icon"` +} + var ( upgrader = websocket.Upgrader{ ReadBufferSize: 1024, @@ -53,6 +61,9 @@ func SetUpIMGroup(router *gin.Engine) { imGroup.GET("/ws", SRMessage) imGroup.POST("/send_message", SendMessage) imGroup.POST("/get_message", GetMessage) + //接受邀请,确认好友关系 + imGroup.POST("/accept_invite", AcceptInvite) + imGroup.POST("/create_group", CreateGroup) } func generateRandomHexString(length int) (string, error) { bytes := make([]byte, length/2) // 16字节的字符串需要32个十六进制字符,即16个字节 @@ -66,7 +77,8 @@ func GetMessage(c *gin.Context) { user_id, _ := c.Get("id") id := int(user_id.(float64)) if err := c.ShouldBind(&req); err == nil { - msgs, err2 := service.GetMsgUserByIndexService(id, req.To_user_id, req.Index, req.Type) + fmt.Println(req) + msgs, err2 := service.GetMsgUserByIndexService(id, req.To_user_id, req.Index, req.Type, req.From_user_id) if err2 == nil { c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": msgs, "message": "success"}) } else { @@ -77,15 +89,48 @@ func GetMessage(c *gin.Context) { } } +func CreateGroup(c *gin.Context) { + var req CGroup + id, _ := c.Get("id") + user_id := int(id.(float64)) + if err := c.ShouldBind(&req); err == nil { + err2, id := service.CreateGroup(req.Group_name, req.Group_info, req.Group_type, req.Group_icon, user_id) + if err2 == nil { + c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": id, "message": "success"}) + } else { + c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"}) + } + } else { + c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"}) + } +} + +func AcceptInvite(c *gin.Context) { + var req Message + user_id, _ := c.Get("id") + cid := int(user_id.(float64)) + if err := c.ShouldBind(&req); err == nil { + err2 := service.AddFriendService(req.ID, cid, req.To_user_id) + if err2 == nil { + c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"}) + } else { + c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.OperationFailed, "message": "failed"}) + } + } else { + c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"}) + } +} + func SendMessage(c *gin.Context) { var req SMessage user_id, _ := c.Get("id") id := int(user_id.(float64)) if err := c.ShouldBind(&req); err == nil { var err2 error - err2 = service.CreateGeneralMessageService(id, req.To_user_id, req.Type, req.Msg) + var mid uint + err2, mid = service.CreateGeneralMessageService(id, req.To_user_id, req.Type, req.Msg) if err2 == nil { - c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"}) + c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": mid}) } else { c.JSON(http.StatusOK, gin.H{"error": err2.Error(), "code": proto.MsgSendFailed, "message": "failed"}) } diff --git a/proto/conf.go b/proto/conf.go index d553741..f3c0f8f 100644 --- a/proto/conf.go +++ b/proto/conf.go @@ -22,10 +22,11 @@ const ( const ( // 以下是消息类型 - MSG_TYPE_SIMPLE = 1 // 单聊 - MSG_TYPE_GROUP = 2 // 群聊 - MSG_TYPE_SYSTEM = 3 // 系统消息 - MSG_TYPE_FRIEND = 4 // 好友请求 + MSG_TYPE_SIMPLE = 1 // 单聊 + MSG_TYPE_GROUP = 2 // 群聊 + MSG_TYPE_SYSTEM = 3 // 系统消息 + MSG_TYPE_FRIEND = 4 // 好友请求 + MSG_TYPE_GROUP_ADD = 5 // 加入群聊请求 // 以下是消息状态 MSG_STATUS_READ = 1 // 已读 diff --git a/service/imService.go b/service/imService.go index f5f3ba3..7c038d3 100644 --- a/service/imService.go +++ b/service/imService.go @@ -5,33 +5,98 @@ import ( "videoplayer/dao" ) -func CreateGeneralMessageService(from_id, to_id, msg_type int, content string) error { +func CreateGeneralMessageService(from_id, to_id, msg_type int, content string) (error, uint) { // 业务逻辑 var err error + var id uint switch msg_type { case 1: - err = dao.CreateSimpleMessage(from_id, to_id, content) - case 2, 3: - err = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, content) + //判断是否是好友 + friend := dao.FindFriend(from_id, to_id) + if len(friend) == 0 { + return errors.New("not a friend"), 0 + } + err, id = dao.CreateSimpleMessage(from_id, to_id, content) + case 2: + err, id = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, 0, content) + case 3: + //user := dao.FindUserByID(to_id) + // 系统消息,需要管理员权限 + err, id = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, 0, content) case 4: - err = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, content) + res, _ := dao.GetMsgUserByIndex(from_id, to_id, 4, 1, 0) + if len(res) > 0 { + // 已经有会话记录 + return errors.New("already have a conversation"), 0 + } + err, id = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, 0, content) + case 5: + res, _ := dao.GetMsgUserByIndex(from_id, to_id, 5, 1, 0) + if len(res) > 0 { + // 已经有会话记录 + return errors.New("already have a conversation"), 0 + } + //邀请加入群聊请求 + err, id = dao.CreateGeneralMessage(from_id, to_id, msg_type, 0, from_id, content) default: // 未知消息类型 err = errors.New("unknown message type") } - return err + return err, id } -func GetMsgUserByIndexService(from_id, to_id, index, msq_type int) ([]dao.Message, error) { +func GetMsgUserByIndexService(from_id, to_id, index, msq_type, from_user_id int) ([]dao.Message, error) { // 业务逻辑 if index <= 0 || index > 100 { return nil, errors.New("index out of range") } - msgs, err := dao.GetMsgUserByIndex(from_id, to_id, index, msq_type) + if msq_type == 4 { + from_id = from_user_id + } + msgs, err := dao.GetMsgUserByIndex(from_id, to_id, msq_type, index, 0) return msgs, err } -func GetFriendGroupReqService(user_id int) ([]dao.Message, error) { +// AddFriendService 通过消息id添加好友,和加入群聊 +// id 消息id +// from_user_id 发送消息的用户id +// to_user_id 接收消息的用户id,及接受用户id +func AddFriendService(id, from_user_id, to_user_id int) error { // 业务逻辑 - return nil, nil + res := dao.FindMessageByID(uint(id)) + if res[0].FromUserID == to_user_id && res[0].ToUserID == from_user_id { + friend := dao.FindFriend(from_user_id, to_user_id) + if len(friend) > 0 { + return errors.New("already a friend") + } + dao.UpdateMessageStatus(res[0].ID, 1) + return dao.AddFriend(from_user_id, to_user_id) + } else if res[0].ToUserID == from_user_id && res[0].GroupID == to_user_id { + //加入群聊 + //查看是否已经加入 + groupUser := dao.FindGroupUser(from_user_id, to_user_id) + if len(groupUser) > 0 { + return errors.New("already in the group") + } + err := dao.JoinGroup(groupUser[0].GroupID, to_user_id) + if err != nil { + return err + } + err = dao.UpdateMessageStatus(res[0].ID, 1) + return err + } else { + return errors.New("no such message,cannot add friend") + } +} + +// CreateGroup 创建群聊 +// groupName 群聊名称 +// groupInfo 群聊信息 +// groupType 群聊类型 +// groupIcon 群聊图标 +// user_id 创建群的用户id +func CreateGroup(groupName, groupInfo, groupType, groupIcon string, user_id int) (error, uint) { + // 业务逻辑 + err, id := dao.CreateGroup(groupName, groupInfo, groupType, groupIcon, user_id) + return err, id }