Skip to content

Commit

Permalink
Merge pull request #126 from sendbird/v4.2.26
Browse files Browse the repository at this point in the history
Add 4.2.26.
  • Loading branch information
sf-tyler-jeong authored Oct 28, 2024
2 parents 17191c9 + dcd63f1 commit 63a0786
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 10 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## v4.2.26 (Oct 28, 2024)

### Features
- Added `useAutoResend` in `SendbirdChatOptions`

### Improvements
- Fixed a bug regarding `onReconnectFailed()` event in `ConnectionHandler`

## v4.2.25 (Oct 21, 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.25
sendbird_chat_sdk: ^4.2.26
```
- Run `flutter pub get` command in your project directory.
Expand Down
2 changes: 1 addition & 1 deletion 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.25';
const sdkVersion = '4.2.26';

// Internal implementation for main class. Do not directly access this class.
class Chat with WidgetsBindingObserver {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) 2024 Sendbird, Inc. All rights reserved.

import 'dart:async';

import 'package:sendbird_chat_sdk/sendbird_chat_sdk.dart';
import 'package:sendbird_chat_sdk/src/internal/main/chat/chat.dart';
import 'package:sendbird_chat_sdk/src/internal/main/logger/sendbird_logger.dart';

class AutoResendManager {
AutoResendManager._();

static final AutoResendManager _instance = AutoResendManager._();

factory AutoResendManager() => _instance;

static const int _delayForRateLimit = 200; // Check
bool _isAutoResending = false;
bool _stopAutoResending = false;

void startAutoResend(Chat chat) async {
if (!chat.chatContext.options.useAutoResend) {
sbLog.i(StackTrace.current, 'Returned because of useAutoResend == false');
return;
}

if (_isAutoResending) {
sbLog.i(
StackTrace.current, 'Returned because of _isAutoResending == true');
return;
}

sbLog.i(StackTrace.current, 'Started');
_isAutoResending = true;

try {
for (final collection in chat.collectionManager.baseMessageCollections) {
if (collection is MessageCollection) {
if (collection.channel.isFrozen) {
sbLog.i(StackTrace.current,
'Skipped because of collection.channel.isFrozen == true');
continue;
}

final failedMessages = await collection.getFailedMessages();

for (final failedMessage in failedMessages) {
if (failedMessage.isAutoResendable()) {
// Resend a message
Completer completer = Completer();
SendbirdException? exception;
if (failedMessage is UserMessage) {
collection.channel.resendUserMessage(
failedMessage,
handler: (UserMessage message, SendbirdException? e) {
exception = e;
completer.complete();
},
);
} else if (failedMessage is FileMessage) {
collection.channel.resendFileMessage(
failedMessage,
handler: (FileMessage message, SendbirdException? e) {
exception = e;
completer.complete();
},
);
} else {
// Defensive code
completer.complete();
}
await completer.future;

if (exception != null) {
sbLog.i(
StackTrace.current, 'Stopped because of exception != null');
break;
}

if (_stopAutoResending) break;

// Delay to avoid the rate limit
await Future.delayed(
const Duration(milliseconds: _delayForRateLimit));
}

if (_stopAutoResending) break;
}
}

if (_stopAutoResending) break;
}
} catch (e) {
sbLog.e(StackTrace.current, e.toString());
}

_stopAutoResending = false;
_isAutoResending = false;
sbLog.i(StackTrace.current, 'Stopped');
}

void stopAutoResend() {
if (_isAutoResending) {
sbLog.i(StackTrace.current);
_stopAutoResending = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:sendbird_chat_sdk/sendbird_chat_sdk.dart';
import 'package:sendbird_chat_sdk/src/internal/db/schema/channel/meta/channel_info.dart';
import 'package:sendbird_chat_sdk/src/internal/db/schema/message/meta/message_changelog_info.dart';
import 'package:sendbird_chat_sdk/src/internal/main/chat/chat.dart';
import 'package:sendbird_chat_sdk/src/internal/main/chat_manager/collection_manager/auto_resend_manager.dart';
import 'package:sendbird_chat_sdk/src/internal/main/logger/sendbird_logger.dart';
import 'package:sendbird_chat_sdk/src/internal/network/http/http_client/request/channel/message/channel_messages_gap_request.dart';
import 'package:sendbird_chat_sdk/src/internal/network/http/http_client/request/channel/message/channel_messages_get_request.dart';
Expand Down Expand Up @@ -75,12 +76,22 @@ class CollectionManager {
await _chat.dbManager.checkDBFileSize();
}
//- [DBManager]

AutoResendManager().startAutoResend(_chat);
}

Future<void> onDisconnected() async {
sbLog.d(StackTrace.current);

AutoResendManager().stopAutoResend();
}

Future<void> onReconnected() async {
sbLog.d(StackTrace.current);

await _refresh();

AutoResendManager().startAutoResend(_chat);
}

Future<void> _refresh() async {
Expand Down
8 changes: 5 additions & 3 deletions lib/src/internal/main/chat_manager/connection_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,6 @@ class ConnectionManager {
final disconnectedUserId = chat.chatContext.currentUserId ?? '';

if (clear || logout) {
await chat.eventDispatcher.onLogout();

chat.messageQueueMap.forEach((key, q) => q.cleanUp());
chat.messageQueueMap.clear();
// chat.uploads.forEach((key, value) => _api.cancelUploadingFile(key));
Expand All @@ -281,6 +279,8 @@ class ConnectionManager {
chat.apiClient.cleanUp();

if (logout) {
await chat.eventDispatcher.onLogout();

chat.chatContext.cleanUp();
chat.collectionManager.cleanUpGroupChannelCollections();
chat.collectionManager.cleanUpMessageCollections();
Expand Down Expand Up @@ -311,8 +311,10 @@ class ConnectionManager {

if (chat.chatContext.currentUser == null ||
chat.chatContext.sessionKey == null) {
if (isReconnecting()) {
chat.eventManager.notifyReconnectFailed();
}
changeState(DisconnectedState(chat: chat));
chat.eventManager.notifyReconnectFailed();
return false;
}

Expand Down
1 change: 1 addition & 0 deletions lib/src/internal/main/chat_manager/event_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class EventDispatcher {

Future<void> onDisconnected() async {
sbLog.d(StackTrace.current);
_chat.collectionManager.onDisconnected();
}

Future<void> onReconnecting() async {
Expand Down
11 changes: 11 additions & 0 deletions lib/src/public/core/message/base_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,17 @@ class BaseMessage extends RootMessage {
return result;
}

bool isAutoResendable() {
if (errorCode == SendbirdError.connectionRequired ||
errorCode == SendbirdError.webSocketConnectionClosed ||
errorCode == SendbirdError.webSocketConnectionFailed ||
errorCode == SendbirdError.requestFailed || // Check
errorCode == SendbirdError.socketChannelFrozen) {
return true;
}
return false;
}

/// Returns [MessageMetaArray] list which is filtered by given metaArrayKeys.
List<MessageMetaArray> getMetaArrays(List<String> keys) {
sbLog.i(StackTrace.current, 'keys: $keys');
Expand Down
25 changes: 25 additions & 0 deletions lib/src/public/main/chat/sendbird_chat_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ class SendbirdChatOptions {
static const defaultFileTransferTimeout = 30;
static const defaultTypingIndicatorThrottle = 1000;
static const defaultUseMemberInfoInMessage = true;
static const defaultUseAutoResend = false;

bool _useCollectionCaching = defaultUseCollectionCaching;
int _connectionTimeout = defaultConnectionTimeout;
int _webSocketTimeout = defaultWebSocketTimeout;
int _fileTransferTimeout = defaultFileTransferTimeout;
int _typingIndicatorThrottle = defaultTypingIndicatorThrottle;
bool _useMemberInfoInMessage = defaultUseMemberInfoInMessage;
bool _useAutoResend = defaultUseAutoResend;

SendbirdChatOptions({
bool? useCollectionCaching = defaultUseCollectionCaching,
Expand All @@ -26,13 +28,16 @@ class SendbirdChatOptions {
int? fileTransferTimeout = defaultFileTransferTimeout,
int? typingIndicatorThrottle = defaultTypingIndicatorThrottle,
bool? useMemberInfoInMessage = defaultUseMemberInfoInMessage,
bool? useAutoResend = defaultUseAutoResend,
}) {
this.useCollectionCaching = useCollectionCaching;
this.connectionTimeout = connectionTimeout;
this.webSocketTimeout = webSocketTimeout;
this.fileTransferTimeout = fileTransferTimeout;
this.typingIndicatorThrottle = typingIndicatorThrottle;
this.useMemberInfoInMessage = useMemberInfoInMessage;
this.useAutoResend = useAutoResend;
this.useAutoResend = _useCollectionCaching ? useAutoResend : false;
}

bool get useCollectionCaching => _useCollectionCaching;
Expand Down Expand Up @@ -105,4 +110,24 @@ class SendbirdChatOptions {
set useMemberInfoInMessage(value) {
_useMemberInfoInMessage = value;
}

bool get useAutoResend => _useAutoResend;

/// If set `true` and `useCollectionCaching` is `true`,
/// the failed messages will be resent automatically
/// when the WebSocket is reconnected
///
/// With local caching, you can temporarily keep an unsent message in the local cache
/// if the WebSocket connection is lost.
/// The Chat SDK with local caching marks the failed message as pending, stores it locally,
/// and automatically resends the pending message when the WebSocket is reconnected.
/// This is called auto resend.
/// The default value is `false`.
///
/// @since 4.2.26
set useAutoResend(value) {
if (_useCollectionCaching) {
_useAutoResend = value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:collection/collection.dart';
import 'package:sendbird_chat_sdk/sendbird_chat_sdk.dart';
import 'package:sendbird_chat_sdk/src/internal/main/chat/chat.dart';
import 'package:sendbird_chat_sdk/src/internal/main/chat_cache/cache_service.dart';
import 'package:sendbird_chat_sdk/src/internal/main/chat_manager/collection_manager/auto_resend_manager.dart';
import 'package:sendbird_chat_sdk/src/internal/main/chat_manager/collection_manager/collection_manager.dart';
import 'package:sendbird_chat_sdk/src/internal/main/chat_manager/db_manager.dart';
import 'package:sendbird_chat_sdk/src/internal/main/logger/sendbird_logger.dart';
Expand Down Expand Up @@ -397,6 +398,8 @@ abstract class BaseMessageCollection {
throw exception;
}
}

AutoResendManager().startAutoResend(chat);
}

void _setValuesForInitialize({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,20 @@ class MessageCollection extends BaseMessageCollection {
/// Gets all failed messages of this MessageCollection
/// @since 4.2.0
Future<List<BaseMessage>> getFailedMessages() async {
sbLog.i(StackTrace.current, 'getFailedMessages()');
return await chat.dbManager.getFailedMessages(
final failedMessages = await chat.dbManager.getFailedMessages(
channelType: ChannelType.group,
channelUrl: channel.channelUrl,
);
sbLog.i(StackTrace.current, '${failedMessages.length}');
return failedMessages;
}

/// Removes specific failed messages of this MessageCollection.
/// @since 4.2.0
Future<void> removeFailedMessages({
required List<BaseMessage> messages,
}) async {
sbLog.i(StackTrace.current, 'removeFailedMessages()');
sbLog.i(StackTrace.current, '${messages.length}');
await chat.dbManager.removeFailedMessages(
channelType: ChannelType.group,
channelUrl: channel.channelUrl,
Expand All @@ -76,7 +77,7 @@ class MessageCollection extends BaseMessageCollection {
/// Removes all failed messages of this MessageCollection.
/// @since 4.2.0
Future<void> removeAllFailedMessages() async {
sbLog.i(StackTrace.current, 'removeAllFailedMessages()');
sbLog.i(StackTrace.current);
await chat.dbManager.removeAllFailedMessages(
channelType: ChannelType.group,
channelUrl: channel.channelUrl,
Expand Down
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.25
version: 4.2.26
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 63a0786

Please sign in to comment.