@@ -20,6 +20,7 @@ import (
20
20
"runtime/debug"
21
21
"strings"
22
22
"sync"
23
+ "time"
23
24
24
25
"golang.org/x/sync/errgroup"
25
26
@@ -42,7 +43,8 @@ const (
42
43
pullMsgGoroutineLimit = 10
43
44
)
44
45
45
- // The callback synchronization starts. The reconnection ends
46
+ // MsgSyncer is a central hub for message relay, responsible for sequential message gap pulling,
47
+ // handling network events, and managing app foreground and background events.
46
48
type MsgSyncer struct {
47
49
loginUserID string // login user ID
48
50
longConnMgr * LongConnMgr // long connection manager
@@ -54,6 +56,8 @@ type MsgSyncer struct {
54
56
syncTimes int // times of sync
55
57
ctx context.Context // context
56
58
reinstalled bool //true if the app was uninstalled and reinstalled
59
+ isSyncing bool // indicates whether data is being synced
60
+ isSyncingLock sync.Mutex // lock for syncing state
57
61
58
62
}
59
63
@@ -183,9 +187,19 @@ func (m *MsgSyncer) handlePushMsgAndEvent(cmd common.Cmd2Value) {
183
187
switch cmd .Cmd {
184
188
case constant .CmdConnSuccesss :
185
189
log .ZInfo (cmd .Ctx , "recv long conn mgr connected" , "cmd" , cmd .Cmd , "value" , cmd .Value )
186
- m .doConnected (cmd .Ctx )
187
- case constant .CmdMaxSeq :
188
- log .ZInfo (cmd .Ctx , "recv max seqs from long conn mgr, start sync msgs" , "cmd" , cmd .Cmd , "value" , cmd .Value )
190
+ if m .startSync () {
191
+ m .doConnected (cmd .Ctx )
192
+ } else {
193
+ log .ZWarn (cmd .Ctx , "syncing, ignore connected event" , nil , "cmd" , cmd .Cmd , "value" , cmd .Value )
194
+ }
195
+ case constant .CmdWakeUpDataSync :
196
+ log .ZInfo (cmd .Ctx , "app wake up, start sync msgs" , "cmd" , cmd .Cmd , "value" , cmd .Value )
197
+ if m .startSync () {
198
+ m .doWakeupDataSync (cmd .Ctx )
199
+ } else {
200
+ log .ZWarn (cmd .Ctx , "syncing, ignore wake up event" , nil , "cmd" , cmd .Cmd , "value" , cmd .Value )
201
+
202
+ }
189
203
m .compareSeqsAndBatchSync (cmd .Ctx , cmd .Value .(* sdk_struct.CmdMaxSeqToMsgSync ).ConversationMaxSeqOnSvr , defaultPullNums )
190
204
case constant .CmdPushMsg :
191
205
m .doPushMsg (cmd .Ctx , cmd .Value .(* sdkws.PushMessages ))
@@ -200,7 +214,9 @@ func (m *MsgSyncer) compareSeqsAndBatchSync(ctx context.Context, maxSeqToSync ma
200
214
messagesSeqMap := make (map [string ]int64 )
201
215
for conversationID , seq := range maxSeqToSync {
202
216
if IsNotification (conversationID ) {
203
- notificationsSeqMap [conversationID ] = seq
217
+ if seq != 0 { // seq is 0, no need to sync
218
+ notificationsSeqMap [conversationID ] = seq
219
+ }
204
220
} else {
205
221
messagesSeqMap [conversationID ] = seq
206
222
}
@@ -243,13 +259,40 @@ func (m *MsgSyncer) compareSeqsAndBatchSync(ctx context.Context, maxSeqToSync ma
243
259
needSyncSeqMap [conversationID ] = [2 ]int64 {syncedMaxSeq + 1 , maxSeq }
244
260
}
245
261
} else {
246
- needSyncSeqMap [conversationID ] = [2 ]int64 {0 , maxSeq }
262
+ if maxSeq != 0 { // seq is 0, no need to sync
263
+ needSyncSeqMap [conversationID ] = [2 ]int64 {0 , maxSeq }
264
+ }
247
265
}
248
266
}
249
267
_ = m .syncAndTriggerMsgs (m .ctx , needSyncSeqMap , pullNums )
250
268
}
251
269
}
252
270
271
+ // startSync checks if the sync is already in progress.
272
+ // If syncing is in progress, it returns false. Otherwise, it starts syncing and returns true.
273
+ func (ms * MsgSyncer ) startSync () bool {
274
+ ms .isSyncingLock .Lock ()
275
+ defer ms .isSyncingLock .Unlock ()
276
+
277
+ if ms .isSyncing {
278
+ // If already syncing, return false
279
+ return false
280
+ }
281
+
282
+ // Set syncing to true and start the sync
283
+ ms .isSyncing = true
284
+
285
+ // Create a goroutine that waits for 5 seconds and then sets isSyncing to false
286
+ go func () {
287
+ time .Sleep (5 * time .Second )
288
+ ms .isSyncingLock .Lock ()
289
+ ms .isSyncing = false
290
+ ms .isSyncingLock .Unlock ()
291
+ }()
292
+
293
+ return true
294
+ }
295
+
253
296
func (m * MsgSyncer ) doPushMsg (ctx context.Context , push * sdkws.PushMessages ) {
254
297
log .ZDebug (ctx , "push msgs" , "push" , push , "syncedMaxSeqs" , m .syncedMaxSeqs )
255
298
m .pushTriggerAndSync (ctx , push .Msgs , m .triggerConversation )
@@ -308,83 +351,83 @@ func (m *MsgSyncer) doConnected(ctx context.Context) {
308
351
}
309
352
}
310
353
354
+ func (m * MsgSyncer ) doWakeupDataSync (ctx context.Context ) {
355
+ common .TriggerCmdSyncData (ctx , m .conversationCh )
356
+ var resp sdkws.GetMaxSeqResp
357
+ if err := m .longConnMgr .SendReqWaitResp (m .ctx , & sdkws.GetMaxSeqReq {UserID : m .loginUserID }, constant .GetNewestSeq , & resp ); err != nil {
358
+ log .ZError (m .ctx , "get max seq error" , err )
359
+ return
360
+ } else {
361
+ log .ZDebug (m .ctx , "get max seq success" , "resp" , resp .MaxSeqs )
362
+ }
363
+ m .compareSeqsAndBatchSync (ctx , resp .MaxSeqs , defaultPullNums )
364
+ }
365
+
311
366
func IsNotification (conversationID string ) bool {
312
367
return strings .HasPrefix (conversationID , "n_" )
313
368
}
314
369
315
- // Fragment synchronization message, seq refresh after successful trigger
316
370
func (m * MsgSyncer ) syncAndTriggerMsgs (ctx context.Context , seqMap map [string ][2 ]int64 , syncMsgNum int64 ) error {
317
- if len (seqMap ) > 0 {
318
- log .ZDebug (ctx , "current sync seqMap" , "seqMap" , seqMap )
319
- var (
320
- tempSeqMap = make (map [string ][2 ]int64 , 50 )
321
- msgNum = 0
322
- )
323
- for k , v := range seqMap {
324
- oneConversationSyncNum := v [1 ] - v [0 ] + 1
325
- if (oneConversationSyncNum / SplitPullMsgNum ) > 1 && IsNotification (k ) {
326
- nSeqMap := make (map [string ][2 ]int64 , 1 )
327
- count := int (oneConversationSyncNum / SplitPullMsgNum )
328
- startSeq := v [0 ]
329
- var end int64
330
- for i := 0 ; i <= count ; i ++ {
331
- if i == count {
332
- nSeqMap [k ] = [2 ]int64 {startSeq , v [1 ]}
333
- } else {
334
- end = startSeq + int64 (SplitPullMsgNum )
335
- if end > v [1 ] {
336
- end = v [1 ]
337
- i = count
338
- }
339
- nSeqMap [k ] = [2 ]int64 {startSeq , end }
340
- }
341
- resp , err := m .pullMsgBySeqRange (ctx , nSeqMap , syncMsgNum )
342
- if err != nil {
343
- log .ZError (ctx , "syncMsgFromSvr err" , err , "nSeqMap" , nSeqMap )
344
- return err
345
- }
346
- _ = m .triggerConversation (ctx , resp .Msgs )
347
- _ = m .triggerNotification (ctx , resp .NotificationMsgs )
348
- for conversationID , seqs := range nSeqMap {
349
- m .syncedMaxSeqs [conversationID ] = seqs [1 ]
350
- }
351
- startSeq = end + 1
352
- }
353
- continue
371
+ if len (seqMap ) == 0 {
372
+ log .ZDebug (ctx , "nothing to sync" , "syncMsgNum" , syncMsgNum )
373
+ return nil
374
+ }
375
+
376
+ log .ZDebug (ctx , "current sync seqMap" , "seqMap" , seqMap )
377
+ var (
378
+ tempSeqMap = make (map [string ][2 ]int64 , 50 )
379
+ msgNum = 0
380
+ )
381
+
382
+ for k , v := range seqMap {
383
+ oneConversationSyncNum := v [1 ] - v [0 ] + 1
384
+ tempSeqMap [k ] = v
385
+ // For notification conversations, use oneConversationSyncNum directly
386
+ if IsNotification (k ) {
387
+ msgNum += int (oneConversationSyncNum )
388
+ } else {
389
+ // For regular conversations, ensure msgNum is the minimum of oneConversationSyncNum and syncMsgNum
390
+ currentSyncMsgNum := int64 (0 )
391
+ if oneConversationSyncNum > syncMsgNum {
392
+ currentSyncMsgNum = syncMsgNum
393
+ } else {
394
+ currentSyncMsgNum = oneConversationSyncNum
354
395
}
355
- tempSeqMap [k ] = v
356
- if oneConversationSyncNum > 0 {
357
- msgNum += int (oneConversationSyncNum )
396
+ msgNum += int (currentSyncMsgNum )
397
+ }
398
+
399
+ // If accumulated msgNum reaches SplitPullMsgNum, trigger a batch pull
400
+ if msgNum >= SplitPullMsgNum {
401
+ resp , err := m .pullMsgBySeqRange (ctx , tempSeqMap , syncMsgNum )
402
+ if err != nil {
403
+ log .ZError (ctx , "syncMsgFromSvr error" , err , "tempSeqMap" , tempSeqMap )
404
+ return err
358
405
}
359
- if msgNum >= SplitPullMsgNum {
360
- resp , err := m .pullMsgBySeqRange (ctx , tempSeqMap , syncMsgNum )
361
- if err != nil {
362
- log .ZError (ctx , "syncMsgFromSvr err" , err , "tempSeqMap" , tempSeqMap )
363
- return err
364
- }
365
- _ = m .triggerConversation (ctx , resp .Msgs )
366
- _ = m .triggerNotification (ctx , resp .NotificationMsgs )
367
- for conversationID , seqs := range tempSeqMap {
368
- m .syncedMaxSeqs [conversationID ] = seqs [1 ]
369
- }
370
- tempSeqMap = make (map [string ][2 ]int64 , 50 )
371
- msgNum = 0
406
+ _ = m .triggerConversation (ctx , resp .Msgs )
407
+ _ = m .triggerNotification (ctx , resp .NotificationMsgs )
408
+ for conversationID , seqs := range tempSeqMap {
409
+ m .syncedMaxSeqs [conversationID ] = seqs [1 ]
372
410
}
411
+ // Reset tempSeqMap and msgNum to handle the next batch
412
+ tempSeqMap = make (map [string ][2 ]int64 , 50 )
413
+ msgNum = 0
373
414
}
415
+ }
374
416
417
+ // Handle remaining messages to ensure all are synced
418
+ if len (tempSeqMap ) > 0 {
375
419
resp , err := m .pullMsgBySeqRange (ctx , tempSeqMap , syncMsgNum )
376
420
if err != nil {
377
- log .ZError (ctx , "syncMsgFromSvr err " , err , "seqMap " , seqMap )
421
+ log .ZError (ctx , "syncMsgFromSvr error " , err , "tempSeqMap " , tempSeqMap )
378
422
return err
379
423
}
380
424
_ = m .triggerConversation (ctx , resp .Msgs )
381
425
_ = m .triggerNotification (ctx , resp .NotificationMsgs )
382
- for conversationID , seqs := range seqMap {
426
+ for conversationID , seqs := range tempSeqMap {
383
427
m .syncedMaxSeqs [conversationID ] = seqs [1 ]
384
428
}
385
- } else {
386
- log .ZDebug (ctx , "noting conversation to sync" , "syncMsgNum" , syncMsgNum )
387
429
}
430
+
388
431
return nil
389
432
}
390
433
0 commit comments