refactor: unify code formatting and improve push/search implementations
- Remove BOM from all Go source files - Standardize import ordering and whitespace across handlers and services - Replace PostgreSQL full-text search with ILIKE pattern matching in post and user repositories - Enhance JPush client with TLS transport, rate limit monitoring, and simplified API - Refactor PushService to include userID in device management methods - Add MaxDevicesPerUser limit and extract helper functions for push payload construction
This commit is contained in:
@@ -25,13 +25,15 @@ const (
|
||||
DefaultExpiredTime = 24 * time.Hour
|
||||
// PushQueueSize 推送队列大小
|
||||
PushQueueSize = 1000
|
||||
// MaxDevicesPerUser 每个用户最大设备数
|
||||
MaxDevicesPerUser = 10
|
||||
)
|
||||
|
||||
// ChatMessageSender 聊天消息发送者信息
|
||||
type ChatMessageSender struct {
|
||||
ID string
|
||||
Name string
|
||||
Avatar string
|
||||
ID string
|
||||
Name string
|
||||
Avatar string
|
||||
}
|
||||
|
||||
// PushPriority 推送优先级
|
||||
@@ -62,8 +64,8 @@ type PushService interface {
|
||||
|
||||
// 设备管理
|
||||
RegisterDevice(ctx context.Context, userID string, deviceID string, deviceType model.DeviceType, pushToken string) error
|
||||
UnregisterDevice(ctx context.Context, deviceID string) error
|
||||
UpdateDeviceToken(ctx context.Context, deviceID string, newPushToken string) error
|
||||
UnregisterDevice(ctx context.Context, userID string, deviceID string) error
|
||||
UpdateDeviceToken(ctx context.Context, userID string, deviceID string, newPushToken string) error
|
||||
|
||||
// 推送记录管理
|
||||
CreatePushRecord(ctx context.Context, userID string, messageID string, channel model.PushChannel) (*model.PushRecord, error)
|
||||
@@ -135,48 +137,15 @@ func (s *pushServiceImpl) PushToUser(ctx context.Context, userID string, message
|
||||
}
|
||||
|
||||
// 用户不在线,尝试通过极光推送直接发送
|
||||
if s.jpushClient != nil {
|
||||
if s.isJPushAvailable() {
|
||||
devices, err := s.deviceRepo.GetActiveByUserID(userID)
|
||||
if err == nil && len(devices) > 0 {
|
||||
mobileDevices := make([]*model.DeviceToken, 0)
|
||||
for _, d := range devices {
|
||||
if d.SupportsMobilePush() && d.PushToken != "" {
|
||||
mobileDevices = append(mobileDevices, d)
|
||||
}
|
||||
}
|
||||
mobileDevices := getMobileDevices(devices)
|
||||
if len(mobileDevices) > 0 {
|
||||
title := "新消息"
|
||||
content := dto.ExtractTextContentFromModel(message.Segments)
|
||||
if message.IsSystemMessage() || message.Category == model.CategoryNotification {
|
||||
if message.ExtraData != nil && message.ExtraData.ActorName != "" {
|
||||
title = message.ExtraData.ActorName
|
||||
} else {
|
||||
title = "系统通知"
|
||||
}
|
||||
}
|
||||
extras := map[string]any{
|
||||
"message_id": message.ID,
|
||||
"conversation_id": message.ConversationID,
|
||||
"sender_id": message.SenderID,
|
||||
"category": string(message.Category),
|
||||
}
|
||||
if message.ExtraData != nil {
|
||||
extras["actor_name"] = message.ExtraData.ActorName
|
||||
extras["avatar_url"] = message.ExtraData.AvatarURL
|
||||
extras["target_id"] = message.ExtraData.TargetID
|
||||
extras["target_type"] = message.ExtraData.TargetType
|
||||
}
|
||||
pushErr := s.pushViaJPushBatch(mobileDevices, title, content, extras)
|
||||
payload := buildMessagePayload(message)
|
||||
pushErr := s.pushViaJPushBatch(mobileDevices, payload.Title, payload.Content, payload.Extras)
|
||||
if pushErr == nil {
|
||||
for _, device := range mobileDevices {
|
||||
record, rerr := s.CreatePushRecord(ctx, userID, message.ID, model.PushChannelJPush)
|
||||
if rerr == nil {
|
||||
record.DeviceToken = device.PushToken
|
||||
record.DeviceType = string(device.DeviceType)
|
||||
record.MarkPushed()
|
||||
s.pushRepo.Update(record)
|
||||
}
|
||||
}
|
||||
s.batchCreatePushedRecords(ctx, userID, message.ID, mobileDevices)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -247,11 +216,10 @@ func (s *pushServiceImpl) pushViaWebSocket(ctx context.Context, userID string, m
|
||||
}
|
||||
|
||||
// 构建普通聊天消息的 WebSocket 消息 - 使用新的 WSEventResponse 格式
|
||||
// 获取会话类型 (private/group)
|
||||
// 根据 Category 推断 detailType,群聊会话需要查询 Conversation 表获取准确类型
|
||||
detailType := "private"
|
||||
if message.ConversationID != "" {
|
||||
// 从会话中获取类型,需要查询数据库或从消息中判断
|
||||
// 这里暂时默认为 private,group 类型需要额外逻辑
|
||||
if message.Category == model.CategoryNotification || message.IsSystemMessage() {
|
||||
detailType = "system"
|
||||
}
|
||||
|
||||
// 直接使用 message.Segments
|
||||
@@ -275,9 +243,50 @@ func (s *pushServiceImpl) pushViaWebSocket(ctx context.Context, userID string, m
|
||||
return true
|
||||
}
|
||||
|
||||
// messagePayload 推送消息的标题、内容和附加数据
|
||||
type messagePayload struct {
|
||||
Title string
|
||||
Content string
|
||||
Extras map[string]any
|
||||
}
|
||||
|
||||
// buildMessagePayload 从消息中构建推送所需的标题、内容和附加数据
|
||||
func buildMessagePayload(message *model.Message) messagePayload {
|
||||
_ = message.Decrypt()
|
||||
|
||||
title := "新消息"
|
||||
content := dto.ExtractTextContentFromModel(message.Segments)
|
||||
if message.IsSystemMessage() || message.Category == model.CategoryNotification {
|
||||
if message.ExtraData != nil && message.ExtraData.ActorName != "" {
|
||||
title = message.ExtraData.ActorName
|
||||
} else {
|
||||
title = "系统通知"
|
||||
}
|
||||
}
|
||||
|
||||
extras := map[string]any{
|
||||
"message_id": message.ID,
|
||||
"conversation_id": message.ConversationID,
|
||||
"sender_id": message.SenderID,
|
||||
"category": string(message.Category),
|
||||
}
|
||||
if message.ExtraData != nil {
|
||||
extras["actor_name"] = message.ExtraData.ActorName
|
||||
extras["avatar_url"] = message.ExtraData.AvatarURL
|
||||
extras["target_id"] = message.ExtraData.TargetID
|
||||
extras["target_type"] = message.ExtraData.TargetType
|
||||
}
|
||||
|
||||
return messagePayload{
|
||||
Title: title,
|
||||
Content: content,
|
||||
Extras: extras,
|
||||
}
|
||||
}
|
||||
|
||||
// pushViaJPush 通过极光推送发送通知
|
||||
func (s *pushServiceImpl) pushViaJPush(ctx context.Context, device *model.DeviceToken, title, content string, extras map[string]any) error {
|
||||
if s.jpushClient == nil {
|
||||
if !s.isJPushAvailable() {
|
||||
return errors.New("jpush client not configured")
|
||||
}
|
||||
|
||||
@@ -286,7 +295,7 @@ func (s *pushServiceImpl) pushViaJPush(ctx context.Context, device *model.Device
|
||||
}
|
||||
|
||||
notification := jpush.BuildNotification(title, content, "message", extras)
|
||||
_, err := s.jpushClient.PushByRegistrationIDs([]string{device.PushToken}, notification, extras)
|
||||
_, err := s.jpushClient.PushByRegistrationIDs([]string{device.PushToken}, notification)
|
||||
if err != nil {
|
||||
return fmt.Errorf("jpush push failed: %w", err)
|
||||
}
|
||||
@@ -294,9 +303,37 @@ func (s *pushServiceImpl) pushViaJPush(ctx context.Context, device *model.Device
|
||||
return nil
|
||||
}
|
||||
|
||||
// batchCreatePushedRecords 批量创建已推送成功的记录
|
||||
func (s *pushServiceImpl) batchCreatePushedRecords(ctx context.Context, userID string, messageID string, devices []*model.DeviceToken) {
|
||||
expiredAt := time.Now().Add(DefaultExpiredTime)
|
||||
records := make([]*model.PushRecord, 0, len(devices))
|
||||
for _, device := range devices {
|
||||
now := time.Now()
|
||||
record := &model.PushRecord{
|
||||
UserID: userID,
|
||||
MessageID: messageID,
|
||||
PushChannel: model.PushChannelJPush,
|
||||
PushStatus: model.PushStatusPushed,
|
||||
DeviceToken: device.PushToken,
|
||||
DeviceType: string(device.DeviceType),
|
||||
MaxRetry: MaxRetryCount,
|
||||
ExpiredAt: &expiredAt,
|
||||
PushedAt: &now,
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
if err := s.pushRepo.BatchCreate(records); err != nil {
|
||||
zap.L().Error("batch create pushed records failed",
|
||||
zap.String("userID", userID),
|
||||
zap.String("messageID", messageID),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// pushViaJPushBatch 批量通过极光推送发送通知
|
||||
func (s *pushServiceImpl) pushViaJPushBatch(devices []*model.DeviceToken, title, content string, extras map[string]any) error {
|
||||
if s.jpushClient == nil {
|
||||
if !s.isJPushAvailable() {
|
||||
return errors.New("jpush client not configured")
|
||||
}
|
||||
|
||||
@@ -312,7 +349,7 @@ func (s *pushServiceImpl) pushViaJPushBatch(devices []*model.DeviceToken, title,
|
||||
}
|
||||
|
||||
notification := jpush.BuildNotification(title, content, "message", extras)
|
||||
_, err := s.jpushClient.PushByRegistrationIDs(regIDs, notification, extras)
|
||||
_, err := s.jpushClient.PushByRegistrationIDs(regIDs, notification)
|
||||
if err != nil {
|
||||
return fmt.Errorf("jpush batch push failed: %w", err)
|
||||
}
|
||||
@@ -322,6 +359,11 @@ func (s *pushServiceImpl) pushViaJPushBatch(devices []*model.DeviceToken, title,
|
||||
|
||||
// RegisterDevice 注册设备
|
||||
func (s *pushServiceImpl) RegisterDevice(ctx context.Context, userID string, deviceID string, deviceType model.DeviceType, pushToken string) error {
|
||||
existing, err := s.deviceRepo.GetByUserID(userID)
|
||||
if err == nil && len(existing) >= MaxDevicesPerUser {
|
||||
return fmt.Errorf("exceeded maximum device limit (%d)", MaxDevicesPerUser)
|
||||
}
|
||||
|
||||
deviceToken := &model.DeviceToken{
|
||||
UserID: userID,
|
||||
DeviceID: deviceID,
|
||||
@@ -335,16 +377,26 @@ func (s *pushServiceImpl) RegisterDevice(ctx context.Context, userID string, dev
|
||||
}
|
||||
|
||||
// UnregisterDevice 注销设备
|
||||
func (s *pushServiceImpl) UnregisterDevice(ctx context.Context, deviceID string) error {
|
||||
func (s *pushServiceImpl) UnregisterDevice(ctx context.Context, userID string, deviceID string) error {
|
||||
device, err := s.deviceRepo.GetByDeviceID(deviceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("device not found: %w", err)
|
||||
}
|
||||
if device.UserID != userID {
|
||||
return fmt.Errorf("device does not belong to current user")
|
||||
}
|
||||
return s.deviceRepo.Deactivate(deviceID)
|
||||
}
|
||||
|
||||
// UpdateDeviceToken 更新设备Token
|
||||
func (s *pushServiceImpl) UpdateDeviceToken(ctx context.Context, deviceID string, newPushToken string) error {
|
||||
func (s *pushServiceImpl) UpdateDeviceToken(ctx context.Context, userID string, deviceID string, newPushToken string) error {
|
||||
deviceToken, err := s.deviceRepo.GetByDeviceID(deviceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("device not found: %w", err)
|
||||
}
|
||||
if deviceToken.UserID != userID {
|
||||
return fmt.Errorf("device does not belong to current user")
|
||||
}
|
||||
|
||||
deviceToken.PushToken = newPushToken
|
||||
deviceToken.Activate()
|
||||
@@ -417,58 +469,19 @@ func (s *pushServiceImpl) processPushTask(task *pushTask) {
|
||||
return
|
||||
}
|
||||
|
||||
// 提取消息标题和内容
|
||||
_ = task.message.Decrypt()
|
||||
title := "新消息"
|
||||
content := dto.ExtractTextContentFromModel(task.message.Segments)
|
||||
if task.message.IsSystemMessage() || task.message.Category == model.CategoryNotification {
|
||||
if task.message.ExtraData != nil && task.message.ExtraData.ActorName != "" {
|
||||
title = task.message.ExtraData.ActorName
|
||||
} else {
|
||||
title = "系统通知"
|
||||
}
|
||||
}
|
||||
|
||||
extras := map[string]any{
|
||||
"message_id": task.message.ID,
|
||||
"conversation_id": task.message.ConversationID,
|
||||
"sender_id": task.message.SenderID,
|
||||
"category": string(task.message.Category),
|
||||
}
|
||||
if task.message.ExtraData != nil {
|
||||
extras["actor_name"] = task.message.ExtraData.ActorName
|
||||
extras["avatar_url"] = task.message.ExtraData.AvatarURL
|
||||
extras["target_id"] = task.message.ExtraData.TargetID
|
||||
extras["target_type"] = task.message.ExtraData.TargetType
|
||||
}
|
||||
payload := buildMessagePayload(task.message)
|
||||
|
||||
// 尝试使用极光推送(统一推送到所有移动设备)
|
||||
mobileDevices := make([]*model.DeviceToken, 0)
|
||||
for _, device := range devices {
|
||||
if device.SupportsMobilePush() && device.PushToken != "" {
|
||||
mobileDevices = append(mobileDevices, device)
|
||||
}
|
||||
}
|
||||
mobileDevices := getMobileDevices(devices)
|
||||
|
||||
if len(mobileDevices) > 0 {
|
||||
// 优先使用极光推送
|
||||
if s.jpushClient != nil {
|
||||
err := s.pushViaJPushBatch(mobileDevices, title, content, extras)
|
||||
if s.isJPushAvailable() {
|
||||
err := s.pushViaJPushBatch(mobileDevices, payload.Title, payload.Content, payload.Extras)
|
||||
if err == nil {
|
||||
// 极光推送成功,为每个设备创建推送记录
|
||||
for _, device := range mobileDevices {
|
||||
record, rerr := s.CreatePushRecord(ctx, task.userID, task.message.ID, model.PushChannelJPush)
|
||||
if rerr != nil {
|
||||
continue
|
||||
}
|
||||
record.DeviceToken = device.PushToken
|
||||
record.DeviceType = string(device.DeviceType)
|
||||
record.MarkPushed()
|
||||
s.pushRepo.Update(record)
|
||||
}
|
||||
s.batchCreatePushedRecords(ctx, task.userID, task.message.ID, mobileDevices)
|
||||
return
|
||||
}
|
||||
// 极光推送失败,记录错误,逐个设备重试
|
||||
}
|
||||
|
||||
// 极光推送不可用或批量推送失败,逐个设备处理
|
||||
@@ -482,8 +495,8 @@ func (s *pushServiceImpl) processPushTask(task *pushTask) {
|
||||
record.DeviceType = string(device.DeviceType)
|
||||
|
||||
var pushErr error
|
||||
if s.jpushClient != nil {
|
||||
pushErr = s.pushViaJPush(ctx, device, title, content, extras)
|
||||
if s.isJPushAvailable() {
|
||||
pushErr = s.pushViaJPush(ctx, device, payload.Title, payload.Content, payload.Extras)
|
||||
} else {
|
||||
pushErr = errors.New("jpush not configured")
|
||||
}
|
||||
@@ -510,9 +523,29 @@ func (s *pushServiceImpl) getChannelForDevice(device *model.DeviceToken) model.P
|
||||
}
|
||||
}
|
||||
|
||||
// retryFailedPushes 重试失败的推送
|
||||
// isJPushAvailable 检查极光推送是否可用
|
||||
func (s *pushServiceImpl) isJPushAvailable() bool {
|
||||
return s.jpushClient != nil
|
||||
}
|
||||
|
||||
// getMobileDevices 从设备列表中筛选出支持手机推送的活跃设备
|
||||
func getMobileDevices(devices []*model.DeviceToken) []*model.DeviceToken {
|
||||
mobileDevices := make([]*model.DeviceToken, 0, len(devices))
|
||||
for _, d := range devices {
|
||||
if d.SupportsMobilePush() && d.PushToken != "" {
|
||||
mobileDevices = append(mobileDevices, d)
|
||||
}
|
||||
}
|
||||
return mobileDevices
|
||||
}
|
||||
|
||||
// retryFailedPushes 重试失败的推送(使用指数退避)
|
||||
func (s *pushServiceImpl) retryFailedPushes() {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
baseInterval := 5 * time.Minute
|
||||
maxInterval := 30 * time.Minute
|
||||
currentInterval := baseInterval
|
||||
|
||||
ticker := time.NewTicker(currentInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
@@ -520,21 +553,31 @@ func (s *pushServiceImpl) retryFailedPushes() {
|
||||
case <-s.stopChan:
|
||||
return
|
||||
case <-ticker.C:
|
||||
s.doRetry()
|
||||
retryCount := s.doRetry()
|
||||
if retryCount > 0 {
|
||||
currentInterval = baseInterval
|
||||
} else {
|
||||
currentInterval = currentInterval * 2
|
||||
if currentInterval > maxInterval {
|
||||
currentInterval = maxInterval
|
||||
}
|
||||
}
|
||||
ticker.Reset(currentInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// doRetry 执行重试
|
||||
func (s *pushServiceImpl) doRetry() {
|
||||
// doRetry 执行重试,返回本次成功重试的数量
|
||||
func (s *pushServiceImpl) doRetry() int {
|
||||
ctx := context.Background()
|
||||
|
||||
// 获取失败待重试的推送
|
||||
records, err := s.pushRepo.GetFailedPushesForRetry(100)
|
||||
if err != nil {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
|
||||
retriedCount := 0
|
||||
for _, record := range records {
|
||||
// 检查是否过期
|
||||
if record.IsExpired() {
|
||||
@@ -555,6 +598,7 @@ func (s *pushServiceImpl) doRetry() {
|
||||
if s.pushViaWebSocket(ctx, record.UserID, message) {
|
||||
record.MarkDelivered()
|
||||
s.pushRepo.Update(record)
|
||||
retriedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -568,40 +612,21 @@ func (s *pushServiceImpl) doRetry() {
|
||||
}
|
||||
|
||||
var pushErr error
|
||||
if s.jpushClient != nil && device.SupportsMobilePush() && device.PushToken != "" {
|
||||
_ = message.Decrypt()
|
||||
title := "新消息"
|
||||
content := dto.ExtractTextContentFromModel(message.Segments)
|
||||
if message.IsSystemMessage() || message.Category == model.CategoryNotification {
|
||||
if message.ExtraData != nil && message.ExtraData.ActorName != "" {
|
||||
title = message.ExtraData.ActorName
|
||||
} else {
|
||||
title = "系统通知"
|
||||
}
|
||||
}
|
||||
extras := map[string]any{
|
||||
"message_id": message.ID,
|
||||
"conversation_id": message.ConversationID,
|
||||
"sender_id": message.SenderID,
|
||||
"category": string(message.Category),
|
||||
}
|
||||
if message.ExtraData != nil {
|
||||
extras["actor_name"] = message.ExtraData.ActorName
|
||||
extras["avatar_url"] = message.ExtraData.AvatarURL
|
||||
extras["target_id"] = message.ExtraData.TargetID
|
||||
extras["target_type"] = message.ExtraData.TargetType
|
||||
}
|
||||
pushErr = s.pushViaJPush(ctx, device, title, content, extras)
|
||||
if s.isJPushAvailable() && device.SupportsMobilePush() && device.PushToken != "" {
|
||||
payload := buildMessagePayload(message)
|
||||
pushErr = s.pushViaJPush(ctx, device, payload.Title, payload.Content, payload.Extras)
|
||||
}
|
||||
|
||||
if pushErr != nil {
|
||||
record.MarkFailed(pushErr.Error())
|
||||
} else {
|
||||
record.MarkPushed()
|
||||
retriedCount++
|
||||
}
|
||||
s.pushRepo.Update(record)
|
||||
}
|
||||
}
|
||||
return retriedCount
|
||||
}
|
||||
|
||||
// PushChatMessage 推送聊天消息给离线用户
|
||||
@@ -623,7 +648,7 @@ func (s *pushServiceImpl) PushChatMessage(ctx context.Context, userID string, co
|
||||
}
|
||||
|
||||
// 3. 获取用户的移动设备
|
||||
if s.jpushClient == nil {
|
||||
if !s.isJPushAvailable() {
|
||||
return nil
|
||||
}
|
||||
devices, err := s.deviceRepo.GetActiveByUserID(userID)
|
||||
@@ -631,16 +656,16 @@ func (s *pushServiceImpl) PushChatMessage(ctx context.Context, userID string, co
|
||||
return nil
|
||||
}
|
||||
|
||||
var regIDs []string
|
||||
for _, d := range devices {
|
||||
if d.SupportsMobilePush() && d.PushToken != "" {
|
||||
regIDs = append(regIDs, d.PushToken)
|
||||
}
|
||||
}
|
||||
if len(regIDs) == 0 {
|
||||
mobileDevices := getMobileDevices(devices)
|
||||
if len(mobileDevices) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var regIDs []string
|
||||
for _, d := range mobileDevices {
|
||||
regIDs = append(regIDs, d.PushToken)
|
||||
}
|
||||
|
||||
// 4. 构建通知内容
|
||||
title := sender.Name
|
||||
if title == "" {
|
||||
@@ -655,13 +680,13 @@ func (s *pushServiceImpl) PushChatMessage(ctx context.Context, userID string, co
|
||||
}
|
||||
extras := map[string]any{
|
||||
"notification_type": "chat_message",
|
||||
"message_id": message.ID,
|
||||
"conversation_id": message.ConversationID,
|
||||
"message_id": message.ID,
|
||||
"conversation_id": message.ConversationID,
|
||||
"conversation_type": string(convType),
|
||||
"sender_id": message.SenderID,
|
||||
"sender_name": sender.Name,
|
||||
"sender_avatar": sender.Avatar,
|
||||
"category": string(message.Category),
|
||||
"sender_id": message.SenderID,
|
||||
"sender_name": sender.Name,
|
||||
"sender_avatar": sender.Avatar,
|
||||
"category": string(message.Category),
|
||||
}
|
||||
if message.Category == model.CategoryNotification && message.ExtraData != nil {
|
||||
title = message.ExtraData.ActorName
|
||||
@@ -679,7 +704,7 @@ func (s *pushServiceImpl) PushChatMessage(ctx context.Context, userID string, co
|
||||
if sender.Avatar != "" {
|
||||
notification.Android.LargeIcon = sender.Avatar
|
||||
}
|
||||
if _, pushErr := s.jpushClient.PushByRegistrationIDs(regIDs, notification, extras); pushErr != nil {
|
||||
if _, pushErr := s.jpushClient.PushByRegistrationIDs(regIDs, notification); pushErr != nil {
|
||||
zap.L().Error("jpush push chat message failed",
|
||||
zap.String("userID", userID),
|
||||
zap.String("conversationID", conversationID),
|
||||
@@ -717,13 +742,13 @@ func (s *pushServiceImpl) pushSystemViaWebSocket(ctx context.Context, userID str
|
||||
}
|
||||
|
||||
sysMsg := map[string]any{
|
||||
"type": "notification",
|
||||
"type": "notification",
|
||||
"system_type": msgType,
|
||||
"title": title,
|
||||
"content": content,
|
||||
"is_read": false,
|
||||
"extra_data": data,
|
||||
"created_at": time.Now().Format("2006-01-02T15:04:05Z07:00"),
|
||||
"title": title,
|
||||
"content": content,
|
||||
"is_read": false,
|
||||
"extra_data": data,
|
||||
"created_at": time.Now().Format("2006-01-02T15:04:05Z07:00"),
|
||||
}
|
||||
s.wsHub.PublishToUserOnline(userID, "system_notification", sysMsg)
|
||||
return true
|
||||
@@ -737,15 +762,10 @@ func (s *pushServiceImpl) PushSystemNotification(ctx context.Context, userID str
|
||||
}
|
||||
|
||||
// 用户不在线,尝试极光推送
|
||||
if s.jpushClient != nil {
|
||||
if s.isJPushAvailable() {
|
||||
devices, err := s.deviceRepo.GetActiveByUserID(userID)
|
||||
if err == nil && len(devices) > 0 {
|
||||
mobileDevices := make([]*model.DeviceToken, 0)
|
||||
for _, d := range devices {
|
||||
if d.SupportsMobilePush() && d.PushToken != "" {
|
||||
mobileDevices = append(mobileDevices, d)
|
||||
}
|
||||
}
|
||||
mobileDevices := getMobileDevices(devices)
|
||||
if len(mobileDevices) > 0 {
|
||||
content := notification.Content
|
||||
title := notification.Title
|
||||
@@ -777,7 +797,6 @@ func (s *pushServiceImpl) PushSystemNotification(ctx context.Context, userID str
|
||||
return ids
|
||||
}(),
|
||||
jpushNotif,
|
||||
extras,
|
||||
)
|
||||
if pushErr == nil {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user