Skip to content

Commit

Permalink
Merge pull request #125 from sendbird/v4.2.25
Browse files Browse the repository at this point in the history
Add 4.2.25.
  • Loading branch information
sf-tyler-jeong authored Oct 21, 2024
2 parents 1727cfb + a0cfc84 commit 17191c9
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 36 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v4.2.25 (Oct 21, 2024)

### Improvements
- Fixed the reconnection bug while entering foreground
- Modified the endpoint of sbm metric

## v4.2.24 (Oct 8, 2024)

### Improvements
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Before installing Sendbird Chat SDK, you need to create a Sendbird application o

```yaml
dependencies:
sendbird_chat_sdk: ^4.2.24
sendbird_chat_sdk: ^4.2.25
```
- Run `flutter pub get` command in your project directory.
Expand Down
12 changes: 9 additions & 3 deletions lib/src/internal/main/chat/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ part 'chat_notifications.dart';
part 'chat_push.dart';
part 'chat_user.dart';

const sdkVersion = '4.2.24';
const sdkVersion = '4.2.25';

// Internal implementation for main class. Do not directly access this class.
class Chat with WidgetsBindingObserver {
Expand Down Expand Up @@ -91,6 +91,7 @@ class Chat with WidgetsBindingObserver {

bool? _isObserverRegistered;
int lastMarkAsReadTimestamp;
bool isBackground = false;

// This allows a value of type T or T? to be treated as a value of type T?.
// We use this so that APIs that have become non-nullable can still be used
Expand Down Expand Up @@ -176,8 +177,13 @@ class Chat with WidgetsBindingObserver {
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
sbLog.i(StackTrace.current, 'state: $state');

if (state == AppLifecycleState.paused) await _handleEnterBackground();
if (state == AppLifecycleState.resumed) await _handleEnterForeground();
if (state == AppLifecycleState.paused) {
isBackground = true;
await _handleEnterBackground();
} else if (state == AppLifecycleState.resumed) {
isBackground = false;
await _handleEnterForeground();
}
}

Future<void> _handleEnterBackground() async {
Expand Down
17 changes: 11 additions & 6 deletions lib/src/internal/main/chat_manager/connection_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ class ConnectionManager {
);
}

Future<void> disconnect({required logout}) async {
Future<void> disconnect({required bool logout}) async {
await _currentState.disconnect(logout: logout);
}

Future<bool> reconnect({bool reset = false}) async {
Future<bool> reconnect({required bool reset}) async {
return await _currentState.reconnect(reset: reset);
}

Expand Down Expand Up @@ -242,6 +242,7 @@ class ConnectionManager {
Future<void> doDisconnect({
required bool clear,
bool logout = false,
bool fromEnterBackground = false,
}) async {
sbLog.i(
StackTrace.current,
Expand All @@ -262,7 +263,7 @@ class ConnectionManager {
}
}

await webSocketClient.close();
final isClosedSuccessfully = await webSocketClient.close();

final disconnectedUserId = chat.chatContext.currentUserId ?? '';

Expand Down Expand Up @@ -294,10 +295,14 @@ class ConnectionManager {
await chat.eventDispatcher.onDisconnected();
}

changeState(DisconnectedState(chat: chat));
if (fromEnterBackground && !chat.isBackground && !isClosedSuccessfully) {
chat.connectionManager.reconnect(reset: true); // Check
} else {
changeState(DisconnectedState(chat: chat));

if (clear && disconnectedUserId.isNotEmpty) {
chat.eventManager.notifyDisconnected(disconnectedUserId);
if (clear && disconnectedUserId.isNotEmpty) {
chat.eventManager.notifyDisconnected(disconnectedUserId);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ abstract class BaseConnectionState {
String? apiHost,
String? wsHost,
});
Future<void> disconnect({required logout});
Future<bool> reconnect({bool reset = false});
Future<void> disconnect({required bool logout});
Future<bool> reconnect({required bool reset});

Future<void> enterBackground();
Future<void> enterForeground();
Expand Down
5 changes: 3 additions & 2 deletions lib/src/internal/main/connection_state/connected_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ConnectedState extends BaseConnectionState {
}

@override
Future<void> disconnect({required logout}) async {
Future<void> disconnect({required bool logout}) async {
sbLog.i(StackTrace.current);
await chat.connectionManager.doDisconnect(clear: logout, logout: logout);
}
Expand All @@ -51,7 +51,8 @@ class ConnectedState extends BaseConnectionState {
@override
Future<void> enterBackground() async {
sbLog.i(StackTrace.current);
await chat.connectionManager.doDisconnect(clear: false);
await chat.connectionManager
.doDisconnect(clear: false, fromEnterBackground: true);
}

@override
Expand Down
5 changes: 3 additions & 2 deletions lib/src/internal/main/connection_state/connecting_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class ConnectingState extends BaseConnectionState {
}

@override
Future<void> disconnect({required logout}) async {
Future<void> disconnect({required bool logout}) async {
sbLog.i(StackTrace.current);
await chat.connectionManager.doDisconnect(clear: logout, logout: logout);
}
Expand All @@ -52,7 +52,8 @@ class ConnectingState extends BaseConnectionState {
@override
Future<void> enterBackground() async {
sbLog.i(StackTrace.current);
await chat.connectionManager.doDisconnect(clear: false);
await chat.connectionManager
.doDisconnect(clear: false, fromEnterBackground: true);
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class DisconnectedState extends BaseConnectionState {
}

@override
Future<void> disconnect({required logout}) async {
Future<void> disconnect({required bool logout}) async {
sbLog.i(StackTrace.current);
await chat.connectionManager.doDisconnect(clear: logout, logout: logout);
}
Expand All @@ -51,7 +51,8 @@ class DisconnectedState extends BaseConnectionState {
@override
Future<void> enterBackground() async {
sbLog.i(StackTrace.current);
await chat.connectionManager.doDisconnect(clear: false);
await chat.connectionManager
.doDisconnect(clear: false, fromEnterBackground: true);
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class ReconnectingState extends BaseConnectionState {
}

@override
Future<void> disconnect({required logout}) async {
Future<void> disconnect({required bool logout}) async {
sbLog.i(StackTrace.current);
await chat.connectionManager.doDisconnect(clear: logout, logout: logout);
}
Expand All @@ -50,7 +50,8 @@ class ReconnectingState extends BaseConnectionState {
@override
Future<void> enterBackground() async {
sbLog.i(StackTrace.current);
await chat.connectionManager.doDisconnect(clear: false);
await chat.connectionManager
.doDisconnect(clear: false, fromEnterBackground: true);
}

@override
Expand Down
74 changes: 59 additions & 15 deletions lib/src/internal/main/stats/stat_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'package:sendbird_chat_sdk/src/internal/main/stats/stat_state.dart';
import 'package:sendbird_chat_sdk/src/internal/main/stats/stat_type.dart';
import 'package:sendbird_chat_sdk/src/internal/main/stats/stat_utils.dart';
import 'package:sendbird_chat_sdk/src/internal/main/utils/json_converter.dart';
import 'package:sendbird_chat_sdk/src/internal/network/http/http_client/request/main/upload_notification_stat_request.dart';
import 'package:sendbird_chat_sdk/src/internal/network/http/http_client/request/main/upload_stat_request.dart';
import 'package:sendbird_chat_sdk/src/internal/network/websocket/event/login_event.dart';
import 'package:sendbird_chat_sdk/src/public/main/define/exceptions.dart';
Expand Down Expand Up @@ -241,19 +242,55 @@ class StatManager {
await _clearDisallowedStats(); // Defensive code

final deviceId = await defaultStatPrefs.deviceId;

final dailyRecordStats = (await dailyRecordStatPrefs.uploadCandidateStats)
.take(_maxStatCountPerRequest)
.toList();

final copiedStats = cachedDefaultStats
.take(_maxStatCountPerRequest - dailyRecordStats.length)
.toList();

final List<NotificationStat> notificationStats = [];
final List<DefaultStat> otherStats = [];
final List<DefaultStat> remainingDefaultStats = [...cachedDefaultStats];

for (DefaultStat stat in copiedStats) {
if (stat is NotificationStat) {
notificationStats.add(stat);
} else {
otherStats.add(stat);
}
}

Object? exception;
bool wereNotificationStatsSent = false;
try {
final stats = [...dailyRecordStats, ...copiedStats];
await _chat.apiClient.send(
UploadStatRequest(_chat, deviceId: deviceId, stats: stats),
);
if (notificationStats.isNotEmpty) {
// Send notificationStats
await _chat.apiClient.send(
UploadNotificationStatRequest(_chat,
deviceId: deviceId, stats: notificationStats),
);

for (NotificationStat stat in notificationStats) {
remainingDefaultStats.remove(stat);
}

wereNotificationStatsSent = true;
}

if (dailyRecordStats.isNotEmpty || otherStats.isNotEmpty) {
// Send otherStats
await _chat.apiClient.send(
UploadStatRequest(_chat,
deviceId: deviceId, stats: [...dailyRecordStats, ...otherStats]),
);

for (DefaultStat stat in otherStats) {
remainingDefaultStats.remove(stat);
}
}
} catch (e) {
if (copiedStats.length >= _minStatCount) {
_minStatCount += _intervalCountToTryAgain;
Expand All @@ -271,20 +308,11 @@ class StatManager {
if (exception == null) {
_minStatCount = _initialMinStatCount;

final List<DefaultStat> remainingStats = [];
try {
remainingStats.addAll(cachedDefaultStats
.sublist(copiedStats.length, cachedDefaultStats.length)
.toList());
} catch (e) {
sbLog.d(StackTrace.current, 'e: ${e.toString()}');
}

cachedDefaultStats.clear();
cachedDefaultStats.addAll(remainingStats);
cachedDefaultStats.addAll(remainingDefaultStats);
await defaultStatPrefs
.updateLastSentAt(DateTime.now().millisecondsSinceEpoch);
await defaultStatPrefs.putStats(remainingStats);
await defaultStatPrefs.putStats(remainingDefaultStats);
await dailyRecordStatPrefs.remove(dailyRecordStats);

sbLog.d(
Expand All @@ -294,6 +322,22 @@ class StatManager {
' cachedDefaultStats: ${cachedDefaultStats.length},'
' defaultStatPrefs: ${await defaultStatPrefs.statCount},'
' dailyRecordStatPrefs: ${(await dailyRecordStatPrefs.stats).length}');
} else if (wereNotificationStatsSent) {
_minStatCount = _initialMinStatCount;

cachedDefaultStats.clear();
cachedDefaultStats.addAll(remainingDefaultStats);
await defaultStatPrefs
.updateLastSentAt(DateTime.now().millisecondsSinceEpoch);
await defaultStatPrefs.putStats(remainingDefaultStats);

sbLog.d(
StackTrace.current,
'[StatTest][NotificationStatsSent] deviceId: $deviceId,'
' pendingDefaultStats: ${pendingDefaultStats.length},'
' cachedDefaultStats: ${cachedDefaultStats.length},'
' defaultStatPrefs: ${await defaultStatPrefs.statCount},'
' dailyRecordStatPrefs: ${(await dailyRecordStatPrefs.stats).length}');
}

_isFlushing = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2023 Sendbird, Inc. All rights reserved.

import 'package:sendbird_chat_sdk/src/internal/main/chat/chat.dart';
import 'package:sendbird_chat_sdk/src/internal/main/stats/model/base_stat.dart';
import 'package:sendbird_chat_sdk/src/internal/network/http/http_client/http_client.dart';
import 'package:sendbird_chat_sdk/src/internal/network/http/http_client/request/api_request.dart';

class UploadNotificationStatRequest extends ApiRequest {
@override
HttpMethod get method => HttpMethod.post;

static const statUrl = 'sdk/notification_statistics';

UploadNotificationStatRequest(
Chat chat, {
required String deviceId,
required List<BaseStat> stats,
}) : super(chat: chat) {
url = statUrl;
body = {
'device_id': deviceId,
'log_entries': stats.map((stat) => stat.toJson()).toList(),
};
userId = null;
}
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: sendbird_chat_sdk
description: With Sendbird Chat for Flutter, you can easily build an in-app chat with all the essential messaging features.
version: 4.2.24
version: 4.2.25
homepage: https://sendbird.com
repository: https://github.com/sendbird/sendbird-chat-sdk-flutter
documentation: https://sendbird.com/docs/chat/sdk/v4/flutter/getting-started/send-first-message
Expand Down

0 comments on commit 17191c9

Please sign in to comment.