mirror of
https://github.com/openimsdk/open-im-server.git
synced 2025-04-06 04:15:46 +08:00
send group message split topic
This commit is contained in:
parent
804eb6c076
commit
f8af109821
@ -41,11 +41,15 @@ kafka:
|
|||||||
ws2mschat:
|
ws2mschat:
|
||||||
addr: [ 127.0.0.1:9092 ] #kafka配置,默认即可
|
addr: [ 127.0.0.1:9092 ] #kafka配置,默认即可
|
||||||
topic: "ws2ms_chat"
|
topic: "ws2ms_chat"
|
||||||
|
ws2mschatoffline:
|
||||||
|
addr: [ 127.0.0.1:9092 ] #kafka配置,默认即可
|
||||||
|
topic: "ws2ms_chat_offline"
|
||||||
ms2pschat:
|
ms2pschat:
|
||||||
addr: [ 127.0.0.1:9092 ] #kafka配置,默认即可
|
addr: [ 127.0.0.1:9092 ] #kafka配置,默认即可
|
||||||
topic: "ms2ps_chat"
|
topic: "ms2ps_chat"
|
||||||
consumergroupid:
|
consumergroupid:
|
||||||
msgToMongo: mongo
|
msgToMongo: mongo
|
||||||
|
MsgToMongoOffline: mongo_offline
|
||||||
msgToMySql: mysql
|
msgToMySql: mysql
|
||||||
msgToPush: push
|
msgToPush: push
|
||||||
|
|
||||||
|
@ -2,20 +2,36 @@ package logic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"Open_IM/pkg/common/config"
|
"Open_IM/pkg/common/config"
|
||||||
|
"Open_IM/pkg/common/constant"
|
||||||
"Open_IM/pkg/common/kafka"
|
"Open_IM/pkg/common/kafka"
|
||||||
|
"Open_IM/pkg/statistics"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const OnlineTopicBusy = "Busy"
|
||||||
|
const OnlineTopicVacancy = "Vacancy"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
persistentCH PersistentConsumerHandler
|
persistentCH PersistentConsumerHandler
|
||||||
historyCH HistoryConsumerHandler
|
historyCH OnlineHistoryConsumerHandler
|
||||||
producer *kafka.Producer
|
offlineHistoryCH OfflineHistoryConsumerHandler
|
||||||
|
producer *kafka.Producer
|
||||||
|
cmdCh chan Cmd2Value
|
||||||
|
onlineTopicStatus string
|
||||||
|
w *sync.Mutex
|
||||||
|
singleMsgSuccessCount uint64
|
||||||
|
groupMsgCount uint64
|
||||||
|
singleMsgFailedCount uint64
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
|
cmdCh = make(chan Cmd2Value, 10000)
|
||||||
persistentCH.Init()
|
persistentCH.Init()
|
||||||
historyCH.Init()
|
historyCH.Init(cmdCh)
|
||||||
|
offlineHistoryCH.Init(cmdCh)
|
||||||
|
statistics.NewStatistics(&singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
|
||||||
|
statistics.NewStatistics(&groupMsgCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d second groupMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
|
||||||
producer = kafka.NewKafkaProducer(config.Config.Kafka.Ms2pschat.Addr, config.Config.Kafka.Ms2pschat.Topic)
|
producer = kafka.NewKafkaProducer(config.Config.Kafka.Ms2pschat.Addr, config.Config.Kafka.Ms2pschat.Topic)
|
||||||
}
|
}
|
||||||
func Run() {
|
func Run() {
|
||||||
@ -26,4 +42,15 @@ func Run() {
|
|||||||
fmt.Println("not start mysql consumer")
|
fmt.Println("not start mysql consumer")
|
||||||
}
|
}
|
||||||
go historyCH.historyConsumerGroup.RegisterHandleAndConsumer(&historyCH)
|
go historyCH.historyConsumerGroup.RegisterHandleAndConsumer(&historyCH)
|
||||||
|
go offlineHistoryCH.historyConsumerGroup.RegisterHandleAndConsumer(&offlineHistoryCH)
|
||||||
|
}
|
||||||
|
func SetOnlineTopicStatus(status string) {
|
||||||
|
w.Lock()
|
||||||
|
defer w.Unlock()
|
||||||
|
onlineTopicStatus = status
|
||||||
|
}
|
||||||
|
func GetOnlineTopicStatus() string {
|
||||||
|
w.Lock()
|
||||||
|
defer w.Unlock()
|
||||||
|
return onlineTopicStatus
|
||||||
}
|
}
|
||||||
|
116
internal/msg_transfer/logic/offline_history_msg_handler.go
Normal file
116
internal/msg_transfer/logic/offline_history_msg_handler.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Open_IM/pkg/common/config"
|
||||||
|
"Open_IM/pkg/common/constant"
|
||||||
|
kfk "Open_IM/pkg/common/kafka"
|
||||||
|
"Open_IM/pkg/common/log"
|
||||||
|
pbMsg "Open_IM/pkg/proto/chat"
|
||||||
|
"Open_IM/pkg/utils"
|
||||||
|
"github.com/Shopify/sarama"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OfflineHistoryConsumerHandler struct {
|
||||||
|
msgHandle map[string]fcb
|
||||||
|
cmdCh chan Cmd2Value
|
||||||
|
historyConsumerGroup *kfk.MConsumerGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *OfflineHistoryConsumerHandler) Init(cmdCh chan Cmd2Value) {
|
||||||
|
mc.msgHandle = make(map[string]fcb)
|
||||||
|
mc.cmdCh = cmdCh
|
||||||
|
mc.msgHandle[config.Config.Kafka.Ws2mschatOffline.Topic] = mc.handleChatWs2Mongo
|
||||||
|
mc.historyConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0,
|
||||||
|
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ws2mschatOffline.Topic},
|
||||||
|
config.Config.Kafka.Ws2mschatOffline.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongoOffline)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *OfflineHistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string) {
|
||||||
|
now := time.Now()
|
||||||
|
msgFromMQ := pbMsg.MsgDataToMQ{}
|
||||||
|
err := proto.Unmarshal(msg, &msgFromMQ)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("msg_transfer Unmarshal msg err", "", "msg", string(msg), "err", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
operationID := msgFromMQ.OperationID
|
||||||
|
log.NewInfo(operationID, "msg come mongo!!!", "", "msg", string(msg))
|
||||||
|
//Control whether to store offline messages (mongo)
|
||||||
|
isHistory := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsHistory)
|
||||||
|
//Control whether to store history messages (mysql)
|
||||||
|
isPersist := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsPersistent)
|
||||||
|
isSenderSync := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsSenderSync)
|
||||||
|
switch msgFromMQ.MsgData.SessionType {
|
||||||
|
case constant.SingleChatType:
|
||||||
|
log.NewDebug(msgFromMQ.OperationID, "msg_transfer msg type = SingleChatType", isHistory, isPersist)
|
||||||
|
if isHistory {
|
||||||
|
err := saveUserChat(msgKey, &msgFromMQ)
|
||||||
|
if err != nil {
|
||||||
|
singleMsgFailedCount++
|
||||||
|
log.NewError(operationID, "single data insert to mongo err", err.Error(), msgFromMQ.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
singleMsgSuccessCount++
|
||||||
|
log.NewDebug(msgFromMQ.OperationID, "sendMessageToPush cost time ", time.Since(now))
|
||||||
|
}
|
||||||
|
if !isSenderSync && msgKey == msgFromMQ.MsgData.SendID {
|
||||||
|
} else {
|
||||||
|
go sendMessageToPush(&msgFromMQ, msgKey)
|
||||||
|
}
|
||||||
|
log.NewDebug(operationID, "saveUserChat cost time ", time.Since(now))
|
||||||
|
case constant.GroupChatType:
|
||||||
|
log.NewDebug(msgFromMQ.OperationID, "msg_transfer msg type = GroupChatType", isHistory, isPersist)
|
||||||
|
if isHistory {
|
||||||
|
err := saveUserChat(msgFromMQ.MsgData.RecvID, &msgFromMQ)
|
||||||
|
if err != nil {
|
||||||
|
log.NewError(operationID, "group data insert to mongo err", msgFromMQ.String(), msgFromMQ.MsgData.RecvID, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
groupMsgCount++
|
||||||
|
}
|
||||||
|
go sendMessageToPush(&msgFromMQ, msgFromMQ.MsgData.RecvID)
|
||||||
|
case constant.NotificationChatType:
|
||||||
|
log.NewDebug(msgFromMQ.OperationID, "msg_transfer msg type = NotificationChatType", isHistory, isPersist)
|
||||||
|
if isHistory {
|
||||||
|
err := saveUserChat(msgKey, &msgFromMQ)
|
||||||
|
if err != nil {
|
||||||
|
log.NewError(operationID, "single data insert to mongo err", err.Error(), msgFromMQ.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.NewDebug(msgFromMQ.OperationID, "sendMessageToPush cost time ", time.Since(now))
|
||||||
|
}
|
||||||
|
if !isSenderSync && msgKey == msgFromMQ.MsgData.SendID {
|
||||||
|
} else {
|
||||||
|
go sendMessageToPush(&msgFromMQ, msgKey)
|
||||||
|
}
|
||||||
|
log.NewDebug(operationID, "saveUserChat cost time ", time.Since(now))
|
||||||
|
default:
|
||||||
|
log.NewError(msgFromMQ.OperationID, "SessionType error", msgFromMQ.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.NewDebug(msgFromMQ.OperationID, "msg_transfer handle topic data to database success...", msgFromMQ.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (OfflineHistoryConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
|
||||||
|
func (OfflineHistoryConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
|
||||||
|
func (mc *OfflineHistoryConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession,
|
||||||
|
claim sarama.ConsumerGroupClaim) error { // a instance in the consumer group
|
||||||
|
log.NewDebug("", "new session msg come", claim.HighWaterMarkOffset(), claim.Topic(), claim.Partition())
|
||||||
|
select {
|
||||||
|
case cmd := <-mc.cmdCh:
|
||||||
|
if cmd.Cmd == OnlineTopicVacancy {
|
||||||
|
for msg := range claim.Messages() {
|
||||||
|
if GetOnlineTopicStatus() == OnlineTopicVacancy {
|
||||||
|
log.NewDebug("", "kafka get info to mongo", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "msg", string(msg.Value))
|
||||||
|
mc.msgHandle[msg.Topic](msg.Value, string(msg.Key))
|
||||||
|
sess.MarkMessage(msg, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -8,10 +8,9 @@ import (
|
|||||||
"Open_IM/pkg/grpc-etcdv3/getcdv3"
|
"Open_IM/pkg/grpc-etcdv3/getcdv3"
|
||||||
pbMsg "Open_IM/pkg/proto/chat"
|
pbMsg "Open_IM/pkg/proto/chat"
|
||||||
pbPush "Open_IM/pkg/proto/push"
|
pbPush "Open_IM/pkg/proto/push"
|
||||||
"Open_IM/pkg/statistics"
|
|
||||||
"Open_IM/pkg/utils"
|
"Open_IM/pkg/utils"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"errors"
|
||||||
"github.com/Shopify/sarama"
|
"github.com/Shopify/sarama"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"strings"
|
"strings"
|
||||||
@ -19,28 +18,52 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type fcb func(msg []byte, msgKey string)
|
type fcb func(msg []byte, msgKey string)
|
||||||
|
type Cmd2Value struct {
|
||||||
type HistoryConsumerHandler struct {
|
Cmd string
|
||||||
msgHandle map[string]fcb
|
Value interface{}
|
||||||
historyConsumerGroup *kfk.MConsumerGroup
|
}
|
||||||
singleMsgFailedCount uint64
|
type OnlineHistoryConsumerHandler struct {
|
||||||
singleMsgSuccessCount uint64
|
msgHandle map[string]fcb
|
||||||
groupMsgCount uint64
|
historyConsumerGroup *kfk.MConsumerGroup
|
||||||
|
cmdCh chan Cmd2Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *HistoryConsumerHandler) Init() {
|
func (och *OnlineHistoryConsumerHandler) Init(cmdCh chan Cmd2Value) {
|
||||||
statistics.NewStatistics(&mc.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
|
och.msgHandle = make(map[string]fcb)
|
||||||
statistics.NewStatistics(&mc.groupMsgCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d second groupMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
|
och.cmdCh = cmdCh
|
||||||
|
och.msgHandle[config.Config.Kafka.Ws2mschat.Topic] = och.handleChatWs2Mongo
|
||||||
mc.msgHandle = make(map[string]fcb)
|
och.historyConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0,
|
||||||
mc.msgHandle[config.Config.Kafka.Ws2mschat.Topic] = mc.handleChatWs2Mongo
|
|
||||||
mc.historyConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0,
|
|
||||||
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ws2mschat.Topic},
|
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ws2mschat.Topic},
|
||||||
config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo)
|
config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
func (och *OnlineHistoryConsumerHandler) TriggerCmd(status string) {
|
||||||
func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string) {
|
operationID := utils.OperationIDGenerator()
|
||||||
|
for {
|
||||||
|
err := sendCmd(och.cmdCh, Cmd2Value{Cmd: status, Value: ""}, 1)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(operationID, "TriggerCmd failed ", err.Error(), status)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Debug(operationID, "TriggerCmd success", status)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func sendCmd(ch chan Cmd2Value, value Cmd2Value, timeout int64) error {
|
||||||
|
var flag = 0
|
||||||
|
select {
|
||||||
|
case ch <- value:
|
||||||
|
flag = 1
|
||||||
|
case <-time.After(time.Second * time.Duration(timeout)):
|
||||||
|
flag = 2
|
||||||
|
}
|
||||||
|
if flag == 1 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New("send cmd timeout")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (och *OnlineHistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
msgFromMQ := pbMsg.MsgDataToMQ{}
|
msgFromMQ := pbMsg.MsgDataToMQ{}
|
||||||
err := proto.Unmarshal(msg, &msgFromMQ)
|
err := proto.Unmarshal(msg, &msgFromMQ)
|
||||||
@ -61,11 +84,11 @@ func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string)
|
|||||||
if isHistory {
|
if isHistory {
|
||||||
err := saveUserChat(msgKey, &msgFromMQ)
|
err := saveUserChat(msgKey, &msgFromMQ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mc.singleMsgFailedCount++
|
singleMsgFailedCount++
|
||||||
log.NewError(operationID, "single data insert to mongo err", err.Error(), msgFromMQ.String())
|
log.NewError(operationID, "single data insert to mongo err", err.Error(), msgFromMQ.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mc.singleMsgSuccessCount++
|
singleMsgSuccessCount++
|
||||||
log.NewDebug(msgFromMQ.OperationID, "sendMessageToPush cost time ", time.Since(now))
|
log.NewDebug(msgFromMQ.OperationID, "sendMessageToPush cost time ", time.Since(now))
|
||||||
}
|
}
|
||||||
if !isSenderSync && msgKey == msgFromMQ.MsgData.SendID {
|
if !isSenderSync && msgKey == msgFromMQ.MsgData.SendID {
|
||||||
@ -81,7 +104,7 @@ func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string)
|
|||||||
log.NewError(operationID, "group data insert to mongo err", msgFromMQ.String(), msgFromMQ.MsgData.RecvID, err.Error())
|
log.NewError(operationID, "group data insert to mongo err", msgFromMQ.String(), msgFromMQ.MsgData.RecvID, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mc.groupMsgCount++
|
groupMsgCount++
|
||||||
}
|
}
|
||||||
go sendMessageToPush(&msgFromMQ, msgFromMQ.MsgData.RecvID)
|
go sendMessageToPush(&msgFromMQ, msgFromMQ.MsgData.RecvID)
|
||||||
case constant.NotificationChatType:
|
case constant.NotificationChatType:
|
||||||
@ -106,14 +129,20 @@ func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string)
|
|||||||
log.NewDebug(msgFromMQ.OperationID, "msg_transfer handle topic data to database success...", msgFromMQ.String())
|
log.NewDebug(msgFromMQ.OperationID, "msg_transfer handle topic data to database success...", msgFromMQ.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (HistoryConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
|
func (OnlineHistoryConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
|
||||||
func (HistoryConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
|
func (OnlineHistoryConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
|
||||||
func (mc *HistoryConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession,
|
func (och *OnlineHistoryConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession,
|
||||||
claim sarama.ConsumerGroupClaim) error {
|
claim sarama.ConsumerGroupClaim) error { // a instance in the consumer group
|
||||||
|
och.TriggerCmd(OnlineTopicBusy)
|
||||||
|
SetOnlineTopicStatus(OnlineTopicBusy)
|
||||||
for msg := range claim.Messages() {
|
for msg := range claim.Messages() {
|
||||||
log.NewDebug("", "kafka get info to mongo", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "msg", string(msg.Value))
|
log.NewDebug("", "kafka get info to mongo", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "msg", string(msg.Value))
|
||||||
mc.msgHandle[msg.Topic](msg.Value, string(msg.Key))
|
och.msgHandle[msg.Topic](msg.Value, string(msg.Key))
|
||||||
sess.MarkMessage(msg, "")
|
sess.MarkMessage(msg, "")
|
||||||
|
if claim.HighWaterMarkOffset()-msg.Offset <= 1 {
|
||||||
|
och.TriggerCmd(OnlineTopicVacancy)
|
||||||
|
SetOnlineTopicStatus(OnlineTopicVacancy)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@ -19,7 +19,8 @@ type rpcChat struct {
|
|||||||
rpcRegisterName string
|
rpcRegisterName string
|
||||||
etcdSchema string
|
etcdSchema string
|
||||||
etcdAddr []string
|
etcdAddr []string
|
||||||
producer *kafka.Producer
|
onlineProducer *kafka.Producer
|
||||||
|
offlineProducer *kafka.Producer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRpcChatServer(port int) *rpcChat {
|
func NewRpcChatServer(port int) *rpcChat {
|
||||||
@ -30,7 +31,8 @@ func NewRpcChatServer(port int) *rpcChat {
|
|||||||
etcdSchema: config.Config.Etcd.EtcdSchema,
|
etcdSchema: config.Config.Etcd.EtcdSchema,
|
||||||
etcdAddr: config.Config.Etcd.EtcdAddr,
|
etcdAddr: config.Config.Etcd.EtcdAddr,
|
||||||
}
|
}
|
||||||
rc.producer = kafka.NewKafkaProducer(config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.Ws2mschat.Topic)
|
rc.onlineProducer = kafka.NewKafkaProducer(config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.Ws2mschat.Topic)
|
||||||
|
rc.offlineProducer = kafka.NewKafkaProducer(config.Config.Kafka.Ws2mschatOffline.Addr, config.Config.Kafka.Ws2mschatOffline.Topic)
|
||||||
return &rc
|
return &rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,9 +10,11 @@ import (
|
|||||||
pbCache "Open_IM/pkg/proto/cache"
|
pbCache "Open_IM/pkg/proto/cache"
|
||||||
pbChat "Open_IM/pkg/proto/chat"
|
pbChat "Open_IM/pkg/proto/chat"
|
||||||
pbConversation "Open_IM/pkg/proto/conversation"
|
pbConversation "Open_IM/pkg/proto/conversation"
|
||||||
|
pbRelay "Open_IM/pkg/proto/relay"
|
||||||
sdk_ws "Open_IM/pkg/proto/sdk_ws"
|
sdk_ws "Open_IM/pkg/proto/sdk_ws"
|
||||||
"Open_IM/pkg/utils"
|
"Open_IM/pkg/utils"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"github.com/garyburd/redigo/redis"
|
"github.com/garyburd/redigo/redis"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -188,14 +190,14 @@ func (rpc *rpcChat) SendMsg(_ context.Context, pb *pbChat.SendMsgReq) (*pbChat.S
|
|||||||
if isSend {
|
if isSend {
|
||||||
msgToMQSingle.MsgData = pb.MsgData
|
msgToMQSingle.MsgData = pb.MsgData
|
||||||
log.NewInfo(msgToMQSingle.OperationID, msgToMQSingle)
|
log.NewInfo(msgToMQSingle.OperationID, msgToMQSingle)
|
||||||
err1 := rpc.sendMsgToKafka(&msgToMQSingle, msgToMQSingle.MsgData.RecvID)
|
err1 := rpc.sendMsgToKafka(&msgToMQSingle, msgToMQSingle.MsgData.RecvID, constant.OnlineStatus)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:RecvID", msgToMQSingle.MsgData.RecvID, msgToMQSingle.String())
|
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:RecvID", msgToMQSingle.MsgData.RecvID, msgToMQSingle.String())
|
||||||
return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0)
|
return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if msgToMQSingle.MsgData.SendID != msgToMQSingle.MsgData.RecvID { //Filter messages sent to yourself
|
if msgToMQSingle.MsgData.SendID != msgToMQSingle.MsgData.RecvID { //Filter messages sent to yourself
|
||||||
err2 := rpc.sendMsgToKafka(&msgToMQSingle, msgToMQSingle.MsgData.SendID)
|
err2 := rpc.sendMsgToKafka(&msgToMQSingle, msgToMQSingle.MsgData.SendID, constant.OnlineStatus)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:SendID", msgToMQSingle.MsgData.SendID, msgToMQSingle.String())
|
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:SendID", msgToMQSingle.MsgData.SendID, msgToMQSingle.String())
|
||||||
return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0)
|
return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0)
|
||||||
@ -252,72 +254,33 @@ func (rpc *rpcChat) SendMsg(_ context.Context, pb *pbChat.SendMsgReq) (*pbChat.S
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
onUserIDList, offUserIDList := getOnlineAndOfflineUserIDList(memberUserIDList, pb.OperationID)
|
||||||
|
log.Debug(pb.OperationID, onUserIDList, offUserIDList)
|
||||||
groupID := pb.MsgData.GroupID
|
groupID := pb.MsgData.GroupID
|
||||||
//split parallel send
|
//split parallel send
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var sendTag bool
|
var sendTag bool
|
||||||
var split = 50
|
var split = 50
|
||||||
remain := len(memberUserIDList) % split
|
remain := len(onUserIDList) % split
|
||||||
for i := 0; i < len(memberUserIDList)/split; i++ {
|
for i := 0; i < len(onUserIDList)/split; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(list []string) {
|
go rpc.sendMsgToGroup(onUserIDList[i*split:(i+1)*split], pb, constant.OnlineStatus, &sendTag, &wg)
|
||||||
// log.Debug(pb.OperationID, "split userID ", list)
|
|
||||||
groupPB := pbChat.SendMsgReq{Token: pb.Token, OperationID: pb.OperationID, MsgData: &sdk_ws.MsgData{OfflinePushInfo: &sdk_ws.OfflinePushInfo{}}}
|
|
||||||
*groupPB.MsgData = *pb.MsgData
|
|
||||||
if pb.MsgData.OfflinePushInfo != nil {
|
|
||||||
*groupPB.MsgData.OfflinePushInfo = *pb.MsgData.OfflinePushInfo
|
|
||||||
}
|
|
||||||
msgToMQGroup := pbChat.MsgDataToMQ{Token: groupPB.Token, OperationID: groupPB.OperationID, MsgData: groupPB.MsgData}
|
|
||||||
for _, v := range list {
|
|
||||||
groupPB.MsgData.RecvID = v
|
|
||||||
isSend := modifyMessageByUserMessageReceiveOpt(v, groupID, constant.GroupChatType, &groupPB)
|
|
||||||
if isSend {
|
|
||||||
msgToMQGroup.MsgData = groupPB.MsgData
|
|
||||||
// log.Debug(groupPB.OperationID, "sendMsgToKafka, ", v, groupID, msgToMQGroup.String())
|
|
||||||
err := rpc.sendMsgToKafka(&msgToMQGroup, v)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(msgToMQGroup.OperationID, "kafka send msg err:UserId", v, msgToMQGroup.String())
|
|
||||||
} else {
|
|
||||||
sendTag = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Debug(groupPB.OperationID, "not sendMsgToKafka, ", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}(memberUserIDList[i*split : (i+1)*split])
|
|
||||||
}
|
}
|
||||||
if remain > 0 {
|
if remain > 0 {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(list []string) {
|
go rpc.sendMsgToGroup(onUserIDList[split*(len(onUserIDList)/split):], pb, constant.OnlineStatus, &sendTag, &wg)
|
||||||
// log.Debug(pb.OperationID, "split userID ", list)
|
}
|
||||||
groupPB := pbChat.SendMsgReq{Token: pb.Token, OperationID: pb.OperationID, MsgData: &sdk_ws.MsgData{OfflinePushInfo: &sdk_ws.OfflinePushInfo{}}}
|
wg.Wait()
|
||||||
*groupPB.MsgData = *pb.MsgData
|
remain = len(offUserIDList) % split
|
||||||
if pb.MsgData.OfflinePushInfo != nil {
|
for i := 0; i < len(offUserIDList)/split; i++ {
|
||||||
*groupPB.MsgData.OfflinePushInfo = *pb.MsgData.OfflinePushInfo
|
wg.Add(1)
|
||||||
}
|
go rpc.sendMsgToGroup(offUserIDList[i*split:(i+1)*split], pb, constant.OfflineStatus, &sendTag, &wg)
|
||||||
msgToMQGroup := pbChat.MsgDataToMQ{Token: groupPB.Token, OperationID: groupPB.OperationID, MsgData: groupPB.MsgData}
|
}
|
||||||
for _, v := range list {
|
if remain > 0 {
|
||||||
groupPB.MsgData.RecvID = v
|
wg.Add(1)
|
||||||
isSend := modifyMessageByUserMessageReceiveOpt(v, groupID, constant.GroupChatType, &groupPB)
|
go rpc.sendMsgToGroup(offUserIDList[split*(len(offUserIDList)/split):], pb, constant.OfflineStatus, &sendTag, &wg)
|
||||||
if isSend {
|
|
||||||
msgToMQGroup.MsgData = groupPB.MsgData
|
|
||||||
// log.Debug(groupPB.OperationID, "sendMsgToKafka, ", v, groupID, msgToMQGroup.String())
|
|
||||||
err := rpc.sendMsgToKafka(&msgToMQGroup, v)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(msgToMQGroup.OperationID, "kafka send msg err:UserId", v, msgToMQGroup.String())
|
|
||||||
} else {
|
|
||||||
sendTag = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Debug(groupPB.OperationID, "not sendMsgToKafka, ", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}(memberUserIDList[split*(len(memberUserIDList)/split):])
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
log.Info(msgToMQSingle.OperationID, "addUidList", addUidList)
|
log.Info(msgToMQSingle.OperationID, "addUidList", addUidList)
|
||||||
for _, v := range addUidList {
|
for _, v := range addUidList {
|
||||||
pb.MsgData.RecvID = v
|
pb.MsgData.RecvID = v
|
||||||
@ -325,7 +288,7 @@ func (rpc *rpcChat) SendMsg(_ context.Context, pb *pbChat.SendMsgReq) (*pbChat.S
|
|||||||
log.Info(msgToMQSingle.OperationID, "isSend", isSend)
|
log.Info(msgToMQSingle.OperationID, "isSend", isSend)
|
||||||
if isSend {
|
if isSend {
|
||||||
msgToMQSingle.MsgData = pb.MsgData
|
msgToMQSingle.MsgData = pb.MsgData
|
||||||
err := rpc.sendMsgToKafka(&msgToMQSingle, v)
|
err := rpc.sendMsgToKafka(&msgToMQSingle, v, constant.OnlineStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:UserId", v, msgToMQSingle.String())
|
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:UserId", v, msgToMQSingle.String())
|
||||||
} else {
|
} else {
|
||||||
@ -397,14 +360,14 @@ func (rpc *rpcChat) SendMsg(_ context.Context, pb *pbChat.SendMsgReq) (*pbChat.S
|
|||||||
case constant.NotificationChatType:
|
case constant.NotificationChatType:
|
||||||
msgToMQSingle.MsgData = pb.MsgData
|
msgToMQSingle.MsgData = pb.MsgData
|
||||||
log.NewInfo(msgToMQSingle.OperationID, msgToMQSingle)
|
log.NewInfo(msgToMQSingle.OperationID, msgToMQSingle)
|
||||||
err1 := rpc.sendMsgToKafka(&msgToMQSingle, msgToMQSingle.MsgData.RecvID)
|
err1 := rpc.sendMsgToKafka(&msgToMQSingle, msgToMQSingle.MsgData.RecvID, constant.OnlineStatus)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:RecvID", msgToMQSingle.MsgData.RecvID, msgToMQSingle.String())
|
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:RecvID", msgToMQSingle.MsgData.RecvID, msgToMQSingle.String())
|
||||||
return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0)
|
return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if msgToMQSingle.MsgData.SendID != msgToMQSingle.MsgData.RecvID { //Filter messages sent to yourself
|
if msgToMQSingle.MsgData.SendID != msgToMQSingle.MsgData.RecvID { //Filter messages sent to yourself
|
||||||
err2 := rpc.sendMsgToKafka(&msgToMQSingle, msgToMQSingle.MsgData.SendID)
|
err2 := rpc.sendMsgToKafka(&msgToMQSingle, msgToMQSingle.MsgData.SendID, constant.OnlineStatus)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:SendID", msgToMQSingle.MsgData.SendID, msgToMQSingle.String())
|
log.NewError(msgToMQSingle.OperationID, "kafka send msg err:SendID", msgToMQSingle.MsgData.SendID, msgToMQSingle.String())
|
||||||
return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0)
|
return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0)
|
||||||
@ -416,12 +379,22 @@ func (rpc *rpcChat) SendMsg(_ context.Context, pb *pbChat.SendMsgReq) (*pbChat.S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rpc *rpcChat) sendMsgToKafka(m *pbChat.MsgDataToMQ, key string) error {
|
func (rpc *rpcChat) sendMsgToKafka(m *pbChat.MsgDataToMQ, key string, status string) error {
|
||||||
pid, offset, err := rpc.producer.SendMessage(m, key)
|
switch status {
|
||||||
if err != nil {
|
case constant.OnlineStatus:
|
||||||
log.Error(m.OperationID, "kafka send failed", "send data", m.String(), "pid", pid, "offset", offset, "err", err.Error(), "key", key)
|
pid, offset, err := rpc.onlineProducer.SendMessage(m, key)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(m.OperationID, "kafka send failed", "send data", m.String(), "pid", pid, "offset", offset, "err", err.Error(), "key", key, status)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
case constant.OfflineStatus:
|
||||||
|
pid, offset, err := rpc.offlineProducer.SendMessage(m, key)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(m.OperationID, "kafka send failed", "send data", m.String(), "pid", pid, "offset", offset, "err", err.Error(), "key", key, status)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return err
|
return errors.New("status error")
|
||||||
}
|
}
|
||||||
func GetMsgID(sendID string) string {
|
func GetMsgID(sendID string) string {
|
||||||
t := time.Now().Format("2006-01-02 15:04:05")
|
t := time.Now().Format("2006-01-02 15:04:05")
|
||||||
@ -736,3 +709,68 @@ func Notification(n *NotificationMsg) {
|
|||||||
log.NewError(req.OperationID, "SendMsg rpc failed, ", req.String(), reply.ErrCode, reply.ErrMsg)
|
log.NewError(req.OperationID, "SendMsg rpc failed, ", req.String(), reply.ErrCode, reply.ErrMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func getOnlineAndOfflineUserIDList(memberList []string, operationID string) (onllUserIDList []string, offlUserIDList []string) {
|
||||||
|
var wsResult []*pbRelay.GetUsersOnlineStatusResp_SuccessResult
|
||||||
|
req := &pbRelay.GetUsersOnlineStatusReq{}
|
||||||
|
req.UserIDList = memberList
|
||||||
|
req.OperationID = operationID
|
||||||
|
req.OpUserID = config.Config.Manager.AppManagerUid[0]
|
||||||
|
flag := false
|
||||||
|
grpcCons := getcdv3.GetConn4Unique(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOnlineMessageRelayName)
|
||||||
|
for _, v := range grpcCons {
|
||||||
|
client := pbRelay.NewOnlineMessageRelayServiceClient(v)
|
||||||
|
reply, err := client.GetUsersOnlineStatus(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
log.NewError(operationID, "GetUsersOnlineStatus rpc err", req.String(), err.Error())
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
if reply.ErrCode == 0 {
|
||||||
|
wsResult = append(wsResult, reply.SuccessResult...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.NewInfo(operationID, "call GetUsersOnlineStatus rpc server is success", wsResult)
|
||||||
|
//Online data merge of each node
|
||||||
|
for _, v1 := range memberList {
|
||||||
|
flag = false
|
||||||
|
|
||||||
|
for _, v2 := range wsResult {
|
||||||
|
if v2.UserID == v1 {
|
||||||
|
flag = true
|
||||||
|
onllUserIDList = append(onllUserIDList, v1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if !flag {
|
||||||
|
offlUserIDList = append(offlUserIDList, v1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return onllUserIDList, offlUserIDList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rpc *rpcChat) sendMsgToGroup(list []string, pb *pbChat.SendMsgReq, status string, sendTag *bool, wg *sync.WaitGroup) {
|
||||||
|
// log.Debug(pb.OperationID, "split userID ", list)
|
||||||
|
groupPB := pbChat.SendMsgReq{Token: pb.Token, OperationID: pb.OperationID, MsgData: &sdk_ws.MsgData{OfflinePushInfo: &sdk_ws.OfflinePushInfo{}}}
|
||||||
|
*groupPB.MsgData = *pb.MsgData
|
||||||
|
if pb.MsgData.OfflinePushInfo != nil {
|
||||||
|
*groupPB.MsgData.OfflinePushInfo = *pb.MsgData.OfflinePushInfo
|
||||||
|
}
|
||||||
|
msgToMQGroup := pbChat.MsgDataToMQ{Token: groupPB.Token, OperationID: groupPB.OperationID, MsgData: groupPB.MsgData}
|
||||||
|
for _, v := range list {
|
||||||
|
groupPB.MsgData.RecvID = v
|
||||||
|
isSend := modifyMessageByUserMessageReceiveOpt(v, groupPB.MsgData.GroupID, constant.GroupChatType, &groupPB)
|
||||||
|
if isSend {
|
||||||
|
msgToMQGroup.MsgData = groupPB.MsgData
|
||||||
|
// log.Debug(groupPB.OperationID, "sendMsgToKafka, ", v, groupID, msgToMQGroup.String())
|
||||||
|
err := rpc.sendMsgToKafka(&msgToMQGroup, v, status)
|
||||||
|
if err != nil {
|
||||||
|
log.NewError(msgToMQGroup.OperationID, "kafka send msg err:UserId", v, msgToMQGroup.String())
|
||||||
|
} else {
|
||||||
|
*sendTag = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Debug(groupPB.OperationID, "not sendMsgToKafka, ", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
@ -192,14 +192,19 @@ type config struct {
|
|||||||
Addr []string `yaml:"addr"`
|
Addr []string `yaml:"addr"`
|
||||||
Topic string `yaml:"topic"`
|
Topic string `yaml:"topic"`
|
||||||
}
|
}
|
||||||
|
Ws2mschatOffline struct {
|
||||||
|
Addr []string `yaml:"addr"`
|
||||||
|
Topic string `yaml:"topic"`
|
||||||
|
}
|
||||||
Ms2pschat struct {
|
Ms2pschat struct {
|
||||||
Addr []string `yaml:"addr"`
|
Addr []string `yaml:"addr"`
|
||||||
Topic string `yaml:"topic"`
|
Topic string `yaml:"topic"`
|
||||||
}
|
}
|
||||||
ConsumerGroupID struct {
|
ConsumerGroupID struct {
|
||||||
MsgToMongo string `yaml:"msgToMongo"`
|
MsgToMongo string `yaml:"msgToMongo"`
|
||||||
MsgToMySql string `yaml:"msgToMySql"`
|
MsgToMongoOffline string `yaml:"msgToMongoOffline"`
|
||||||
MsgToPush string `yaml:"msgToPush"`
|
MsgToMySql string `yaml:"msgToMySql"`
|
||||||
|
MsgToPush string `yaml:"msgToPush"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Secret string `yaml:"secret"`
|
Secret string `yaml:"secret"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user