Merge branch 'develop' of https://github.com/GetStream/stream-chat-flutter into feat/capabilities

 Conflicts:
	packages/stream_chat/CHANGELOG.md
	packages/stream_chat_flutter/CHANGELOG.md
This commit is contained in:
Deven Joshi
2022-01-05 14:14:03 +05:30
33 changed files with 311 additions and 140 deletions
@@ -1538,6 +1538,7 @@ class ChannelClientState {
members: List.from(
channelState.members..removeWhere((m) => m.userId == user!.id),
),
read: channelState.read..removeWhere((r) => r.user.id == user!.id),
));
}));
}
@@ -1698,7 +1699,7 @@ class ChannelClientState {
}
_channelState = _channelState.copyWith(
messages: newMessages,
messages: newMessages..sort(_sortByCreatedAt),
channel: _channelState.channel?.copyWith(
lastMessageAt: message.createdAt,
),
@@ -1316,6 +1316,10 @@ class StreamChatClient {
},
);
/// Get OpenGraph data of the given [url].
Future<OGAttachmentResponse> enrichUrl(String url) =>
_chatApi.general.enrichUrl(url);
/// Closes the [_ws] connection and resets the [state]
/// If [flushChatPersistence] is true the client deletes all offline
/// user's data.
@@ -71,14 +71,15 @@ class RetryQueue {
/// Add a list of messages
void add(List<Message> messages) {
if (messages.isEmpty) return;
if (_messageQueue.containsAllMessage(messages)) return;
if (!_messageQueue.containsAllMessage(messages)) {
logger?.info('Adding ${messages.length} messages');
final messageList = _messageQueue.toList();
// we should not add message if already available in the queue
_messageQueue.addAll(messages.where(
(it) => !messageList.any((m) => m.id == it.id),
));
}
logger?.info('Adding ${messages.length} messages');
final messageList = _messageQueue.toList();
// we should not add message if already available in the queue
_messageQueue.addAll(messages.where(
(it) => !messageList.any((m) => m.id == it.id),
));
_startRetrying();
}
@@ -90,17 +91,21 @@ class RetryQueue {
while (_messageQueue.isNotEmpty) {
logger?.info('${_messageQueue.length} messages remaining in the queue');
final message = _messageQueue.first;
await _runAndRetry(message);
final succeeded = await _runAndRetry(message);
if (!succeeded) {
_messageQueue.toList().forEach(_sendFailedEvent);
break;
}
}
_isRetrying = false;
}
Future<void> _runAndRetry(Message message) async {
Future<bool> _runAndRetry(Message message) async {
var attempt = 1;
final maxAttempt = _retryPolicy.maxRetryAttempts;
// early return in case maxAttempt is less than 0
if (attempt > maxAttempt) return;
if (attempt > maxAttempt) return false;
// ignore: literal_only_boolean_expressions
while (true) {
@@ -109,8 +114,12 @@ class RetryQueue {
await _retryMessage(message);
logger?.info('Message (${message.id}) sent successfully');
_messageQueue.removeMessage(message);
break;
} on StreamChatError catch (e) {
return true;
} catch (e) {
if (e is! StreamChatNetworkError || !e.isRetriable) {
_messageQueue.removeMessage(message);
return true;
}
// retry logic
final maxAttempt = _retryPolicy.maxRetryAttempts;
if (attempt < maxAttempt) {
@@ -143,16 +152,9 @@ class RetryQueue {
_sendFailedEvent(message);
break;
}
} catch (e) {
logger?.info(
'API call failed due to unknown error (attempt $attempt). '
'Giving up for now, will retry when connection recovers. '
'Error was $e',
);
_sendFailedEvent(message);
break;
}
}
return false;
}
void _sendFailedEvent(Message message) {
@@ -96,4 +96,16 @@ class GeneralApi {
return QueryMembersResponse.fromJson(response.data);
}
/// Get OpenGraph data of the given [url].
Future<OGAttachmentResponse> enrichUrl(String url) async {
final response = await _client.get(
'/og',
queryParameters: {
'url': url,
},
);
return OGAttachmentResponse.fromJson(response.data);
}
}
@@ -442,3 +442,43 @@ class ChannelStateResponse extends _BaseResponse {
static ChannelStateResponse fromJson(Map<String, dynamic> json) =>
_$ChannelStateResponseFromJson(json);
}
/// Model response for [Client.enrichUrl] api call.
@JsonSerializable(createToJson: false)
class OGAttachmentResponse extends _BaseResponse {
/// The URL of the page that was scraped.
late String ogScrapeUrl;
/// The URL of the asset.
String? assetUrl;
/// The URL of the author.
String? authorLink;
/// The name of the author.
String? authorName;
/// The URL of the image.
String? imageUrl;
/// The text of the attachment.
String? text;
/// The URL of the thumbnail.
String? thumbUrl;
/// The title of the attachment.
String? title;
/// The URL of the title.
String? titleLink;
/// The type of the attachment.
///
/// 'video' | 'audio' | 'image'
String? type;
/// Create a new instance from a [json].
static OGAttachmentResponse fromJson(Map<String, dynamic> json) =>
_$OGAttachmentResponseFromJson(json);
}
@@ -273,3 +273,18 @@ ChannelStateResponse _$ChannelStateResponseFromJson(
?.map((e) => Read.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
OGAttachmentResponse _$OGAttachmentResponseFromJson(
Map<String, dynamic> json) =>
OGAttachmentResponse()
..duration = json['duration'] as String?
..ogScrapeUrl = json['og_scrape_url'] as String
..assetUrl = json['asset_url'] as String?
..authorLink = json['author_link'] as String?
..authorName = json['author_name'] as String?
..imageUrl = json['image_url'] as String?
..text = json['text'] as String?
..thumbUrl = json['thumb_url'] as String?
..title = json['title'] as String?
..titleLink = json['title_link'] as String?
..type = json['type'] as String?;