mirror of
https://github.com/openimsdk/open-im-server.git
synced 2025-12-19 12:47:06 +08:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
84d7591738
@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cronTaskCmd := cmd.NewCronTaskCmd()
|
cronTaskCmd := cmd.NewCronTaskCmd()
|
||||||
if err := cronTaskCmd.Exec(tools.StartCronTask); err != nil {
|
if err := cronTaskCmd.Exec(tools.StartTask); err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,15 +124,19 @@ api:
|
|||||||
# Session token
|
# Session token
|
||||||
# Configuration for Tencent COS
|
# Configuration for Tencent COS
|
||||||
# Configuration for Aliyun OSS
|
# Configuration for Aliyun OSS
|
||||||
|
# apiURL is the address of the api, the access address of the app, use s3 must be configured
|
||||||
|
# minio.endpoint can be configured as an intranet address,
|
||||||
|
# minio.signEndpoint is minio public network address
|
||||||
object:
|
object:
|
||||||
enable: "minio"
|
enable: "minio"
|
||||||
apiURL: http://127.0.0.1:10002/object/
|
apiURL: "http://127.0.0.1:10002"
|
||||||
minio:
|
minio:
|
||||||
bucket: "openim"
|
bucket: "openim"
|
||||||
endpoint: http://127.0.0.1:10005
|
endpoint: "http://127.0.0.1:10005"
|
||||||
accessKeyID: root
|
accessKeyID: "root"
|
||||||
secretAccessKey: openIM123
|
secretAccessKey: "openIM123"
|
||||||
sessionToken: ""
|
sessionToken: ""
|
||||||
|
signEndpoint: "http://127.0.0.1:10005"
|
||||||
cos:
|
cos:
|
||||||
bucketURL: "https://temp-1252357374.cos.ap-chengdu.myqcloud.com"
|
bucketURL: "https://temp-1252357374.cos.ap-chengdu.myqcloud.com"
|
||||||
secretID: ""
|
secretID: ""
|
||||||
@ -142,7 +146,7 @@ object:
|
|||||||
endpoint: "https://oss-cn-chengdu.aliyuncs.com"
|
endpoint: "https://oss-cn-chengdu.aliyuncs.com"
|
||||||
bucket: "demo-9999999"
|
bucket: "demo-9999999"
|
||||||
bucketURL: "https://demo-9999999.oss-cn-chengdu.aliyuncs.com"
|
bucketURL: "https://demo-9999999.oss-cn-chengdu.aliyuncs.com"
|
||||||
accessKeyID: root
|
accessKeyID: ""
|
||||||
accessKeySecret: ""
|
accessKeySecret: ""
|
||||||
sessionToken: ""
|
sessionToken: ""
|
||||||
|
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -25,7 +25,7 @@ require (
|
|||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
go.mongodb.org/mongo-driver v1.12.1
|
go.mongodb.org/mongo-driver v1.12.1
|
||||||
golang.org/x/image v0.9.0 // indirect
|
golang.org/x/image v0.11.0
|
||||||
google.golang.org/api v0.135.0
|
google.golang.org/api v0.135.0
|
||||||
google.golang.org/grpc v1.57.0
|
google.golang.org/grpc v1.57.0
|
||||||
google.golang.org/protobuf v1.31.0
|
google.golang.org/protobuf v1.31.0
|
||||||
@ -121,7 +121,7 @@ require (
|
|||||||
golang.org/x/oauth2 v0.10.0 // indirect
|
golang.org/x/oauth2 v0.10.0 // indirect
|
||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
golang.org/x/sys v0.10.0 // indirect
|
golang.org/x/sys v0.10.0 // indirect
|
||||||
golang.org/x/text v0.11.0 // indirect
|
golang.org/x/text v0.12.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
|||||||
8
go.sum
8
go.sum
@ -364,8 +364,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
|
|||||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
|
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
|
||||||
golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
|
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
@ -442,8 +442,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
|
|||||||
@ -83,7 +83,14 @@ func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
|
|||||||
operationID = strconv.Itoa(rand.Int())
|
operationID = strconv.Itoa(rand.Int())
|
||||||
}
|
}
|
||||||
ctx := mcontext.SetOperationID(c, operationID)
|
ctx := mcontext.SetOperationID(c, operationID)
|
||||||
resp, err := o.Client.AccessURL(ctx, &third.AccessURLReq{Name: name})
|
query := make(map[string]string)
|
||||||
|
for key, values := range c.Request.URL.Query() {
|
||||||
|
if len(values) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
query[key] = values[0]
|
||||||
|
}
|
||||||
|
resp, err := o.Client.AccessURL(ctx, &third.AccessURLReq{Name: name, Query: query})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errs.ErrArgs.Is(err) {
|
if errs.ErrArgs.Is(err) {
|
||||||
c.String(http.StatusBadRequest, err.Error())
|
c.String(http.StatusBadRequest, err.Error())
|
||||||
|
|||||||
@ -145,7 +145,7 @@ func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
|
|||||||
len(modifyMsgList),
|
len(modifyMsgList),
|
||||||
)
|
)
|
||||||
conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message)
|
conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message)
|
||||||
conversationIDNotification := msgprocessor.GetNotificationConversationID(ctxMsgList[0].message)
|
conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message)
|
||||||
och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList)
|
och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList)
|
||||||
och.handleNotification(
|
och.handleNotification(
|
||||||
ctx,
|
ctx,
|
||||||
|
|||||||
@ -161,6 +161,9 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbGroup.CreateGroupR
|
|||||||
if req.OwnerUserID == "" {
|
if req.OwnerUserID == "" {
|
||||||
return nil, errs.ErrArgs.Wrap("no group owner")
|
return nil, errs.ErrArgs.Wrap("no group owner")
|
||||||
}
|
}
|
||||||
|
if req.GroupInfo.GroupType != constant.WorkingGroup {
|
||||||
|
return nil, errs.ErrArgs.Wrap(fmt.Sprintf("group type %d not support", req.GroupInfo.GroupType))
|
||||||
|
}
|
||||||
if err := authverify.CheckAccessV3(ctx, req.OwnerUserID); err != nil {
|
if err := authverify.CheckAccessV3(ctx, req.OwnerUserID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -690,8 +693,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbGroup
|
|||||||
return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed")
|
return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed")
|
||||||
}
|
}
|
||||||
var inGroup bool
|
var inGroup bool
|
||||||
_, err = s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.FromUserID)
|
if _, err := s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil {
|
||||||
if err == nil {
|
|
||||||
inGroup = true // 已经在群里了
|
inGroup = true // 已经在群里了
|
||||||
} else if !s.IsNotFound(err) {
|
} else if !s.IsNotFound(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -718,6 +720,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbGroup
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.ZDebug(ctx, "GroupApplicationResponse", "inGroup", inGroup, "HandleResult", req.HandleResult, "member", member)
|
||||||
if err := s.GroupDatabase.HandlerGroupRequest(ctx, req.GroupID, req.FromUserID, req.HandledMsg, req.HandleResult, member); err != nil {
|
if err := s.GroupDatabase.HandlerGroupRequest(ctx, req.GroupID, req.FromUserID, req.HandledMsg, req.HandleResult, member); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -727,12 +730,14 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbGroup
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.Notification.GroupApplicationAcceptedNotification(ctx, req)
|
s.Notification.GroupApplicationAcceptedNotification(ctx, req)
|
||||||
|
if member == nil {
|
||||||
|
log.ZDebug(ctx, "GroupApplicationResponse", "member is nil")
|
||||||
|
} else {
|
||||||
|
s.Notification.MemberEnterNotification(ctx, req.GroupID, req.FromUserID)
|
||||||
|
}
|
||||||
case constant.GroupResponseRefuse:
|
case constant.GroupResponseRefuse:
|
||||||
s.Notification.GroupApplicationRejectedNotification(ctx, req)
|
s.Notification.GroupApplicationRejectedNotification(ctx, req)
|
||||||
}
|
}
|
||||||
if member != nil {
|
|
||||||
s.Notification.MemberEnterNotification(ctx, req)
|
|
||||||
}
|
|
||||||
return &pbGroup.GroupApplicationResponseResp{}, nil
|
return &pbGroup.GroupApplicationResponseResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,7 +783,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbGroup.JoinGroupReq)
|
|||||||
if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); err != nil {
|
if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.Notification.MemberEnterDirectlyNotification(ctx, req.GroupID, req.InviterUserID)
|
s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
groupRequest := relationTb.GroupRequestModel{
|
groupRequest := relationTb.GroupRequestModel{
|
||||||
|
|||||||
@ -116,41 +116,75 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
|
|||||||
if total, chatLogs, err = m.MsgDatabase.SearchMessage(ctx, req); err != nil {
|
if total, chatLogs, err = m.MsgDatabase.SearchMessage(ctx, req); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
sendIDs []string
|
||||||
|
recvIDs []string
|
||||||
|
groupIDs []string
|
||||||
|
sendMap = make(map[string]string)
|
||||||
|
recvMap = make(map[string]string)
|
||||||
|
groupMap = make(map[string]*sdkws.GroupInfo)
|
||||||
|
)
|
||||||
|
for _, chatLog := range chatLogs {
|
||||||
|
if chatLog.SenderNickname == "" {
|
||||||
|
sendIDs = append(sendIDs, chatLog.SendID)
|
||||||
|
}
|
||||||
|
switch chatLog.SessionType {
|
||||||
|
case constant.SingleChatType:
|
||||||
|
recvIDs = append(recvIDs, chatLog.RecvID)
|
||||||
|
case constant.GroupChatType, constant.SuperGroupChatType:
|
||||||
|
groupIDs = append(groupIDs, chatLog.GroupID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(sendIDs) != 0 {
|
||||||
|
sendInfos, err := m.User.GetUsersInfo(ctx, sendIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, sendInfo := range sendInfos {
|
||||||
|
sendMap[sendInfo.UserID] = sendInfo.Nickname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(recvIDs) != 0 {
|
||||||
|
recvInfos, err := m.User.GetUsersInfo(ctx, recvIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, recvInfo := range recvInfos {
|
||||||
|
recvMap[recvInfo.UserID] = recvInfo.Nickname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(groupIDs) != 0 {
|
||||||
|
groupInfos, err := m.Group.GetGroupInfos(ctx, groupIDs, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, groupInfo := range groupInfos {
|
||||||
|
groupMap[groupInfo.GroupID] = groupInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, chatLog := range chatLogs {
|
for _, chatLog := range chatLogs {
|
||||||
pbChatLog := &msg.ChatLog{}
|
pbChatLog := &msg.ChatLog{}
|
||||||
utils.CopyStructFields(pbChatLog, chatLog)
|
utils.CopyStructFields(pbChatLog, chatLog)
|
||||||
pbChatLog.SendTime = chatLog.SendTime
|
pbChatLog.SendTime = chatLog.SendTime
|
||||||
pbChatLog.CreateTime = chatLog.CreateTime
|
pbChatLog.CreateTime = chatLog.CreateTime
|
||||||
if chatLog.SenderNickname == "" {
|
if chatLog.SenderNickname == "" {
|
||||||
sendUser, err := m.User.GetUserInfo(ctx, chatLog.SendID)
|
pbChatLog.SenderNickname = sendMap[chatLog.SendID]
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pbChatLog.SenderNickname = sendUser.Nickname
|
|
||||||
}
|
}
|
||||||
switch chatLog.SessionType {
|
switch chatLog.SessionType {
|
||||||
case constant.SingleChatType:
|
case constant.SingleChatType:
|
||||||
recvUser, err := m.User.GetUserInfo(ctx, chatLog.RecvID)
|
pbChatLog.RecvNickname = recvMap[chatLog.RecvID]
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pbChatLog.RecvNickname = recvUser.Nickname
|
|
||||||
|
|
||||||
case constant.GroupChatType, constant.SuperGroupChatType:
|
case constant.GroupChatType, constant.SuperGroupChatType:
|
||||||
group, err := m.Group.GetGroupInfo(ctx, chatLog.GroupID)
|
pbChatLog.SenderFaceURL = groupMap[chatLog.GroupID].FaceURL
|
||||||
if err != nil {
|
pbChatLog.GroupMemberCount = groupMap[chatLog.GroupID].MemberCount
|
||||||
return nil, err
|
pbChatLog.RecvID = groupMap[chatLog.GroupID].GroupID
|
||||||
}
|
pbChatLog.GroupName = groupMap[chatLog.GroupID].GroupName
|
||||||
pbChatLog.SenderFaceURL = group.FaceURL
|
pbChatLog.GroupOwner = groupMap[chatLog.GroupID].OwnerUserID
|
||||||
pbChatLog.GroupMemberCount = group.MemberCount
|
pbChatLog.GroupType = groupMap[chatLog.GroupID].GroupType
|
||||||
pbChatLog.RecvID = group.GroupID
|
|
||||||
pbChatLog.GroupName = group.GroupName
|
|
||||||
pbChatLog.GroupOwner = group.OwnerUserID
|
|
||||||
pbChatLog.GroupType = group.GroupType
|
|
||||||
}
|
}
|
||||||
resp.ChatLogs = append(resp.ChatLogs, pbChatLog)
|
resp.ChatLogs = append(resp.ChatLogs, pbChatLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.ChatLogsNum = total
|
resp.ChatLogsNum = total
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,11 @@ package third
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/s3"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/third"
|
"github.com/OpenIMSDK/protocol/third"
|
||||||
"github.com/OpenIMSDK/tools/errs"
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
"github.com/OpenIMSDK/tools/log"
|
"github.com/OpenIMSDK/tools/log"
|
||||||
@ -152,7 +155,21 @@ func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *thirdServer) AccessURL(ctx context.Context, req *third.AccessURLReq) (*third.AccessURLResp, error) {
|
func (t *thirdServer) AccessURL(ctx context.Context, req *third.AccessURLReq) (*third.AccessURLResp, error) {
|
||||||
expireTime, rawURL, err := t.s3dataBase.AccessURL(ctx, req.Name, t.defaultExpire)
|
opt := &s3.AccessURLOption{}
|
||||||
|
if len(req.Query) > 0 {
|
||||||
|
switch req.Query["type"] {
|
||||||
|
case "":
|
||||||
|
case "image":
|
||||||
|
opt.Image = &s3.Image{}
|
||||||
|
opt.Image.Format = req.Query["format"]
|
||||||
|
opt.Image.Width, _ = strconv.Atoi(req.Query["width"])
|
||||||
|
opt.Image.Height, _ = strconv.Atoi(req.Query["height"])
|
||||||
|
log.ZDebug(ctx, "AccessURL image", "name", req.Name, "option", opt.Image)
|
||||||
|
default:
|
||||||
|
return nil, errs.ErrArgs.Wrap("invalid query type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expireTime, rawURL, err := t.s3dataBase.AccessURL(ctx, req.Name, t.defaultExpire, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
|
|||||||
if apiURL[len(apiURL)-1] != '/' {
|
if apiURL[len(apiURL)-1] != '/' {
|
||||||
apiURL += "/"
|
apiURL += "/"
|
||||||
}
|
}
|
||||||
|
apiURL += "object/"
|
||||||
rdb, err := cache.NewRedis()
|
rdb, err := cache.NewRedis()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -36,10 +36,11 @@ import (
|
|||||||
tablerelation "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
|
tablerelation "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
|
||||||
"github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient"
|
"github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient"
|
||||||
"github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient/notification"
|
"github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient/notification"
|
||||||
|
registry "github.com/OpenIMSDK/tools/discoveryregistry"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
pbuser "github.com/OpenIMSDK/protocol/user"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/tools/utils"
|
"github.com/OpenIMSDK/tools/utils"
|
||||||
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type userServer struct {
|
type userServer struct {
|
||||||
|
|||||||
@ -26,12 +26,13 @@ import (
|
|||||||
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
|
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StartCronTask() error {
|
func StartTask() error {
|
||||||
fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime)
|
fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime)
|
||||||
msgTool, err := InitMsgTool()
|
msgTool, err := InitMsgTool()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msgTool.ConvertTools()
|
||||||
c := cron.New()
|
c := cron.New()
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|||||||
32
internal/tools/msg_doc_convert.go
Normal file
32
internal/tools/msg_doc_convert.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/OpenIMSDK/Open-IM-Server/pkg/msgprocessor"
|
||||||
|
"github.com/OpenIMSDK/protocol/constant"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/OpenIMSDK/tools/mcontext"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *MsgTool) ConvertTools() {
|
||||||
|
ctx := mcontext.NewCtx("convert")
|
||||||
|
conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, "get all conversation ids failed", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, conversationID := range conversationIDs {
|
||||||
|
conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationIDByConversationID(conversationID))
|
||||||
|
}
|
||||||
|
userIDs, err := c.userDatabase.GetAllUserID(ctx, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, "get all user ids failed", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.ZDebug(ctx, "all userIDs", "len userIDs", len(userIDs))
|
||||||
|
for _, userID := range userIDs {
|
||||||
|
conversationIDs = append(conversationIDs, msgprocessor.GetConversationIDBySessionType(constant.SingleChatType, userID, userID))
|
||||||
|
conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationID(constant.SingleChatType, userID, userID))
|
||||||
|
}
|
||||||
|
log.ZDebug(ctx, "all conversationIDs", "len userIDs", len(conversationIDs))
|
||||||
|
c.msgDatabase.ConvertMsgsDocLen(ctx, conversationIDs)
|
||||||
|
}
|
||||||
@ -120,6 +120,7 @@ type configStruct struct {
|
|||||||
AccessKeyID string `yaml:"accessKeyID"`
|
AccessKeyID string `yaml:"accessKeyID"`
|
||||||
SecretAccessKey string `yaml:"secretAccessKey"`
|
SecretAccessKey string `yaml:"secretAccessKey"`
|
||||||
SessionToken string `yaml:"sessionToken"`
|
SessionToken string `yaml:"sessionToken"`
|
||||||
|
SignEndpoint string `yaml:"signEndpoint"`
|
||||||
} `yaml:"minio"`
|
} `yaml:"minio"`
|
||||||
Cos struct {
|
Cos struct {
|
||||||
BucketURL string `yaml:"bucketURL"`
|
BucketURL string `yaml:"bucketURL"`
|
||||||
|
|||||||
@ -386,8 +386,24 @@ func (g *groupDatabase) HandlerGroupRequest(
|
|||||||
handleResult int32,
|
handleResult int32,
|
||||||
member *relationTb.GroupMemberModel,
|
member *relationTb.GroupMemberModel,
|
||||||
) error {
|
) error {
|
||||||
cache := g.cache.NewCache()
|
//cache := g.cache.NewCache()
|
||||||
if err := g.tx.Transaction(func(tx any) error {
|
//if err := g.tx.Transaction(func(tx any) error {
|
||||||
|
// if err := g.groupRequestDB.NewTx(tx).UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if member != nil {
|
||||||
|
// if err := g.groupMemberDB.NewTx(tx).Create(ctx, []*relationTb.GroupMemberModel{member}); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// cache = cache.DelGroupMembersHash(groupID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID)
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
//}); err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//return cache.ExecDel(ctx)
|
||||||
|
|
||||||
|
return g.tx.Transaction(func(tx any) error {
|
||||||
if err := g.groupRequestDB.NewTx(tx).UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil {
|
if err := g.groupRequestDB.NewTx(tx).UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -395,13 +411,12 @@ func (g *groupDatabase) HandlerGroupRequest(
|
|||||||
if err := g.groupMemberDB.NewTx(tx).Create(ctx, []*relationTb.GroupMemberModel{member}); err != nil {
|
if err := g.groupMemberDB.NewTx(tx).Create(ctx, []*relationTb.GroupMemberModel{member}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cache = cache.DelGroupMembersHash(groupID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID)
|
if err := g.cache.NewCache().DelGroupMembersHash(groupID).DelGroupMembersInfo(groupID, member.UserID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID).ExecDel(ctx); err != nil {
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return cache.ExecDel(ctx)
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *groupDatabase) DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error {
|
func (g *groupDatabase) DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error {
|
||||||
|
|||||||
@ -118,6 +118,7 @@ type CommonMsgDatabase interface {
|
|||||||
pageNumber int32,
|
pageNumber int32,
|
||||||
showNumber int32,
|
showNumber int32,
|
||||||
) (msgCount int64, userCount int64, groups []*unRelationTb.GroupCount, dateCount map[string]int64, err error)
|
) (msgCount int64, userCount int64, groups []*unRelationTb.GroupCount, dateCount map[string]int64, err error)
|
||||||
|
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCommonMsgDatabase(msgDocModel unRelationTb.MsgDocModelInterface, cacheModel cache.MsgModel) CommonMsgDatabase {
|
func NewCommonMsgDatabase(msgDocModel unRelationTb.MsgDocModelInterface, cacheModel cache.MsgModel) CommonMsgDatabase {
|
||||||
@ -961,7 +962,14 @@ func (db *commonMsgDatabase) SearchMessage(ctx context.Context, req *pbMsg.Searc
|
|||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
for _, msg := range msgs {
|
for _, msg := range msgs {
|
||||||
|
if msg.IsRead {
|
||||||
|
msg.Msg.IsRead = true
|
||||||
|
}
|
||||||
totalMsgs = append(totalMsgs, convert.MsgDB2Pb(msg.Msg))
|
totalMsgs = append(totalMsgs, convert.MsgDB2Pb(msg.Msg))
|
||||||
}
|
}
|
||||||
return total, totalMsgs, nil
|
return total, totalMsgs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *commonMsgDatabase) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) {
|
||||||
|
db.msgDocDatabase.ConvertMsgsDocLen(ctx, conversationIDs)
|
||||||
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ type S3Database interface {
|
|||||||
AuthSign(ctx context.Context, uploadID string, partNumbers []int) (*s3.AuthSignResult, error)
|
AuthSign(ctx context.Context, uploadID string, partNumbers []int) (*s3.AuthSignResult, error)
|
||||||
InitiateMultipartUpload(ctx context.Context, hash string, size int64, expire time.Duration, maxParts int) (*cont.InitiateUploadResult, error)
|
InitiateMultipartUpload(ctx context.Context, hash string, size int64, expire time.Duration, maxParts int) (*cont.InitiateUploadResult, error)
|
||||||
CompleteMultipartUpload(ctx context.Context, uploadID string, parts []string) (*cont.UploadResult, error)
|
CompleteMultipartUpload(ctx context.Context, uploadID string, parts []string) (*cont.UploadResult, error)
|
||||||
AccessURL(ctx context.Context, name string, expire time.Duration) (time.Time, string, error)
|
AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (time.Time, string, error)
|
||||||
SetObject(ctx context.Context, info *relation.ObjectModel) error
|
SetObject(ctx context.Context, info *relation.ObjectModel) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,14 +70,19 @@ func (s *s3Database) SetObject(ctx context.Context, info *relation.ObjectModel)
|
|||||||
return s.obj.SetObject(ctx, info)
|
return s.obj.SetObject(ctx, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *s3Database) AccessURL(ctx context.Context, name string, expire time.Duration) (time.Time, string, error) {
|
func (s *s3Database) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (time.Time, string, error) {
|
||||||
obj, err := s.obj.Take(ctx, name)
|
obj, err := s.obj.Take(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return time.Time{}, "", err
|
return time.Time{}, "", err
|
||||||
}
|
}
|
||||||
opt := &s3.AccessURLOption{
|
if opt == nil {
|
||||||
ContentType: obj.ContentType,
|
opt = &s3.AccessURLOption{}
|
||||||
Filename: filepath.Base(obj.Name),
|
}
|
||||||
|
if opt.ContentType == "" {
|
||||||
|
opt.ContentType = obj.ContentType
|
||||||
|
}
|
||||||
|
if opt.Filename == "" {
|
||||||
|
opt.Filename = filepath.Base(obj.Name)
|
||||||
}
|
}
|
||||||
expireTime := time.Now().Add(expire)
|
expireTime := time.Now().Add(expire)
|
||||||
rawURL, err := s.s3.AccessURL(ctx, obj.Key, expire, opt)
|
rawURL, err := s.s3.AccessURL(ctx, obj.Key, expire, opt)
|
||||||
|
|||||||
@ -18,9 +18,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
|
|
||||||
"github.com/OpenIMSDK/protocol/user"
|
"github.com/OpenIMSDK/protocol/user"
|
||||||
|
|
||||||
|
unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/tools/errs"
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
"github.com/OpenIMSDK/tools/tx"
|
"github.com/OpenIMSDK/tools/tx"
|
||||||
"github.com/OpenIMSDK/tools/utils"
|
"github.com/OpenIMSDK/tools/utils"
|
||||||
|
|||||||
@ -86,7 +86,11 @@ func (u *UserGorm) Page(
|
|||||||
|
|
||||||
// 获取所有用户ID.
|
// 获取所有用户ID.
|
||||||
func (u *UserGorm) GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) {
|
func (u *UserGorm) GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) {
|
||||||
|
if pageNumber == 0 || showNumber == 0 {
|
||||||
|
return userIDs, errs.Wrap(u.db(ctx).Pluck("user_id", &userIDs).Error)
|
||||||
|
} else {
|
||||||
return userIDs, errs.Wrap(u.db(ctx).Limit(int(showNumber)).Offset(int((pageNumber-1)*showNumber)).Pluck("user_id", &userIDs).Error)
|
return userIDs, errs.Wrap(u.db(ctx).Limit(int(showNumber)).Offset(int((pageNumber-1)*showNumber)).Pluck("user_id", &userIDs).Error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserGorm) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) {
|
func (u *UserGorm) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) {
|
||||||
|
|||||||
@ -257,5 +257,9 @@ func (c *Controller) IsNotFound(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
func (c *Controller) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
||||||
|
if opt.Image != nil {
|
||||||
|
opt.Filename = ""
|
||||||
|
opt.ContentType = ""
|
||||||
|
}
|
||||||
return c.impl.AccessURL(ctx, name, expire, opt)
|
return c.impl.AccessURL(ctx, name, expire, opt)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,19 @@ const (
|
|||||||
maxNumSize = 1000
|
maxNumSize = 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
imagePng = "png"
|
||||||
|
imageJpg = "jpg"
|
||||||
|
imageJpeg = "jpeg"
|
||||||
|
imageGif = "gif"
|
||||||
|
imageWebp = "webp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
videoSnapshotImagePng = "png"
|
||||||
|
videoSnapshotImageJpg = "jpg"
|
||||||
|
)
|
||||||
|
|
||||||
func NewCos() (s3.Interface, error) {
|
func NewCos() (s3.Interface, error) {
|
||||||
conf := config.Config.Object.Cos
|
conf := config.Config.Object.Cos
|
||||||
u, err := url.Parse(conf.BucketURL)
|
u, err := url.Parse(conf.BucketURL)
|
||||||
@ -248,19 +261,44 @@ func (c *Cos) ListUploadedParts(ctx context.Context, uploadID string, name strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
||||||
var option *cos.PresignedURLOptions
|
var imageMogr string
|
||||||
|
var option cos.PresignedURLOptions
|
||||||
if opt != nil {
|
if opt != nil {
|
||||||
query := make(url.Values)
|
query := make(url.Values)
|
||||||
|
if opt.Image != nil {
|
||||||
|
// https://cloud.tencent.com/document/product/436/44880
|
||||||
|
style := make([]string, 0, 2)
|
||||||
|
wh := make([]string, 2)
|
||||||
|
if opt.Image.Width > 0 {
|
||||||
|
wh[0] = strconv.Itoa(opt.Image.Width)
|
||||||
|
}
|
||||||
|
if opt.Image.Height > 0 {
|
||||||
|
wh[1] = strconv.Itoa(opt.Image.Height)
|
||||||
|
}
|
||||||
|
if opt.Image.Width > 0 || opt.Image.Height > 0 {
|
||||||
|
style = append(style, strings.Join(wh, "x"))
|
||||||
|
}
|
||||||
|
switch opt.Image.Format {
|
||||||
|
case
|
||||||
|
imagePng,
|
||||||
|
imageJpg,
|
||||||
|
imageJpeg,
|
||||||
|
imageGif,
|
||||||
|
imageWebp:
|
||||||
|
style = append(style, "format/"+opt.Image.Format)
|
||||||
|
}
|
||||||
|
if len(style) > 0 {
|
||||||
|
imageMogr = "&imageMogr2/thumbnail/" + strings.Join(style, "/") + "/ignore-error/1"
|
||||||
|
}
|
||||||
|
}
|
||||||
if opt.ContentType != "" {
|
if opt.ContentType != "" {
|
||||||
query.Set("response-content-type", opt.ContentType)
|
query.Set("response-content-type", opt.ContentType)
|
||||||
}
|
}
|
||||||
if opt.Filename != "" {
|
if opt.Filename != "" {
|
||||||
query.Set("response-content-disposition", `attachment; filename="`+opt.Filename+`"`)
|
query.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename))
|
||||||
}
|
}
|
||||||
if len(query) > 0 {
|
if len(query) > 0 {
|
||||||
option = &cos.PresignedURLOptions{
|
option.Query = &query
|
||||||
Query: &query,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if expire <= 0 {
|
if expire <= 0 {
|
||||||
@ -268,9 +306,13 @@ func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration,
|
|||||||
} else if expire < time.Second {
|
} else if expire < time.Second {
|
||||||
expire = time.Second
|
expire = time.Second
|
||||||
}
|
}
|
||||||
rawURL, err := c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, option)
|
rawURL, err := c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, &option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return rawURL.String(), nil
|
urlStr := rawURL.String()
|
||||||
|
if imageMogr != "" {
|
||||||
|
urlStr += imageMogr
|
||||||
|
}
|
||||||
|
return urlStr, nil
|
||||||
}
|
}
|
||||||
|
|||||||
106
pkg/common/db/s3/minio/image.go
Normal file
106
pkg/common/db/s3/minio/image.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package minio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
_ "image/gif"
|
||||||
|
_ "image/jpeg"
|
||||||
|
_ "image/png"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
_ "golang.org/x/image/bmp"
|
||||||
|
_ "golang.org/x/image/tiff"
|
||||||
|
_ "golang.org/x/image/webp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
formatPng = "png"
|
||||||
|
formatJpeg = "jpeg"
|
||||||
|
formatJpg = "jpg"
|
||||||
|
formatGif = "gif"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ImageStat(reader io.Reader) (image.Image, string, error) {
|
||||||
|
return image.Decode(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImageWidthHeight(img image.Image) (int, int) {
|
||||||
|
bounds := img.Bounds().Max
|
||||||
|
return bounds.X, bounds.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image {
|
||||||
|
bounds := img.Bounds()
|
||||||
|
imgWidth := bounds.Max.X
|
||||||
|
imgHeight := bounds.Max.Y
|
||||||
|
|
||||||
|
// 计算缩放比例
|
||||||
|
scaleWidth := float64(maxWidth) / float64(imgWidth)
|
||||||
|
scaleHeight := float64(maxHeight) / float64(imgHeight)
|
||||||
|
|
||||||
|
// 如果都为0,则不缩放,返回原始图片
|
||||||
|
if maxWidth == 0 && maxHeight == 0 {
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果宽度和高度都大于0,则选择较小的缩放比例,以保持宽高比
|
||||||
|
if maxWidth > 0 && maxHeight > 0 {
|
||||||
|
scale := scaleWidth
|
||||||
|
if scaleHeight < scaleWidth {
|
||||||
|
scale = scaleHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算缩略图尺寸
|
||||||
|
thumbnailWidth := int(float64(imgWidth) * scale)
|
||||||
|
thumbnailHeight := int(float64(imgHeight) * scale)
|
||||||
|
|
||||||
|
// 使用"image"库的Resample方法生成缩略图
|
||||||
|
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
|
||||||
|
for y := 0; y < thumbnailHeight; y++ {
|
||||||
|
for x := 0; x < thumbnailWidth; x++ {
|
||||||
|
srcX := int(float64(x) / scale)
|
||||||
|
srcY := int(float64(y) / scale)
|
||||||
|
thumbnail.Set(x, y, img.At(srcX, srcY))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果只指定了宽度或高度,则根据最大不超过的规则生成缩略图
|
||||||
|
if maxWidth > 0 {
|
||||||
|
thumbnailWidth := maxWidth
|
||||||
|
thumbnailHeight := int(float64(imgHeight) * scaleWidth)
|
||||||
|
|
||||||
|
// 使用"image"库的Resample方法生成缩略图
|
||||||
|
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
|
||||||
|
for y := 0; y < thumbnailHeight; y++ {
|
||||||
|
for x := 0; x < thumbnailWidth; x++ {
|
||||||
|
srcX := int(float64(x) / scaleWidth)
|
||||||
|
srcY := int(float64(y) / scaleWidth)
|
||||||
|
thumbnail.Set(x, y, img.At(srcX, srcY))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxHeight > 0 {
|
||||||
|
thumbnailWidth := int(float64(imgWidth) * scaleHeight)
|
||||||
|
thumbnailHeight := maxHeight
|
||||||
|
|
||||||
|
// 使用"image"库的Resample方法生成缩略图
|
||||||
|
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
|
||||||
|
for y := 0; y < thumbnailHeight; y++ {
|
||||||
|
for x := 0; x < thumbnailWidth; x++ {
|
||||||
|
srcX := int(float64(x) / scaleHeight)
|
||||||
|
srcY := int(float64(y) / scaleHeight)
|
||||||
|
thumbnail.Set(x, y, img.At(srcX, srcY))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认情况下,返回原始图片
|
||||||
|
return img
|
||||||
|
}
|
||||||
@ -15,16 +15,28 @@
|
|||||||
package minio
|
package minio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/gif"
|
||||||
|
"image/jpeg"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
"github.com/minio/minio-go/v7"
|
"github.com/minio/minio-go/v7"
|
||||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||||
"github.com/minio/minio-go/v7/pkg/signer"
|
"github.com/minio/minio-go/v7/pkg/signer"
|
||||||
@ -43,6 +55,13 @@ const (
|
|||||||
maxNumSize = 10000
|
maxNumSize = 10000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxImageWidth = 1024
|
||||||
|
maxImageHeight = 1024
|
||||||
|
maxImageSize = 1024 * 1024 * 50
|
||||||
|
pathInfo = "openim/thumbnail"
|
||||||
|
)
|
||||||
|
|
||||||
func NewMinio() (s3.Interface, error) {
|
func NewMinio() (s3.Interface, error) {
|
||||||
conf := config.Config.Object.Minio
|
conf := config.Config.Object.Minio
|
||||||
u, err := url.Parse(conf.Endpoint)
|
u, err := url.Parse(conf.Endpoint)
|
||||||
@ -60,11 +79,26 @@ func NewMinio() (s3.Interface, error) {
|
|||||||
m := &Minio{
|
m := &Minio{
|
||||||
bucket: conf.Bucket,
|
bucket: conf.Bucket,
|
||||||
bucketURL: conf.Endpoint + "/" + conf.Bucket + "/",
|
bucketURL: conf.Endpoint + "/" + conf.Bucket + "/",
|
||||||
opts: opts,
|
|
||||||
core: &minio.Core{Client: client},
|
core: &minio.Core{Client: client},
|
||||||
lock: &sync.Mutex{},
|
lock: &sync.Mutex{},
|
||||||
init: false,
|
init: false,
|
||||||
}
|
}
|
||||||
|
if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint {
|
||||||
|
m.sign = m.core.Client
|
||||||
|
} else {
|
||||||
|
su, err := url.Parse(conf.SignEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m.opts = &minio.Options{
|
||||||
|
Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken),
|
||||||
|
Secure: su.Scheme == "https",
|
||||||
|
}
|
||||||
|
m.sign, err = minio.New(su.Host, m.opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if err := m.initMinio(ctx); err != nil {
|
if err := m.initMinio(ctx); err != nil {
|
||||||
@ -76,8 +110,10 @@ func NewMinio() (s3.Interface, error) {
|
|||||||
type Minio struct {
|
type Minio struct {
|
||||||
bucket string
|
bucket string
|
||||||
bucketURL string
|
bucketURL string
|
||||||
|
location string
|
||||||
opts *minio.Options
|
opts *minio.Options
|
||||||
core *minio.Core
|
core *minio.Core
|
||||||
|
sign *minio.Client
|
||||||
lock sync.Locker
|
lock sync.Locker
|
||||||
init bool
|
init bool
|
||||||
}
|
}
|
||||||
@ -91,15 +127,43 @@ func (m *Minio) initMinio(ctx context.Context) error {
|
|||||||
if m.init {
|
if m.init {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
exists, err := m.core.Client.BucketExists(ctx, config.Config.Object.Minio.Bucket)
|
conf := config.Config.Object.Minio
|
||||||
|
exists, err := m.core.Client.BucketExists(ctx, conf.Bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("check bucket exists error: %w", err)
|
return fmt.Errorf("check bucket exists error: %w", err)
|
||||||
}
|
}
|
||||||
if !exists {
|
if !exists {
|
||||||
if err := m.core.Client.MakeBucket(ctx, config.Config.Object.Minio.Bucket, minio.MakeBucketOptions{}); err != nil {
|
if err := m.core.Client.MakeBucket(ctx, conf.Bucket, minio.MakeBucketOptions{}); err != nil {
|
||||||
return fmt.Errorf("make bucket error: %w", err)
|
return fmt.Errorf("make bucket error: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m.location, err = m.core.Client.GetBucketLocation(ctx, conf.Bucket)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func() {
|
||||||
|
if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
m.sign = m.core.Client
|
||||||
|
log.ZWarn(
|
||||||
|
context.Background(),
|
||||||
|
"set sign bucket location cache panic",
|
||||||
|
errors.New("failed to get private field value"),
|
||||||
|
"recover",
|
||||||
|
fmt.Sprintf("%+v", r),
|
||||||
|
"development version",
|
||||||
|
"github.com/minio/minio-go/v7 v7.0.61",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
blc := reflect.ValueOf(m.sign).Elem().FieldByName("bucketLocCache")
|
||||||
|
vblc := reflect.New(reflect.PtrTo(blc.Type()))
|
||||||
|
*(*unsafe.Pointer)(vblc.UnsafePointer()) = unsafe.Pointer(blc.UnsafeAddr())
|
||||||
|
vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(conf.Bucket, m.location)
|
||||||
|
}()
|
||||||
m.init = true
|
m.init = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -191,7 +255,7 @@ func (m *Minio) AuthSign(ctx context.Context, uploadID string, name string, expi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
request.Header.Set("X-Amz-Content-Sha256", unsignedPayload)
|
request.Header.Set("X-Amz-Content-Sha256", unsignedPayload)
|
||||||
request = signer.SignV4Trailer(*request, creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken, "us-east-1", nil)
|
request = signer.SignV4Trailer(*request, creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken, m.location, nil)
|
||||||
result.Parts[i] = s3.SignPart{
|
result.Parts[i] = s3.SignPart{
|
||||||
PartNumber: partNumber,
|
PartNumber: partNumber,
|
||||||
URL: request.URL.String(),
|
URL: request.URL.String(),
|
||||||
@ -206,7 +270,7 @@ func (m *Minio) PresignedPutObject(ctx context.Context, name string, expire time
|
|||||||
if err := m.initMinio(ctx); err != nil {
|
if err := m.initMinio(ctx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
rawURL, err := m.core.Client.PresignedPutObject(ctx, m.bucket, name, expire)
|
rawURL, err := m.sign.PresignedPutObject(ctx, m.bucket, name, expire)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -303,6 +367,19 @@ func (m *Minio) ListUploadedParts(ctx context.Context, uploadID string, name str
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Minio) presignedGetObject(ctx context.Context, name string, expire time.Duration, query url.Values) (string, error) {
|
||||||
|
if expire <= 0 {
|
||||||
|
expire = time.Hour * 24 * 365 * 99 // 99 years
|
||||||
|
} else if expire < time.Second {
|
||||||
|
expire = time.Second
|
||||||
|
}
|
||||||
|
rawURL, err := m.sign.PresignedGetObject(ctx, m.bucket, name, expire, query)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return rawURL.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Minio) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
func (m *Minio) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
||||||
if err := m.initMinio(ctx); err != nil {
|
if err := m.initMinio(ctx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -313,17 +390,123 @@ func (m *Minio) AccessURL(ctx context.Context, name string, expire time.Duration
|
|||||||
reqParams.Set("response-content-type", opt.ContentType)
|
reqParams.Set("response-content-type", opt.ContentType)
|
||||||
}
|
}
|
||||||
if opt.Filename != "" {
|
if opt.Filename != "" {
|
||||||
reqParams.Set("response-content-disposition", `attachment; filename="`+opt.Filename+`"`)
|
reqParams.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if expire <= 0 {
|
if opt.Image == nil || (opt.Image.Width < 0 && opt.Image.Height < 0 && opt.Image.Format == "") || (opt.Image.Width > maxImageWidth || opt.Image.Height > maxImageHeight) {
|
||||||
expire = time.Hour * 24 * 365 * 99 // 99 years
|
return m.presignedGetObject(ctx, name, expire, reqParams)
|
||||||
} else if expire < time.Second {
|
|
||||||
expire = time.Second
|
|
||||||
}
|
}
|
||||||
u, err := m.core.Client.PresignedGetObject(ctx, m.bucket, name, expire, reqParams)
|
fileInfo, err := m.StatObject(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return u.String(), nil
|
if fileInfo.Size > maxImageSize {
|
||||||
|
return "", errors.New("file size too large")
|
||||||
|
}
|
||||||
|
objectInfoPath := path.Join(pathInfo, fileInfo.ETag, "image.json")
|
||||||
|
var (
|
||||||
|
img image.Image
|
||||||
|
info minioImageInfo
|
||||||
|
)
|
||||||
|
data, err := m.getObjectData(ctx, objectInfoPath, 1024)
|
||||||
|
if err == nil {
|
||||||
|
if err := json.Unmarshal(data, &info); err != nil {
|
||||||
|
return "", fmt.Errorf("unmarshal minio image info.json error: %w", err)
|
||||||
|
}
|
||||||
|
if info.NotImage {
|
||||||
|
return "", errors.New("not image")
|
||||||
|
}
|
||||||
|
} else if m.IsNotFound(err) {
|
||||||
|
reader, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
imageInfo, format, err := ImageStat(reader)
|
||||||
|
if err == nil {
|
||||||
|
info.NotImage = false
|
||||||
|
info.Format = format
|
||||||
|
info.Width, info.Height = ImageWidthHeight(imageInfo)
|
||||||
|
img = imageInfo
|
||||||
|
} else {
|
||||||
|
info.NotImage = true
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(&info)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if _, err := m.core.Client.PutObject(ctx, m.bucket, objectInfoPath, bytes.NewReader(data), int64(len(data)), minio.PutObjectOptions{}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if opt.Image.Width > info.Width || opt.Image.Width <= 0 {
|
||||||
|
opt.Image.Width = info.Width
|
||||||
|
}
|
||||||
|
if opt.Image.Height > info.Height || opt.Image.Height <= 0 {
|
||||||
|
opt.Image.Height = info.Height
|
||||||
|
}
|
||||||
|
opt.Image.Format = strings.ToLower(opt.Image.Format)
|
||||||
|
if opt.Image.Format == formatJpg {
|
||||||
|
opt.Image.Format = formatJpeg
|
||||||
|
}
|
||||||
|
switch opt.Image.Format {
|
||||||
|
case formatPng:
|
||||||
|
case formatJpeg:
|
||||||
|
case formatGif:
|
||||||
|
default:
|
||||||
|
if info.Format == formatGif {
|
||||||
|
opt.Image.Format = formatGif
|
||||||
|
} else {
|
||||||
|
opt.Image.Format = formatJpeg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reqParams.Set("response-content-type", "image/"+opt.Image.Format)
|
||||||
|
if opt.Image.Width == info.Width && opt.Image.Height == info.Height && opt.Image.Format == info.Format {
|
||||||
|
return m.presignedGetObject(ctx, name, expire, reqParams)
|
||||||
|
}
|
||||||
|
cacheKey := filepath.Join(pathInfo, fileInfo.ETag, fmt.Sprintf("image_w%d_h%d.%s", opt.Image.Width, opt.Image.Height, opt.Image.Format))
|
||||||
|
if _, err := m.core.Client.StatObject(ctx, m.bucket, cacheKey, minio.StatObjectOptions{}); err == nil {
|
||||||
|
return m.presignedGetObject(ctx, cacheKey, expire, reqParams)
|
||||||
|
} else if !m.IsNotFound(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if img == nil {
|
||||||
|
reader, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
img, _, err = ImageStat(reader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thumbnail := resizeImage(img, opt.Image.Width, opt.Image.Height)
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
switch opt.Image.Format {
|
||||||
|
case formatPng:
|
||||||
|
err = png.Encode(buf, thumbnail)
|
||||||
|
case formatJpeg:
|
||||||
|
err = jpeg.Encode(buf, thumbnail, nil)
|
||||||
|
case formatGif:
|
||||||
|
err = gif.Encode(buf, thumbnail, nil)
|
||||||
|
}
|
||||||
|
if _, err := m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return m.presignedGetObject(ctx, cacheKey, expire, reqParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Minio) getObjectData(ctx context.Context, name string, limit int64) ([]byte, error) {
|
||||||
|
object, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer object.Close()
|
||||||
|
if limit < 0 {
|
||||||
|
return io.ReadAll(object)
|
||||||
|
}
|
||||||
|
return io.ReadAll(io.LimitReader(object, 1024))
|
||||||
}
|
}
|
||||||
|
|||||||
8
pkg/common/db/s3/minio/struct.go
Normal file
8
pkg/common/db/s3/minio/struct.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package minio
|
||||||
|
|
||||||
|
type minioImageInfo struct {
|
||||||
|
NotImage bool `json:"notImage,omitempty"`
|
||||||
|
Width int `json:"width,omitempty"`
|
||||||
|
Height int `json:"height,omitempty"`
|
||||||
|
Format string `json:"format,omitempty"`
|
||||||
|
}
|
||||||
@ -36,6 +36,19 @@ const (
|
|||||||
maxNumSize = 10000
|
maxNumSize = 10000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
imagePng = "png"
|
||||||
|
imageJpg = "jpg"
|
||||||
|
imageJpeg = "jpeg"
|
||||||
|
imageGif = "gif"
|
||||||
|
imageWebp = "webp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
videoSnapshotImagePng = "png"
|
||||||
|
videoSnapshotImageJpg = "jpg"
|
||||||
|
)
|
||||||
|
|
||||||
func NewOSS() (s3.Interface, error) {
|
func NewOSS() (s3.Interface, error) {
|
||||||
conf := config.Config.Object.Oss
|
conf := config.Config.Object.Oss
|
||||||
if conf.BucketURL == "" {
|
if conf.BucketURL == "" {
|
||||||
@ -139,7 +152,7 @@ func (o *OSS) AuthSign(ctx context.Context, uploadID string, name string, expire
|
|||||||
}
|
}
|
||||||
for i, partNumber := range partNumbers {
|
for i, partNumber := range partNumbers {
|
||||||
rawURL := fmt.Sprintf(`%s%s?partNumber=%d&uploadId=%s`, o.bucketURL, name, partNumber, uploadID)
|
rawURL := fmt.Sprintf(`%s%s?partNumber=%d&uploadId=%s`, o.bucketURL, name, partNumber, uploadID)
|
||||||
request, err := http.NewRequestWithContext(ctx, http.MethodPut, rawURL, nil)
|
request, err := http.NewRequest(http.MethodPut, rawURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -150,12 +163,7 @@ func (o *OSS) AuthSign(ctx context.Context, uploadID string, name string, expire
|
|||||||
request.Header.Set(oss.HTTPHeaderHost, request.Host)
|
request.Header.Set(oss.HTTPHeaderHost, request.Host)
|
||||||
request.Header.Set(oss.HTTPHeaderDate, now)
|
request.Header.Set(oss.HTTPHeaderDate, now)
|
||||||
request.Header.Set(oss.HttpHeaderOssDate, now)
|
request.Header.Set(oss.HttpHeaderOssDate, now)
|
||||||
authorization := fmt.Sprintf(
|
ossSignHeader(o.bucket.Client.Conn, request, fmt.Sprintf(`/%s/%s?partNumber=%d&uploadId=%s`, o.bucket.BucketName, name, partNumber, uploadID))
|
||||||
`OSS %s:%s`,
|
|
||||||
o.credentials.GetAccessKeyID(),
|
|
||||||
o.getSignedStr(request, fmt.Sprintf(`/%s/%s?partNumber=%d&uploadId=%s`, o.bucket.BucketName, name, partNumber, uploadID), o.credentials.GetAccessKeySecret()),
|
|
||||||
)
|
|
||||||
request.Header.Set(oss.HTTPHeaderAuthorization, authorization)
|
|
||||||
delete(request.Header, oss.HTTPHeaderDate)
|
delete(request.Header, oss.HTTPHeaderDate)
|
||||||
result.Parts[i] = s3.SignPart{
|
result.Parts[i] = s3.SignPart{
|
||||||
PartNumber: partNumber,
|
PartNumber: partNumber,
|
||||||
@ -266,11 +274,36 @@ func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name strin
|
|||||||
func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
||||||
var opts []oss.Option
|
var opts []oss.Option
|
||||||
if opt != nil {
|
if opt != nil {
|
||||||
|
if opt.Image != nil {
|
||||||
|
// 文档地址: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji
|
||||||
|
var format string
|
||||||
|
switch opt.Image.Format {
|
||||||
|
case
|
||||||
|
imagePng,
|
||||||
|
imageJpg,
|
||||||
|
imageJpeg,
|
||||||
|
imageGif,
|
||||||
|
imageWebp:
|
||||||
|
format = opt.Image.Format
|
||||||
|
default:
|
||||||
|
opt.Image.Format = imageJpg
|
||||||
|
}
|
||||||
|
// https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/example.jpg?x-oss-process=image/resize,h_100,m_lfit
|
||||||
|
process := "image/resize,m_lfit"
|
||||||
|
if opt.Image.Width > 0 {
|
||||||
|
process += ",w_" + strconv.Itoa(opt.Image.Width)
|
||||||
|
}
|
||||||
|
if opt.Image.Height > 0 {
|
||||||
|
process += ",h_" + strconv.Itoa(opt.Image.Height)
|
||||||
|
}
|
||||||
|
process += ",format," + format
|
||||||
|
opts = append(opts, oss.Process(process))
|
||||||
|
}
|
||||||
if opt.ContentType != "" {
|
if opt.ContentType != "" {
|
||||||
opts = append(opts, oss.ResponseContentType(opt.ContentType))
|
opts = append(opts, oss.ResponseContentType(opt.ContentType))
|
||||||
}
|
}
|
||||||
if opt.Filename != "" {
|
if opt.Filename != "" {
|
||||||
opts = append(opts, oss.ResponseContentDisposition(`attachment; filename="`+opt.Filename+`"`))
|
opts = append(opts, oss.ResponseContentDisposition(`attachment; filename=`+strconv.Quote(opt.Filename)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if expire <= 0 {
|
if expire <= 0 {
|
||||||
|
|||||||
@ -1,96 +1,11 @@
|
|||||||
// Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package oss
|
package oss
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha1"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
_ "unsafe"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (o *OSS) getAdditionalHeaderKeys(req *http.Request) ([]string, map[string]string) {
|
//go:linkname ossSignHeader github.com/aliyun/aliyun-oss-go-sdk/oss.(*Conn).signHeader
|
||||||
var keysList []string
|
func ossSignHeader(c *oss.Conn, req *http.Request, canonicalizedResource string)
|
||||||
keysMap := make(map[string]string)
|
|
||||||
srcKeys := make(map[string]string)
|
|
||||||
|
|
||||||
for k := range req.Header {
|
|
||||||
srcKeys[strings.ToLower(k)] = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range o.bucket.Client.Config.AdditionalHeaders {
|
|
||||||
if _, ok := srcKeys[strings.ToLower(v)]; ok {
|
|
||||||
keysMap[strings.ToLower(v)] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for k := range keysMap {
|
|
||||||
keysList = append(keysList, k)
|
|
||||||
}
|
|
||||||
sort.Strings(keysList)
|
|
||||||
return keysList, keysMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *OSS) getSignedStr(req *http.Request, canonicalizedResource string, keySecret string) string {
|
|
||||||
// Find out the "x-oss-"'s address in header of the request
|
|
||||||
ossHeadersMap := make(map[string]string)
|
|
||||||
additionalList, additionalMap := o.getAdditionalHeaderKeys(req)
|
|
||||||
for k, v := range req.Header {
|
|
||||||
if strings.HasPrefix(strings.ToLower(k), "x-oss-") {
|
|
||||||
ossHeadersMap[strings.ToLower(k)] = v[0]
|
|
||||||
} else if o.bucket.Client.Config.AuthVersion == oss.AuthV2 {
|
|
||||||
if _, ok := additionalMap[strings.ToLower(k)]; ok {
|
|
||||||
ossHeadersMap[strings.ToLower(k)] = v[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hs := newHeaderSorter(ossHeadersMap)
|
|
||||||
|
|
||||||
// Sort the ossHeadersMap by the ascending order
|
|
||||||
hs.Sort()
|
|
||||||
|
|
||||||
// Get the canonicalizedOSSHeaders
|
|
||||||
canonicalizedOSSHeaders := ""
|
|
||||||
for i := range hs.Keys {
|
|
||||||
canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give other parameters values
|
|
||||||
// when sign URL, date is expires
|
|
||||||
date := req.Header.Get(oss.HTTPHeaderDate)
|
|
||||||
contentType := req.Header.Get(oss.HTTPHeaderContentType)
|
|
||||||
contentMd5 := req.Header.Get(oss.HTTPHeaderContentMD5)
|
|
||||||
|
|
||||||
// default is v1 signature
|
|
||||||
signStr := req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource
|
|
||||||
h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(keySecret))
|
|
||||||
|
|
||||||
// v2 signature
|
|
||||||
if o.bucket.Client.Config.AuthVersion == oss.AuthV2 {
|
|
||||||
signStr = req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + strings.Join(additionalList, ";") + "\n" + canonicalizedResource
|
|
||||||
h = hmac.New(func() hash.Hash { return sha256.New() }, []byte(keySecret))
|
|
||||||
}
|
|
||||||
_, _ = io.WriteString(h, signStr)
|
|
||||||
signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
|
|
||||||
|
|
||||||
return signedStr
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,61 +0,0 @@
|
|||||||
// Copyright © 2023 OpenIM. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package oss
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
// headerSorter defines the key-value structure for storing the sorted data in signHeader.
|
|
||||||
type headerSorter struct {
|
|
||||||
Keys []string
|
|
||||||
Vals []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// newHeaderSorter is an additional function for function SignHeader.
|
|
||||||
func newHeaderSorter(m map[string]string) *headerSorter {
|
|
||||||
hs := &headerSorter{
|
|
||||||
Keys: make([]string, 0, len(m)),
|
|
||||||
Vals: make([]string, 0, len(m)),
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range m {
|
|
||||||
hs.Keys = append(hs.Keys, k)
|
|
||||||
hs.Vals = append(hs.Vals, v)
|
|
||||||
}
|
|
||||||
return hs
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort is an additional function for function SignHeader.
|
|
||||||
func (hs *headerSorter) Sort() {
|
|
||||||
sort.Sort(hs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len is an additional function for function SignHeader.
|
|
||||||
func (hs *headerSorter) Len() int {
|
|
||||||
return len(hs.Vals)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Less is an additional function for function SignHeader.
|
|
||||||
func (hs *headerSorter) Less(i, j int) bool {
|
|
||||||
return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap is an additional function for function SignHeader.
|
|
||||||
func (hs *headerSorter) Swap(i, j int) {
|
|
||||||
hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i]
|
|
||||||
hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i]
|
|
||||||
}
|
|
||||||
@ -116,9 +116,16 @@ type ListUploadedPartsResult struct {
|
|||||||
UploadedParts []UploadedPart `xml:"Part"`
|
UploadedParts []UploadedPart `xml:"Part"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
Format string `json:"format"`
|
||||||
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessURLOption struct {
|
type AccessURLOption struct {
|
||||||
ContentType string `json:"contentType"`
|
ContentType string `json:"contentType"`
|
||||||
Filename string `json:"filename"`
|
Filename string `json:"filename"`
|
||||||
|
Image *Image `json:"image"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
|
|||||||
@ -27,7 +27,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
singleGocMsgNum = 5000
|
singleGocMsgNum = 100
|
||||||
|
singleGocMsgNum5000 = 5000
|
||||||
Msg = "msg"
|
Msg = "msg"
|
||||||
OldestList = 0
|
OldestList = 0
|
||||||
NewestList = -1
|
NewestList = -1
|
||||||
@ -128,6 +129,7 @@ type MsgDocModelInterface interface {
|
|||||||
pageNumber int32,
|
pageNumber int32,
|
||||||
showNumber int32,
|
showNumber int32,
|
||||||
) (msgCount int64, userCount int64, groups []*GroupCount, dateCount map[string]int64, err error)
|
) (msgCount int64, userCount int64, groups []*GroupCount, dateCount map[string]int64, err error)
|
||||||
|
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (MsgDocModel) TableName() string {
|
func (MsgDocModel) TableName() string {
|
||||||
@ -138,6 +140,10 @@ func (MsgDocModel) GetSingleGocMsgNum() int64 {
|
|||||||
return singleGocMsgNum
|
return singleGocMsgNum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (MsgDocModel) GetSingleGocMsgNum5000() int64 {
|
||||||
|
return singleGocMsgNum5000
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MsgDocModel) IsFull() bool {
|
func (m *MsgDocModel) IsFull() bool {
|
||||||
return m.Msg[len(m.Msg)-1].Msg != nil
|
return m.Msg[len(m.Msg)-1].Msg != nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1073,11 +1073,6 @@ func (m *MsgMongoDriver) SearchMessage(ctx context.Context, req *msg.SearchMessa
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
for _, msg1 := range msgs {
|
|
||||||
if msg1.IsRead {
|
|
||||||
msg1.Msg.IsRead = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return total, msgs, nil
|
return total, msgs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1151,13 +1146,22 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
|
|||||||
{"doc_id", 1},
|
{"doc_id", 1},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
{"$unwind", bson.M{"path": "$msgs"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{"$sort", bson.M{"msgs.msg.send_time": -1}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
cursor, err := m.MsgCollection.Aggregate(ctx, pipe)
|
cursor, err := m.MsgCollection.Aggregate(ctx, pipe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
type docModel struct {
|
||||||
var msgsDocs []table.MsgDocModel
|
DocID string `bson:"doc_id"`
|
||||||
|
Msg *table.MsgInfoModel `bson:"msgs"`
|
||||||
|
}
|
||||||
|
var msgsDocs []docModel
|
||||||
err = cursor.All(ctx, &msgsDocs)
|
err = cursor.All(ctx, &msgsDocs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
@ -1167,24 +1171,23 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
|
|||||||
}
|
}
|
||||||
msgs := make([]*table.MsgInfoModel, 0)
|
msgs := make([]*table.MsgInfoModel, 0)
|
||||||
for index := range msgsDocs {
|
for index := range msgsDocs {
|
||||||
for i := range msgsDocs[index].Msg {
|
msgInfo := msgsDocs[index].Msg
|
||||||
msg := msgsDocs[index].Msg[i]
|
if msgInfo == nil || msgInfo.Msg == nil {
|
||||||
if msg == nil || msg.Msg == nil {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if msg.Revoke != nil {
|
if msgInfo.Revoke != nil {
|
||||||
revokeContent := sdkws.MessageRevokedContent{
|
revokeContent := sdkws.MessageRevokedContent{
|
||||||
RevokerID: msg.Revoke.UserID,
|
RevokerID: msgInfo.Revoke.UserID,
|
||||||
RevokerRole: msg.Revoke.Role,
|
RevokerRole: msgInfo.Revoke.Role,
|
||||||
ClientMsgID: msg.Msg.ClientMsgID,
|
ClientMsgID: msgInfo.Msg.ClientMsgID,
|
||||||
RevokerNickname: msg.Revoke.Nickname,
|
RevokerNickname: msgInfo.Revoke.Nickname,
|
||||||
RevokeTime: msg.Revoke.Time,
|
RevokeTime: msgInfo.Revoke.Time,
|
||||||
SourceMessageSendTime: msg.Msg.SendTime,
|
SourceMessageSendTime: msgInfo.Msg.SendTime,
|
||||||
SourceMessageSendID: msg.Msg.SendID,
|
SourceMessageSendID: msgInfo.Msg.SendID,
|
||||||
SourceMessageSenderNickname: msg.Msg.SenderNickname,
|
SourceMessageSenderNickname: msgInfo.Msg.SenderNickname,
|
||||||
SessionType: msg.Msg.SessionType,
|
SessionType: msgInfo.Msg.SessionType,
|
||||||
Seq: msg.Msg.Seq,
|
Seq: msgInfo.Msg.Seq,
|
||||||
Ex: msg.Msg.Ex,
|
Ex: msgInfo.Msg.Ex,
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(&revokeContent)
|
data, err := json.Marshal(&revokeContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1197,11 +1200,10 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
msg.Msg.ContentType = constant.MsgRevokeNotification
|
msgInfo.Msg.ContentType = constant.MsgRevokeNotification
|
||||||
msg.Msg.Content = string(content)
|
msgInfo.Msg.Content = string(content)
|
||||||
}
|
|
||||||
msgs = append(msgs, msg)
|
|
||||||
}
|
}
|
||||||
|
msgs = append(msgs, msgInfo)
|
||||||
}
|
}
|
||||||
start := (req.Pagination.PageNumber - 1) * req.Pagination.ShowNumber
|
start := (req.Pagination.PageNumber - 1) * req.Pagination.ShowNumber
|
||||||
n := int32(len(msgs))
|
n := int32(len(msgs))
|
||||||
|
|||||||
67
pkg/common/db/unrelation/msg_convert.go
Normal file
67
pkg/common/db/unrelation/msg_convert.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package unrelation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
table "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *MsgMongoDriver) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) {
|
||||||
|
for _, conversationID := range conversationIDs {
|
||||||
|
regex := primitive.Regex{Pattern: fmt.Sprintf("^%s:", conversationID)}
|
||||||
|
cursor, err := m.MsgCollection.Find(ctx, bson.M{"doc_id": regex})
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, "convertAll find msg doc failed", err, "conversationID", conversationID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var msgDocs []table.MsgDocModel
|
||||||
|
err = cursor.All(ctx, &msgDocs)
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, "convertAll cursor all failed", err, "conversationID", conversationID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(msgDocs) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.ZInfo(ctx, "msg doc convert", "conversationID", conversationID, "len(msgDocs)", len(msgDocs))
|
||||||
|
if len(msgDocs[0].Msg) == int(m.model.GetSingleGocMsgNum5000()) {
|
||||||
|
if _, err := m.MsgCollection.DeleteMany(ctx, bson.M{"doc_id": regex}); err != nil {
|
||||||
|
log.ZError(ctx, "convertAll delete many failed", err, "conversationID", conversationID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var newMsgDocs []interface{}
|
||||||
|
for _, msgDoc := range msgDocs {
|
||||||
|
if int64(len(msgDoc.Msg)) == m.model.GetSingleGocMsgNum() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var index int64
|
||||||
|
for index < int64(len(msgDoc.Msg)) {
|
||||||
|
msg := msgDoc.Msg[index]
|
||||||
|
if msg != nil && msg.Msg != nil {
|
||||||
|
msgDocModel := table.MsgDocModel{DocID: m.model.GetDocID(conversationID, msg.Msg.Seq)}
|
||||||
|
end := index + m.model.GetSingleGocMsgNum()
|
||||||
|
if int(end) >= len(msgDoc.Msg) {
|
||||||
|
msgDocModel.Msg = msgDoc.Msg[index:]
|
||||||
|
} else {
|
||||||
|
msgDocModel.Msg = msgDoc.Msg[index:end]
|
||||||
|
}
|
||||||
|
newMsgDocs = append(newMsgDocs, msgDocModel)
|
||||||
|
index = end
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = m.MsgCollection.InsertMany(ctx, newMsgDocs)
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, "convertAll insert many failed", err, "conversationID", conversationID, "len(newMsgDocs)", len(newMsgDocs))
|
||||||
|
} else {
|
||||||
|
log.ZInfo(ctx, "msg doc convert", "conversationID", conversationID, "len(newMsgDocs)", len(newMsgDocs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,12 +16,14 @@ package unrelation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
|
|
||||||
"github.com/OpenIMSDK/tools/errs"
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
"github.com/OpenIMSDK/tools/utils"
|
"github.com/OpenIMSDK/tools/utils"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
|
||||||
|
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
|
||||||
)
|
)
|
||||||
|
|
||||||
// prefixes and suffixes.
|
// prefixes and suffixes.
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import (
|
|||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetNotificationConversationID(msg *sdkws.MsgData) string {
|
func GetNotificationConversationIDByMsg(msg *sdkws.MsgData) string {
|
||||||
switch msg.SessionType {
|
switch msg.SessionType {
|
||||||
case constant.SingleChatType:
|
case constant.SingleChatType:
|
||||||
l := []string{msg.SendID, msg.RecvID}
|
l := []string{msg.SendID, msg.RecvID}
|
||||||
@ -114,6 +114,30 @@ func GetConversationIDBySessionType(sessionType int, ids ...string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetNotificationConversationIDByConversationID(conversationID string) string {
|
||||||
|
l := strings.Split(conversationID, "_")
|
||||||
|
if len(l) > 1 {
|
||||||
|
l[0] = "n"
|
||||||
|
return strings.Join(l, "_")
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNotificationConversationID(sessionType int, ids ...string) string {
|
||||||
|
sort.Strings(ids)
|
||||||
|
if len(ids) > 2 || len(ids) < 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch sessionType {
|
||||||
|
case constant.SingleChatType:
|
||||||
|
return "n_" + strings.Join(ids, "_") // single chat
|
||||||
|
case constant.SuperGroupChatType:
|
||||||
|
return "n_" + ids[0] // super group chat
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func IsNotification(conversationID string) bool {
|
func IsNotification(conversationID string) bool {
|
||||||
return strings.HasPrefix(conversationID, "n_")
|
return strings.HasPrefix(conversationID, "n_")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -220,7 +220,13 @@ func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs [
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) error {
|
func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if opUser == nil {
|
if opUser == nil {
|
||||||
return errs.ErrInternalServer.Wrap("**sdkws.GroupMemberFullInfo is nil")
|
return errs.ErrInternalServer.Wrap("**sdkws.GroupMemberFullInfo is nil")
|
||||||
}
|
}
|
||||||
@ -260,6 +266,12 @@ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) (err error) {
|
func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -267,6 +279,12 @@ func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) (err error) {
|
func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -274,6 +292,12 @@ func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) (err error) {
|
func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -281,6 +305,12 @@ func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) (err error) {
|
func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -288,6 +318,12 @@ func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbGroup.JoinGroupReq) (err error) {
|
func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbGroup.JoinGroupReq) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, req.GroupID)
|
group, err := g.getGroupInfo(ctx, req.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -355,6 +391,12 @@ func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbGroup.GroupApplicationResponseReq) (err error) {
|
func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbGroup.GroupApplicationResponseReq) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, req.GroupID)
|
group, err := g.getGroupInfo(ctx, req.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -377,6 +419,12 @@ func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbGroup.TransferGroupOwnerReq) (err error) {
|
func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbGroup.TransferGroupOwnerReq) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, req.GroupID)
|
group, err := g.getGroupInfo(ctx, req.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -394,6 +442,12 @@ func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) (err error) {
|
func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -401,6 +455,12 @@ func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) MemberInvitedNotification(ctx context.Context, groupID, reason string, invitedUserIDList []string) (err error) {
|
func (g *GroupNotificationSender) MemberInvitedNotification(ctx context.Context, groupID, reason string, invitedUserIDList []string) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -419,12 +479,18 @@ func (g *GroupNotificationSender) MemberInvitedNotification(ctx context.Context,
|
|||||||
return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips)
|
return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, req *pbGroup.GroupApplicationResponseReq) (err error) {
|
func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) (err error) {
|
||||||
group, err := g.getGroupInfo(ctx, req.GroupID)
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
user, err := g.getGroupMember(ctx, req.GroupID, req.FromUserID)
|
user, err := g.getGroupMember(ctx, groupID, entrantUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -433,6 +499,12 @@ func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) (err error) {
|
func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -440,6 +512,12 @@ func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) (err error) {
|
func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -459,6 +537,12 @@ func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
|
func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -475,6 +559,12 @@ func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, groupID string) (err error) {
|
func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, groupID string) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -494,6 +584,12 @@ func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, gr
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) (err error) {
|
func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -513,6 +609,12 @@ func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
|
func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -529,6 +631,12 @@ func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
|
func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -545,6 +653,12 @@ func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
|
func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
|
||||||
|
defer log.ZDebug(ctx, "return")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
group, err := g.getGroupInfo(ctx, groupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -560,25 +674,6 @@ func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx c
|
|||||||
return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips)
|
return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupNotificationSender) MemberEnterDirectlyNotification(ctx context.Context, groupID string, entrantUserID string) (err error) {
|
|
||||||
defer log.ZDebug(ctx, "return")
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
group, err := g.getGroupInfo(ctx, groupID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
user, err := g.getGroupMember(ctx, groupID, entrantUserID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
tips := &sdkws.MemberEnterTips{Group: group, EntrantUser: user}
|
|
||||||
return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberEnterNotification, tips)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GroupNotificationSender) SuperGroupNotification(ctx context.Context, sendID, recvID string) (err error) {
|
func (g *GroupNotificationSender) SuperGroupNotification(ctx context.Context, sendID, recvID string) (err error) {
|
||||||
defer log.ZDebug(ctx, "return")
|
defer log.ZDebug(ctx, "return")
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
12
scripts/start.bat
Normal file
12
scripts/start.bat
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
cd %~p0../_output/bin/platforms/windows
|
||||||
|
start api.exe -p 10002
|
||||||
|
start auth.exe -p 10060
|
||||||
|
start conversation.exe -p 10080
|
||||||
|
start friend.exe -p 10020
|
||||||
|
start group.exe -p 10050
|
||||||
|
start msg.exe -p 10030
|
||||||
|
start msggateway.exe -p 10040 -w 10001
|
||||||
|
start msgtransfer.exe
|
||||||
|
start third.exe -p 10090
|
||||||
|
start push.exe -p 10070
|
||||||
|
start user.exe -p 10010
|
||||||
@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Copyright © 2023 OpenIM. All rights reserved.
|
# Copyright © 2023 OpenIM. All rights reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -24,12 +23,13 @@ source $OPENIM_ROOT/scripts/path_info.sh
|
|||||||
|
|
||||||
bin_dir="$BIN_DIR"
|
bin_dir="$BIN_DIR"
|
||||||
logs_dir="$OPENIM_ROOT/logs"
|
logs_dir="$OPENIM_ROOT/logs"
|
||||||
|
sdk_db_dir="$OPENIM_ROOT/sdk/db/"
|
||||||
|
|
||||||
cd "$SCRIPTS_ROOT"
|
cd "$SCRIPTS_ROOT"
|
||||||
|
|
||||||
for i in ${service_names[*]}; do
|
for i in ${service_names[*]}; do
|
||||||
#Check whether the service exists
|
#Check whether the service exists
|
||||||
name="ps |grep -w $i |grep -v grep"
|
name="ps -aux |grep -w $i |grep -v grep"
|
||||||
count="${name}| wc -l"
|
count="${name}| wc -l"
|
||||||
if [ $(eval ${count}) -gt 0 ]; then
|
if [ $(eval ${count}) -gt 0 ]; then
|
||||||
pid="${name}| awk '{print \$2}'"
|
pid="${name}| awk '{print \$2}'"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user