🎨 update code structure

This commit is contained in:
landaiqing
2024-09-29 17:08:18 +08:00
parent 87f1ff6961
commit 4ec1ea40bb
23 changed files with 672 additions and 761 deletions

View File

@@ -1,25 +1,21 @@
package comment_controller
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/acmestack/gorm-plus/gplus"
ginI18n "github.com/gin-contrib/i18n"
"github.com/gin-gonic/gin"
"github.com/mssola/useragent"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"schisandra-cloud-album/common/enum"
"schisandra-cloud-album/common/result"
"schisandra-cloud-album/global"
"schisandra-cloud-album/model"
"schisandra-cloud-album/mq"
"schisandra-cloud-album/service/impl"
"schisandra-cloud-album/utils"
"time"
)
type CommentController struct{}
var commentReplyService = impl.CommentReplyServiceImpl{}
// CommentSubmit 提交评论
// @Summary 提交评论
// @Description 提交评论
@@ -67,13 +63,6 @@ func (CommentController) CommentSubmit(c *gin.Context) {
isAuthor = 1
}
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
commentReply := model.ScaCommentReply{
Content: commentRequest.Content,
UserId: commentRequest.UserID,
@@ -87,56 +76,11 @@ func (CommentController) CommentSubmit(c *gin.Context) {
OperatingSystem: operatingSystem,
Agent: userAgent,
}
// 使用 goroutine 进行异步评论保存
errCh := make(chan error, 2)
go func() {
errCh <- commentReplyService.CreateCommentReplyService(&commentReply)
}()
// 等待评论回复的创建
if err = <-errCh; err != nil {
global.LOG.Errorln(err)
response := commentReplyService.SubmitCommentService(&commentReply, commentRequest.TopicId, commentRequest.UserID, commentRequest.Images)
if !response {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
tx.Rollback()
return
}
// 处理图片异步上传
if len(commentRequest.Images) > 0 {
imagesDataCh := make(chan [][]byte)
go func() {
imagesData, err := processImages(commentRequest.Images)
if err != nil {
global.LOG.Errorln(err)
imagesDataCh <- nil // 发送失败信号
return
}
imagesDataCh <- imagesData // 发送处理成功的数据
}()
imagesData := <-imagesDataCh
if imagesData == nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
tx.Rollback()
return
}
commentImages := CommentImages{
TopicId: commentRequest.TopicId,
CommentId: commentReply.Id,
UserId: commentRequest.UserID,
Images: imagesData,
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
// 使用 goroutine 进行异步图片保存
go func() {
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
global.LOG.Errorln(err)
}
}()
}
tx.Commit()
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
return
}
@@ -188,13 +132,6 @@ func (CommentController) ReplySubmit(c *gin.Context) {
isAuthor = 1
}
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
commentReply := model.ScaCommentReply{
Content: replyCommentRequest.Content,
UserId: replyCommentRequest.UserID,
@@ -210,60 +147,11 @@ func (CommentController) ReplySubmit(c *gin.Context) {
OperatingSystem: operatingSystem,
Agent: userAgent,
}
// 使用 goroutine 进行异步评论保存
errCh := make(chan error)
go func() {
errCh <- commentReplyService.CreateCommentReplyService(&commentReply)
}()
go func() {
errCh <- commentReplyService.UpdateCommentReplyCountService(replyCommentRequest.ReplyId)
}()
// 等待评论回复的创建
if err = <-errCh; err != nil {
global.LOG.Errorln(err)
response := commentReplyService.SubmitCommentService(&commentReply, replyCommentRequest.TopicId, replyCommentRequest.UserID, replyCommentRequest.Images)
if !response {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
tx.Rollback()
return
}
// 处理图片异步上传
if len(replyCommentRequest.Images) > 0 {
imagesDataCh := make(chan [][]byte)
go func() {
imagesData, err := processImages(replyCommentRequest.Images)
if err != nil {
global.LOG.Errorln(err)
imagesDataCh <- nil // 发送失败信号
return
}
imagesDataCh <- imagesData // 发送处理成功的数据
}()
imagesData := <-imagesDataCh
if imagesData == nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
tx.Rollback()
return
}
commentImages := CommentImages{
TopicId: replyCommentRequest.TopicId,
CommentId: commentReply.Id,
UserId: replyCommentRequest.UserID,
Images: imagesData,
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
// 使用 goroutine 进行异步图片保存
go func() {
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
global.LOG.Errorln(err)
}
}()
}
tx.Commit()
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
return
}
@@ -315,13 +203,6 @@ func (CommentController) ReplyReplySubmit(c *gin.Context) {
isAuthor = 1
}
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
commentReply := model.ScaCommentReply{
Content: replyReplyRequest.Content,
UserId: replyReplyRequest.UserID,
@@ -338,57 +219,11 @@ func (CommentController) ReplyReplySubmit(c *gin.Context) {
OperatingSystem: operatingSystem,
Agent: userAgent,
}
errCh := make(chan error, 2)
go func() {
errCh <- commentReplyService.CreateCommentReplyService(&commentReply)
}()
go func() {
errCh <- commentReplyService.UpdateCommentReplyCountService(replyReplyRequest.ReplyId)
}()
if err = <-errCh; err != nil {
global.LOG.Errorln(err)
response := commentReplyService.SubmitCommentService(&commentReply, replyReplyRequest.TopicId, replyReplyRequest.UserID, replyReplyRequest.Images)
if !response {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
tx.Rollback()
return
}
if len(replyReplyRequest.Images) > 0 {
imagesDataCh := make(chan [][]byte)
go func() {
imagesData, err := processImages(replyReplyRequest.Images)
if err != nil {
global.LOG.Errorln(err)
imagesDataCh <- nil
return
}
imagesDataCh <- imagesData
}()
imagesData := <-imagesDataCh
if imagesData == nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
tx.Rollback()
return
}
commentImages := CommentImages{
TopicId: replyReplyRequest.TopicId,
CommentId: commentReply.Id,
UserId: replyReplyRequest.UserID,
Images: imagesData,
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
// 处理图片保存
go func() {
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
global.LOG.Errorln(err)
}
}()
}
tx.Commit()
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
return
}
@@ -408,162 +243,7 @@ func (CommentController) CommentList(c *gin.Context) {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return
}
// 查询评论列表
query, u := gplus.NewQuery[model.ScaCommentReply]()
page := gplus.NewPage[model.ScaCommentReply](commentListRequest.Page, commentListRequest.Size)
if commentListRequest.IsHot {
query.OrderByDesc(&u.CommentOrder).OrderByDesc(&u.Likes).OrderByDesc(&u.ReplyCount)
} else {
query.OrderByDesc(&u.CommentOrder).OrderByDesc(&u.CreatedTime)
}
query.Eq(&u.TopicId, commentListRequest.TopicId).Eq(&u.CommentType, enum.COMMENT)
page, pageDB := gplus.SelectPage(page, query)
if pageDB.Error != nil {
global.LOG.Errorln(pageDB.Error)
return
}
if len(page.Records) == 0 {
result.OkWithData(CommentResponse{Comments: []CommentContent{}, Size: page.Size, Current: page.Current, Total: page.Total}, c)
return
}
userIds := make([]string, 0, len(page.Records))
commentIds := make([]int64, 0, len(page.Records))
for _, comment := range page.Records {
userIds = append(userIds, comment.UserId)
commentIds = append(commentIds, comment.Id)
}
// 结果存储
userInfoMap := make(map[string]model.ScaAuthUser)
likeMap := make(map[int64]bool)
commentImagesMap := make(map[int64]CommentImages)
// 使用 WaitGroup 等待协程完成
wg.Add(3)
// 查询评论用户信息
go func() {
defer wg.Done()
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
queryUser.Select(&n.UID, &n.Avatar, &n.Nickname).In(&n.UID, userIds)
userInfos, userInfosDB := gplus.SelectList(queryUser)
if userInfosDB.Error != nil {
global.LOG.Errorln(userInfosDB.Error)
return
}
for _, userInfo := range userInfos {
userInfoMap[*userInfo.UID] = *userInfo
}
}()
// 查询评论点赞状态
go func() {
defer wg.Done()
if len(page.Records) > 0 {
queryLike, l := gplus.NewQuery[model.ScaCommentLikes]()
queryLike.Eq(&l.TopicId, commentListRequest.TopicId).Eq(&l.UserId, commentListRequest.UserID).In(&l.CommentId, commentIds)
likes, likesDB := gplus.SelectList(queryLike)
if likesDB.Error != nil {
global.LOG.Errorln(likesDB.Error)
return
}
for _, like := range likes {
likeMap[like.CommentId] = true
}
}
}()
// 查询评论图片信息
go func() {
defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) // 设置超时2秒
defer cancel()
cursor, err := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").Find(ctx, bson.M{"comment_id": bson.M{"$in": commentIds}})
if err != nil {
global.LOG.Errorf("Failed to get images for comments: %v", err)
return
}
defer func(cursor *mongo.Cursor, ctx context.Context) {
err := cursor.Close(ctx)
if err != nil {
return
}
}(cursor, ctx)
for cursor.Next(ctx) {
var commentImages CommentImages
if err = cursor.Decode(&commentImages); err != nil {
global.LOG.Errorf("Failed to decode comment images: %v", err)
continue
}
commentImagesMap[commentImages.CommentId] = commentImages
}
}()
// 等待所有查询完成
wg.Wait()
commentChannel := make(chan CommentContent, len(page.Records))
for _, comment := range page.Records {
wg.Add(1)
go func(comment model.ScaCommentReply) {
defer wg.Done()
// 将图片转换为base64
var imagesBase64 []string
if imgData, ok := commentImagesMap[comment.Id]; ok {
// 将图片转换为base64
for _, img := range imgData.Images {
mimeType := getMimeType(img)
base64Img := base64.StdEncoding.EncodeToString(img)
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
imagesBase64 = append(imagesBase64, base64WithPrefix)
}
}
userInfo, exist := userInfoMap[comment.UserId]
if !exist {
global.LOG.Errorf("Failed to get user info for comment: %s", comment.UserId)
return
}
commentContent := CommentContent{
Avatar: *userInfo.Avatar,
NickName: *userInfo.Nickname,
Id: comment.Id,
UserId: comment.UserId,
TopicId: comment.TopicId,
Content: comment.Content,
ReplyCount: comment.ReplyCount,
Likes: comment.Likes,
CreatedTime: comment.CreatedTime,
Author: comment.Author,
Location: comment.Location,
Browser: comment.Browser,
OperatingSystem: comment.OperatingSystem,
Images: imagesBase64,
IsLiked: likeMap[comment.Id],
}
commentChannel <- commentContent
}(*comment)
}
go func() {
wg.Wait()
close(commentChannel)
}()
var commentsWithImages []CommentContent
for commentContent := range commentChannel {
commentsWithImages = append(commentsWithImages, commentContent)
}
response := CommentResponse{
Comments: commentsWithImages,
Size: page.Size,
Current: page.Current,
Total: page.Total,
}
response := commentReplyService.GetCommentListService(commentListRequest.UserID, commentListRequest.TopicId, commentListRequest.Page, commentListRequest.Size, commentListRequest.IsHot)
result.OkWithData(response, c)
return
}
@@ -583,168 +263,7 @@ func (CommentController) ReplyList(c *gin.Context) {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return
}
query, u := gplus.NewQuery[model.ScaCommentReply]()
page := gplus.NewPage[model.ScaCommentReply](replyListRequest.Page, replyListRequest.Size)
query.Eq(&u.TopicId, replyListRequest.TopicId).Eq(&u.ReplyId, replyListRequest.CommentId).Eq(&u.CommentType, enum.REPLY).OrderByDesc(&u.Likes).OrderByAsc(&u.CreatedTime)
page, pageDB := gplus.SelectPage(page, query)
if pageDB.Error != nil {
global.LOG.Errorln(pageDB.Error)
return
}
if len(page.Records) == 0 {
result.OkWithData(CommentResponse{Comments: []CommentContent{}, Size: page.Size, Current: page.Current, Total: page.Total}, c)
return
}
userIdsSet := make(map[string]struct{}) // 使用集合去重用户 ID
commentIds := make([]int64, 0, len(page.Records))
// 收集用户 ID 和评论 ID
for _, comment := range page.Records {
userIdsSet[comment.UserId] = struct{}{} // 去重
commentIds = append(commentIds, comment.Id)
if comment.ReplyUser != "" {
userIdsSet[comment.ReplyUser] = struct{}{} // 去重
}
}
// 将用户 ID 转换为切片
userIds := make([]string, 0, len(userIdsSet))
for userId := range userIdsSet {
userIds = append(userIds, userId)
}
likeMap := make(map[int64]bool, len(page.Records))
commentImagesMap := make(map[int64]CommentImages)
userInfoMap := make(map[string]model.ScaAuthUser, len(userIds))
wg.Add(3)
go func() {
defer wg.Done()
// 查询评论用户信息
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
queryUser.Select(&n.UID, &n.Avatar, &n.Nickname).In(&n.UID, userIds)
userInfos, userInfosDB := gplus.SelectList(queryUser)
if userInfosDB.Error != nil {
global.LOG.Errorln(userInfosDB.Error)
return
}
for _, userInfo := range userInfos {
userInfoMap[*userInfo.UID] = *userInfo
}
}()
go func() {
defer wg.Done()
// 查询评论点赞状态
if len(page.Records) > 0 {
queryLike, l := gplus.NewQuery[model.ScaCommentLikes]()
queryLike.Eq(&l.TopicId, replyListRequest.TopicId).Eq(&l.UserId, replyListRequest.UserID).In(&l.CommentId, commentIds)
likes, likesDB := gplus.SelectList(queryLike)
if likesDB.Error != nil {
global.LOG.Errorln(likesDB.Error)
return
}
for _, like := range likes {
likeMap[like.CommentId] = true
}
}
}()
go func() {
defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 设置超时2秒
defer cancel()
cursor, err := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").Find(ctx, bson.M{"comment_id": bson.M{"$in": commentIds}})
if err != nil {
global.LOG.Errorf("Failed to get images for comments: %v", err)
return
}
defer func(cursor *mongo.Cursor, ctx context.Context) {
warn := cursor.Close(ctx)
if warn != nil {
return
}
}(cursor, ctx)
for cursor.Next(ctx) {
var commentImages CommentImages
if e := cursor.Decode(&commentImages); e != nil {
global.LOG.Errorf("Failed to decode comment images: %v", e)
continue
}
commentImagesMap[commentImages.CommentId] = commentImages
}
}()
wg.Wait()
replyChannel := make(chan CommentContent, len(page.Records)) // 使用通道传递回复内容
for _, reply := range page.Records {
wg.Add(1)
go func(reply model.ScaCommentReply) {
defer wg.Done()
var imagesBase64 []string
if imgData, ok := commentImagesMap[reply.Id]; ok {
// 将图片转换为base64
for _, img := range imgData.Images {
mimeType := getMimeType(img)
base64Img := base64.StdEncoding.EncodeToString(img)
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
imagesBase64 = append(imagesBase64, base64WithPrefix)
}
}
userInfo, exist := userInfoMap[reply.UserId]
if !exist {
global.LOG.Errorf("Failed to get user info for comment: %s", reply.UserId)
return
}
replyUserInfo, e := userInfoMap[reply.ReplyUser]
if !e {
global.LOG.Errorf("Failed to get reply user info for comment: %s", reply.ReplyUser)
return
}
commentContent := CommentContent{
Avatar: *userInfo.Avatar,
NickName: *userInfo.Nickname,
Id: reply.Id,
UserId: reply.UserId,
TopicId: reply.TopicId,
Content: reply.Content,
ReplyUsername: *replyUserInfo.Nickname,
ReplyCount: reply.ReplyCount,
Likes: reply.Likes,
CreatedTime: reply.CreatedTime,
ReplyUser: reply.ReplyUser,
ReplyId: reply.ReplyId,
ReplyTo: reply.ReplyTo,
Author: reply.Author,
Location: reply.Location,
Browser: reply.Browser,
OperatingSystem: reply.OperatingSystem,
Images: imagesBase64,
IsLiked: likeMap[reply.Id],
}
replyChannel <- commentContent // 发送到通道
}(*reply)
}
go func() {
wg.Wait()
close(replyChannel) // 关闭通道
}()
var repliesWithImages []CommentContent
for replyContent := range replyChannel {
repliesWithImages = append(repliesWithImages, replyContent) // 从通道获取回复内容
}
response := CommentResponse{
Comments: repliesWithImages,
Size: page.Size,
Current: page.Current,
Total: page.Total,
}
response := commentReplyService.GetCommentReplyService(replyListRequest.UserID, replyListRequest.TopicId, replyListRequest.CommentId, replyListRequest.Page, replyListRequest.Size)
result.OkWithData(response, c)
return
}
@@ -764,44 +283,11 @@ func (CommentController) CommentLikes(c *gin.Context) {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return
}
mx.Lock()
defer mx.Unlock()
likes := model.ScaCommentLikes{
CommentId: likeRequest.CommentId,
UserId: likeRequest.UserID,
TopicId: likeRequest.TopicId,
}
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
res := global.DB.Create(&likes) // 假设这是插入数据库的方法
if res.Error != nil {
tx.Rollback()
global.LOG.Errorln(res.Error)
res := commentReplyService.CommentLikeService(likeRequest.UserID, likeRequest.CommentId, likeRequest.TopicId)
if !res {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentLikeFailed"), c)
return
}
// 异步更新点赞计数
go func() {
if err = commentReplyService.UpdateCommentLikesCountService(likeRequest.CommentId, likeRequest.TopicId); err != nil {
global.LOG.Errorln(err)
}
}()
marshal, err := json.Marshal(likes)
if err != nil {
global.LOG.Errorln(err)
return
}
mq.CommentLikeProducer(marshal)
tx.Commit()
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentLikeSuccess"), c)
return
}
@@ -820,34 +306,11 @@ func (CommentController) CancelCommentLikes(c *gin.Context) {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return
}
mx.Lock()
defer mx.Unlock()
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
query, u := gplus.NewQuery[model.ScaCommentLikes]()
query.Eq(&u.CommentId, cancelLikeRequest.CommentId).
Eq(&u.UserId, cancelLikeRequest.UserID).
Eq(&u.TopicId, cancelLikeRequest.TopicId)
res := gplus.Delete[model.ScaCommentLikes](query)
if res.Error != nil {
tx.Rollback()
return // 返回错误而非打印
res := commentReplyService.CommentDislikeService(cancelLikeRequest.UserID, cancelLikeRequest.CommentId, cancelLikeRequest.TopicId)
if !res {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentDislikeFailed"), c)
return
}
// 异步更新点赞计数
go func() {
if err := commentReplyService.DecrementCommentLikesCountService(cancelLikeRequest.CommentId, cancelLikeRequest.TopicId); err != nil {
global.LOG.Errorln(err)
}
}()
tx.Commit()
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentLikeCancelSuccess"), c)
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentDislikeSuccess"), c)
return
}