added null safety for llc

This commit is contained in:
Deven Joshi
2021-04-08 15:03:16 +05:30
parent 3a5308a9c0
commit c80fc0a6b4
41 changed files with 1222 additions and 1202 deletions
File diff suppressed because it is too large Load Diff
+11 -11
View File
@@ -34,7 +34,7 @@ class SortOption<T> {
/// Sorting field Comparator required for offline sorting
@JsonKey(ignore: true)
final Comparator<T> comparator;
final Comparator<T>? comparator;
/// Serialize model to json
Map<String, dynamic> toJson() => _$SortOptionToJson(this);
@@ -70,31 +70,31 @@ class PaginationParams {
/// Filter on ids greater than the given value.
@JsonKey(name: 'id_gt')
final String greaterThan;
final String? greaterThan;
/// Filter on ids greater than or equal to the given value.
@JsonKey(name: 'id_gte')
final String greaterThanOrEqual;
final String? greaterThanOrEqual;
/// Filter on ids smaller than the given value.
@JsonKey(name: 'id_lt')
final String lessThan;
final String? lessThan;
/// Filter on ids smaller than or equal to the given value.
@JsonKey(name: 'id_lte')
final String lessThanOrEqual;
final String? lessThanOrEqual;
/// Serialize model to json
Map<String, dynamic> toJson() => _$PaginationParamsToJson(this);
/// Creates a copy of [PaginationParams] with specified attributes overridden.
PaginationParams copyWith({
int limit,
int offset,
String greaterThan,
String greaterThanOrEqual,
String lessThan,
String lessThanOrEqual,
int? limit,
int? offset,
String? greaterThan,
String? greaterThanOrEqual,
String? lessThan,
String? lessThanOrEqual,
}) =>
PaginationParams(
limit: limit ?? this.limit,
+102 -102
View File
@@ -13,192 +13,192 @@ import 'package:stream_chat/src/models/user.dart';
part 'responses.g.dart';
class _BaseResponse {
String duration;
String? duration;
}
/// Model response for [StreamChatClient.resync] api call
@JsonSerializable(createToJson: false)
class SyncResponse extends _BaseResponse {
/// The list of events
List<Event> events;
List<Event>? events;
/// Create a new instance from a json
static SyncResponse fromJson(Map<String, dynamic> json) =>
_$SyncResponseFromJson(json);
static SyncResponse fromJson(Map<String, dynamic>? json) =>
_$SyncResponseFromJson(json!);
}
/// Model response for [StreamChatClient.queryChannels] api call
@JsonSerializable(createToJson: false)
class QueryChannelsResponse extends _BaseResponse {
/// List of channels state returned by the query
List<ChannelState> channels;
List<ChannelState>? channels;
/// Create a new instance from a json
static QueryChannelsResponse fromJson(Map<String, dynamic> json) =>
_$QueryChannelsResponseFromJson(json);
static QueryChannelsResponse fromJson(Map<String, dynamic>? json) =>
_$QueryChannelsResponseFromJson(json!);
}
/// Model response for [StreamChatClient.queryChannels] api call
@JsonSerializable(createToJson: false)
class TranslateMessageResponse extends _BaseResponse {
/// List of channels state returned by the query
TranslatedMessage message;
TranslatedMessage? message;
/// Create a new instance from a json
static TranslateMessageResponse fromJson(Map<String, dynamic> json) =>
_$TranslateMessageResponseFromJson(json);
static TranslateMessageResponse fromJson(Map<String, dynamic>? json) =>
_$TranslateMessageResponseFromJson(json!);
}
/// Model response for [StreamChatClient.queryChannels] api call
@JsonSerializable(createToJson: false)
class QueryMembersResponse extends _BaseResponse {
/// List of channels state returned by the query
List<Member> members;
List<Member>? members;
/// Create a new instance from a json
static QueryMembersResponse fromJson(Map<String, dynamic> json) =>
_$QueryMembersResponseFromJson(json);
static QueryMembersResponse fromJson(Map<String, dynamic>? json) =>
_$QueryMembersResponseFromJson(json!);
}
/// Model response for [StreamChatClient.queryUsers] api call
@JsonSerializable(createToJson: false)
class QueryUsersResponse extends _BaseResponse {
/// List of users returned by the query
List<User> users;
List<User>? users;
/// Create a new instance from a json
static QueryUsersResponse fromJson(Map<String, dynamic> json) =>
_$QueryUsersResponseFromJson(json);
static QueryUsersResponse fromJson(Map<String, dynamic>? json) =>
_$QueryUsersResponseFromJson(json!);
}
/// Model response for [channel.getReactions] api call
@JsonSerializable(createToJson: false)
class QueryReactionsResponse extends _BaseResponse {
/// List of reactions returned by the query
List<Reaction> reactions;
List<Reaction>? reactions;
/// Create a new instance from a json
static QueryReactionsResponse fromJson(Map<String, dynamic> json) =>
_$QueryReactionsResponseFromJson(json);
static QueryReactionsResponse fromJson(Map<String, dynamic>? json) =>
_$QueryReactionsResponseFromJson(json!);
}
/// Model response for [Channel.getReplies] api call
@JsonSerializable(createToJson: false)
class QueryRepliesResponse extends _BaseResponse {
/// List of messages returned by the api call
List<Message> messages;
List<Message>? messages;
/// Create a new instance from a json
static QueryRepliesResponse fromJson(Map<String, dynamic> json) =>
_$QueryRepliesResponseFromJson(json);
static QueryRepliesResponse fromJson(Map<String, dynamic>? json) =>
_$QueryRepliesResponseFromJson(json!);
}
/// Model response for [StreamChatClient.getDevices] api call
@JsonSerializable(createToJson: false)
class ListDevicesResponse extends _BaseResponse {
/// List of user devices
List<Device> devices;
List<Device>? devices;
/// Create a new instance from a json
static ListDevicesResponse fromJson(Map<String, dynamic> json) =>
_$ListDevicesResponseFromJson(json);
static ListDevicesResponse fromJson(Map<String, dynamic>? json) =>
_$ListDevicesResponseFromJson(json!);
}
/// Model response for [Channel.sendFile] api call
@JsonSerializable(createToJson: false)
class SendFileResponse extends _BaseResponse {
/// The url of the uploaded file
String file;
String? file;
/// Create a new instance from a json
static SendFileResponse fromJson(Map<String, dynamic> json) =>
_$SendFileResponseFromJson(json);
static SendFileResponse fromJson(Map<String, dynamic>? json) =>
_$SendFileResponseFromJson(json!);
}
/// Model response for [Channel.sendImage] api call
@JsonSerializable(createToJson: false)
class SendImageResponse extends _BaseResponse {
/// The url of the uploaded file
String file;
String? file;
/// Create a new instance from a json
static SendImageResponse fromJson(Map<String, dynamic> json) =>
_$SendImageResponseFromJson(json);
static SendImageResponse fromJson(Map<String, dynamic>? json) =>
_$SendImageResponseFromJson(json!);
}
/// Model response for [Channel.sendReaction] api call
@JsonSerializable(createToJson: false)
class SendReactionResponse extends _BaseResponse {
/// Message returned by the api call
Message message;
Message? message;
/// The reaction created by the api call
Reaction reaction;
Reaction? reaction;
/// Create a new instance from a json
static SendReactionResponse fromJson(Map<String, dynamic> json) =>
_$SendReactionResponseFromJson(json);
static SendReactionResponse fromJson(Map<String, dynamic>? json) =>
_$SendReactionResponseFromJson(json!);
}
/// Model response for [StreamChatClient.connectGuestUser] api call
@JsonSerializable(createToJson: false)
class ConnectGuestUserResponse extends _BaseResponse {
/// Guest user access token
String accessToken;
String? accessToken;
/// Guest user
User user;
User? user;
/// Create a new instance from a json
static ConnectGuestUserResponse fromJson(Map<String, dynamic> json) =>
_$ConnectGuestUserResponseFromJson(json);
static ConnectGuestUserResponse fromJson(Map<String, dynamic>? json) =>
_$ConnectGuestUserResponseFromJson(json!);
}
/// Model response for [StreamChatClient.updateUser] api call
@JsonSerializable(createToJson: false)
class UpdateUsersResponse extends _BaseResponse {
/// Updated users
Map<String, User> users;
Map<String, User>? users;
/// Create a new instance from a json
static UpdateUsersResponse fromJson(Map<String, dynamic> json) =>
_$UpdateUsersResponseFromJson(json);
static UpdateUsersResponse fromJson(Map<String, dynamic>? json) =>
_$UpdateUsersResponseFromJson(json!);
}
/// Model response for [StreamChatClient.updateMessage] api call
@JsonSerializable(createToJson: false)
class UpdateMessageResponse extends _BaseResponse {
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static UpdateMessageResponse fromJson(Map<String, dynamic> json) =>
_$UpdateMessageResponseFromJson(json);
static UpdateMessageResponse fromJson(Map<String, dynamic>? json) =>
_$UpdateMessageResponseFromJson(json!);
}
/// Model response for [Channel.sendMessage] api call
@JsonSerializable(createToJson: false)
class SendMessageResponse extends _BaseResponse {
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static SendMessageResponse fromJson(Map<String, dynamic> json) =>
_$SendMessageResponseFromJson(json);
static SendMessageResponse fromJson(Map<String, dynamic>? json) =>
_$SendMessageResponseFromJson(json!);
}
/// Model response for [StreamChatClient.getMessage] api call
@JsonSerializable(createToJson: false)
class GetMessageResponse extends _BaseResponse {
/// Message returned by the api call
Message message;
Message? message;
/// Channel of the message
ChannelModel channel;
ChannelModel? channel;
/// Create a new instance from a json
static GetMessageResponse fromJson(Map<String, dynamic> json) {
final res = _$GetMessageResponseFromJson(json);
static GetMessageResponse fromJson(Map<String, dynamic>? json) {
final res = _$GetMessageResponseFromJson(json!);
final jsonChannel = res.message?.extraData?.remove('channel');
if (jsonChannel != null) {
res.channel = ChannelModel.fromJson(jsonChannel);
@@ -211,176 +211,176 @@ class GetMessageResponse extends _BaseResponse {
@JsonSerializable(createToJson: false)
class SearchMessagesResponse extends _BaseResponse {
/// List of messages returned by the api call
List<GetMessageResponse> results;
List<GetMessageResponse>? results;
/// Create a new instance from a json
static SearchMessagesResponse fromJson(Map<String, dynamic> json) =>
_$SearchMessagesResponseFromJson(json);
static SearchMessagesResponse fromJson(Map<String, dynamic>? json) =>
_$SearchMessagesResponseFromJson(json!);
}
/// Model response for [Channel.getMessagesById] api call
@JsonSerializable(createToJson: false)
class GetMessagesByIdResponse extends _BaseResponse {
/// Message returned by the api call
List<Message> messages;
List<Message>? messages;
/// Create a new instance from a json
static GetMessagesByIdResponse fromJson(Map<String, dynamic> json) =>
_$GetMessagesByIdResponseFromJson(json);
static GetMessagesByIdResponse fromJson(Map<String, dynamic>? json) =>
_$GetMessagesByIdResponseFromJson(json!);
}
/// Model response for [Channel.update] api call
@JsonSerializable(createToJson: false)
class UpdateChannelResponse extends _BaseResponse {
/// Updated channel
ChannelModel channel;
ChannelModel? channel;
/// Channel members
List<Member> members;
List<Member>? members;
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static UpdateChannelResponse fromJson(Map<String, dynamic> json) =>
_$UpdateChannelResponseFromJson(json);
static UpdateChannelResponse fromJson(Map<String, dynamic>? json) =>
_$UpdateChannelResponseFromJson(json!);
}
/// Model response for [Channel.updatePartial] api call
@JsonSerializable(createToJson: false)
class PartialUpdateChannelResponse extends _BaseResponse {
/// Updated channel
ChannelModel channel;
ChannelModel? channel;
/// Channel members
List<Member> members;
List<Member>? members;
/// Create a new instance from a json
static PartialUpdateChannelResponse fromJson(Map<String, dynamic> json) =>
_$PartialUpdateChannelResponseFromJson(json);
static PartialUpdateChannelResponse fromJson(Map<String, dynamic>? json) =>
_$PartialUpdateChannelResponseFromJson(json!);
}
/// Model response for [Channel.inviteMembers] api call
@JsonSerializable(createToJson: false)
class InviteMembersResponse extends _BaseResponse {
/// Updated channel
ChannelModel channel;
ChannelModel? channel;
/// Channel members
List<Member> members;
List<Member>? members;
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static InviteMembersResponse fromJson(Map<String, dynamic> json) =>
_$InviteMembersResponseFromJson(json);
static InviteMembersResponse fromJson(Map<String, dynamic>? json) =>
_$InviteMembersResponseFromJson(json!);
}
/// Model response for [Channel.removeMembers] api call
@JsonSerializable(createToJson: false)
class RemoveMembersResponse extends _BaseResponse {
/// Updated channel
ChannelModel channel;
ChannelModel? channel;
/// Channel members
List<Member> members;
List<Member>? members;
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static RemoveMembersResponse fromJson(Map<String, dynamic> json) =>
_$RemoveMembersResponseFromJson(json);
static RemoveMembersResponse fromJson(Map<String, dynamic>? json) =>
_$RemoveMembersResponseFromJson(json!);
}
/// Model response for [Channel.sendAction] api call
@JsonSerializable(createToJson: false)
class SendActionResponse extends _BaseResponse {
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static SendActionResponse fromJson(Map<String, dynamic> json) =>
_$SendActionResponseFromJson(json);
static SendActionResponse fromJson(Map<String, dynamic>? json) =>
_$SendActionResponseFromJson(json!);
}
/// Model response for [Channel.addMembers] api call
@JsonSerializable(createToJson: false)
class AddMembersResponse extends _BaseResponse {
/// Updated channel
ChannelModel channel;
ChannelModel? channel;
/// Channel members
List<Member> members;
List<Member>? members;
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static AddMembersResponse fromJson(Map<String, dynamic> json) =>
_$AddMembersResponseFromJson(json);
static AddMembersResponse fromJson(Map<String, dynamic>? json) =>
_$AddMembersResponseFromJson(json!);
}
/// Model response for [Channel.acceptInvite] api call
@JsonSerializable(createToJson: false)
class AcceptInviteResponse extends _BaseResponse {
/// Updated channel
ChannelModel channel;
ChannelModel? channel;
/// Channel members
List<Member> members;
List<Member>? members;
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static AcceptInviteResponse fromJson(Map<String, dynamic> json) =>
_$AcceptInviteResponseFromJson(json);
static AcceptInviteResponse fromJson(Map<String, dynamic>? json) =>
_$AcceptInviteResponseFromJson(json!);
}
/// Model response for [Channel.rejectInvite] api call
@JsonSerializable(createToJson: false)
class RejectInviteResponse extends _BaseResponse {
/// Updated channel
ChannelModel channel;
ChannelModel? channel;
/// Channel members
List<Member> members;
List<Member>? members;
/// Message returned by the api call
Message message;
Message? message;
/// Create a new instance from a json
static RejectInviteResponse fromJson(Map<String, dynamic> json) =>
_$RejectInviteResponseFromJson(json);
static RejectInviteResponse fromJson(Map<String, dynamic>? json) =>
_$RejectInviteResponseFromJson(json!);
}
/// Model response for empty responses
@JsonSerializable(createToJson: false)
class EmptyResponse extends _BaseResponse {
/// Create a new instance from a json
static EmptyResponse fromJson(Map<String, dynamic> json) =>
_$EmptyResponseFromJson(json);
static EmptyResponse fromJson(Map<String, dynamic>? json) =>
_$EmptyResponseFromJson(json!);
}
/// Model response for [Channel.query] api call
@JsonSerializable(createToJson: false)
class ChannelStateResponse extends _BaseResponse {
/// Updated channel
ChannelModel channel;
ChannelModel? channel;
/// List of messages returned by the api call
List<Message> messages;
List<Message>? messages;
/// Channel members
List<Member> members;
List<Member>? members;
/// Number of users watching the channel
int watcherCount;
int? watcherCount;
/// List of read states
List<Read> read;
List<Read>? read;
/// Create a new instance from a json
static ChannelStateResponse fromJson(Map<String, dynamic> json) =>
@@ -6,30 +6,30 @@ import 'package:stream_chat/src/exceptions.dart';
class RetryPolicy {
/// Instantiate a new RetryPolicy
RetryPolicy({
@required this.shouldRetry,
@required this.retryTimeout,
this.attempt,
required this.shouldRetry,
required this.retryTimeout,
this.attempt = 0,
});
/// The number of attempts tried so far
int attempt = 0;
/// This function evaluates if we should retry the failure
final bool Function(StreamChatClient client, int attempt, ApiError apiError)
final bool Function(StreamChatClient client, int attempt, ApiError? apiError)
shouldRetry;
/// In the case that we want to retry a failed request the retryTimeout
/// method is called to determine the timeout
final Duration Function(
StreamChatClient client, int attempt, ApiError apiError) retryTimeout;
StreamChatClient client, int attempt, ApiError? apiError) retryTimeout;
/// Creates a copy of [RetryPolicy] with specified attributes overridden.
RetryPolicy copyWith({
bool Function(StreamChatClient client, int attempt, ApiError apiError)
bool Function(StreamChatClient client, int attempt, ApiError? apiError)?
shouldRetry,
Duration Function(StreamChatClient client, int attempt, ApiError apiError)
Duration Function(StreamChatClient client, int attempt, ApiError? apiError)?
retryTimeout,
int attempt,
int? attempt,
}) =>
RetryPolicy(
retryTimeout: retryTimeout ?? this.retryTimeout,
@@ -14,7 +14,7 @@ import 'package:stream_chat/stream_chat.dart';
class RetryQueue {
/// Instantiate a new RetryQueue object
RetryQueue({
@required this.channel,
required this.channel,
this.logger,
}) {
_retryPolicy = channel.client.retryPolicy;
@@ -28,29 +28,29 @@ class RetryQueue {
final Channel channel;
/// The logger associated to this queue
final Logger logger;
final Logger? logger;
final _subscriptions = <StreamSubscription>[];
void _listenConnectionRecovered() {
_subscriptions
.add(channel.client.on(EventType.connectionRecovered).listen((event) {
if (!_isRetrying && event.online) {
if (!_isRetrying && event.online!) {
_startRetrying();
}
}));
}
final HeapPriorityQueue<Message> _messageQueue = HeapPriorityQueue(_byDate);
final HeapPriorityQueue<Message?> _messageQueue = HeapPriorityQueue(_byDate);
bool _isRetrying = false;
RetryPolicy _retryPolicy;
RetryPolicy? _retryPolicy;
/// Add a list of messages
void add(List<Message> messages) {
void add(List<Message?> messages) {
logger?.info('added ${messages.length} messages');
final messageList = _messageQueue.toList();
_messageQueue.addAll(messages
.where((element) => !messageList.any((m) => m.id == element.id)));
.where((element) => !messageList.any((m) => m!.id == element!.id)));
if (_messageQueue.isNotEmpty && !_isRetrying) {
_startRetrying();
@@ -60,10 +60,10 @@ class RetryQueue {
Future<void> _startRetrying() async {
logger?.info('start retrying');
_isRetrying = true;
final retryPolicy = _retryPolicy.copyWith(attempt: 0);
final retryPolicy = _retryPolicy!.copyWith(attempt: 0);
while (_messageQueue.isNotEmpty) {
final message = _messageQueue.first;
final message = _messageQueue.first!;
try {
logger?.info('retry attempt ${retryPolicy.attempt}');
await _sendMessage(message);
@@ -72,7 +72,7 @@ class RetryQueue {
logger?.info('now ${_messageQueue.length} messages in the queue');
retryPolicy.attempt = 0;
} catch (error) {
ApiError apiError;
ApiError? apiError;
if (error is DioError) {
if (error.type == DioErrorType.response) {
_messageQueue.remove(message);
@@ -84,7 +84,7 @@ class RetryQueue {
);
} else if (error is ApiError) {
apiError = error;
if (apiError.status?.toString()?.startsWith('4') == true) {
if (apiError.status?.toString().startsWith('4') == true) {
_messageQueue.remove(message);
return;
}
@@ -101,6 +101,7 @@ class RetryQueue {
}
retryPolicy.attempt++;
final timeout = retryPolicy.retryTimeout(
channel.client,
retryPolicy.attempt,
@@ -112,13 +113,13 @@ class RetryQueue {
_isRetrying = false;
}
void _sendFailedEvent(Message message) {
final newStatus = message.status == MessageSendingStatus.sending
void _sendFailedEvent(Message? message) {
final newStatus = message!.status == MessageSendingStatus.sending
? MessageSendingStatus.failed
: (message.status == MessageSendingStatus.updating
? MessageSendingStatus.failed_update
: MessageSendingStatus.failed_delete);
channel.state.addMessage(message.copyWith(
channel.state!.addMessage(message.copyWith(
status: newStatus,
));
}
@@ -141,20 +142,20 @@ class RetryQueue {
final messageList = _messageQueue.toList();
if (event.message != null) {
final messageIndex =
messageList.indexWhere((m) => m.id == event.message.id);
messageList.indexWhere((m) => m!.id == event.message!.id);
if (messageIndex == -1 &&
[
MessageSendingStatus.failed_update,
MessageSendingStatus.failed,
MessageSendingStatus.failed_delete,
].contains(event.message.status)) {
].contains(event.message!.status)) {
logger?.info('add message from events');
add([event.message]);
} else if (messageIndex != -1 &&
[
MessageSendingStatus.sent,
null,
].contains(event.message.status)) {
].contains(event.message!.status)) {
_messageQueue.remove(messageList[messageIndex]);
}
}
@@ -167,14 +168,14 @@ class RetryQueue {
_subscriptions.forEach((s) => s.cancel());
}
static int _byDate(Message m1, Message m2) {
final date1 = _getMessageDate(m1);
final date2 = _getMessageDate(m2);
static int _byDate(Message? m1, Message? m2) {
final date1 = _getMessageDate(m1!)!;
final date2 = _getMessageDate(m2!)!;
return date1.compareTo(date2);
}
static DateTime _getMessageDate(Message m1) {
static DateTime? _getMessageDate(Message m1) {
switch (m1.status) {
case MessageSendingStatus.failed_delete:
case MessageSendingStatus.deleting:
@@ -3,5 +3,5 @@ import 'package:web_socket_channel/web_socket_channel.dart';
/// Html version of websocket implementation
/// Used in Flutter web version
WebSocketChannel connectWebSocket(String url, {Iterable<String> protocols}) =>
WebSocketChannel connectWebSocket(String url, {Iterable<String>? protocols}) =>
HtmlWebSocketChannel.connect(url, protocols: protocols);
@@ -3,5 +3,5 @@ import 'package:web_socket_channel/web_socket_channel.dart';
/// IO version of websocket implementation
/// Used in Flutter mobile version
WebSocketChannel connectWebSocket(String url, {Iterable<String> protocols}) =>
WebSocketChannel connectWebSocket(String url, {Iterable<String>? protocols}) =>
IOWebSocketChannel.connect(url, protocols: protocols);
@@ -3,7 +3,7 @@ import 'package:web_socket_channel/web_socket_channel.dart';
/// Stub version of websocket implementation
/// Used just for conditional library import
WebSocketChannel connectWebSocket(String url,
{Iterable<String> protocols,
Map<String, dynamic> headers,
Duration pingInterval}) =>
{Iterable<String>? protocols,
Map<String, dynamic>? headers,
Duration? pingInterval}) =>
throw UnimplementedError();
+40 -40
View File
@@ -16,8 +16,8 @@ typedef EventHandler = void Function(Event);
/// Typedef used for connecting to a websocket. Method returns a
/// [WebSocketChannel] and accepts a connection [url] and an optional
/// [Iterable] of `protocols`.
typedef ConnectWebSocket = WebSocketChannel Function(String url,
{Iterable<String> protocols});
typedef ConnectWebSocket = WebSocketChannel Function(String? url,
{Iterable<String>? protocols});
// TODO: parse error even
// TODO: if parsing an error into an event fails we should not hide the
@@ -27,7 +27,7 @@ class WebSocket {
/// Creates a new websocket
/// To connect the WS call [connect]
WebSocket({
@required this.baseUrl,
required this.baseUrl,
this.user,
this.connectParams,
this.connectPayload,
@@ -38,22 +38,22 @@ class WebSocket {
this.healthCheckInterval = 20,
this.reconnectionMonitorTimeout = 40,
}) {
final qs = Map<String, String>.from(connectParams);
final qs = Map<String, String>.from(connectParams!);
final data = Map<String, dynamic>.from(connectPayload);
final data = Map<String, dynamic>.from(connectPayload!);
data['user_details'] = user.toJson();
data['user_details'] = user!.toJson();
qs['json'] = json.encode(data);
if (baseUrl.startsWith('https')) {
_path = baseUrl.replaceFirst('https://', '');
_path = Uri.https(_path, 'connect', qs)
_path = Uri.https(_path!, 'connect', qs)
.toString()
.replaceFirst('https', 'wss');
} else if (baseUrl.startsWith('http')) {
_path = baseUrl.replaceFirst('http://', '');
_path =
Uri.http(_path, 'connect', qs).toString().replaceFirst('http', 'ws');
Uri.http(_path!, 'connect', qs).toString().replaceFirst('http', 'ws');
} else {
_path = Uri.https(baseUrl, 'connect', qs)
.toString()
@@ -65,25 +65,25 @@ class WebSocket {
final String baseUrl;
/// User performing the WS connection
final User user;
final User? user;
/// Querystring connection parameters
final Map<String, String> connectParams;
final Map<String, String?>? connectParams;
/// WS connection payload
final Map<String, dynamic> connectPayload;
final Map<String, dynamic>? connectPayload;
/// Functions that will be called every time a new event is received from the
/// connection
final EventHandler handler;
final EventHandler? handler;
/// A WS specific logger instance
final Logger logger;
final Logger? logger;
/// Connection function
/// Used only for testing purpose
@visibleForTesting
final ConnectWebSocket connectFunc;
final ConnectWebSocket? connectFunc;
/// Interval of the reconnection monitor timer
/// This checks that it received a new event in the last
@@ -107,17 +107,17 @@ class WebSocket {
_connectionStatusController.add(status);
/// The current connection status value
ConnectionStatus get connectionStatus => _connectionStatusController.value;
ConnectionStatus? get connectionStatus => _connectionStatusController.value;
/// This notifies of connection status changes
Stream<ConnectionStatus> get connectionStatusStream =>
_connectionStatusController.stream;
String _path;
String? _path;
int _retryAttempt = 1;
WebSocketChannel _channel;
Timer _healthCheck, _reconnectionMonitor;
DateTime _lastEventAt;
late WebSocketChannel _channel;
Timer? _healthCheck, _reconnectionMonitor;
DateTime? _lastEventAt;
bool _manuallyDisconnected = false;
bool _connecting = false;
bool _reconnecting = false;
@@ -127,23 +127,23 @@ class WebSocket {
Completer<Event> _connectionCompleter = Completer<Event>();
/// Connect the WS using the parameters passed in the constructor
Future<Event> connect() {
Future<Event>? connect() {
_manuallyDisconnected = false;
if (_connecting) {
logger.severe('already connecting');
logger!.severe('already connecting');
return null;
}
_connecting = true;
_connectionStatus = ConnectionStatus.connecting;
logger.info('connecting to $_path');
logger!.info('connecting to $_path');
_channel =
connectFunc?.call(_path) ?? WebSocketChannel.connect(Uri.parse(_path));
connectFunc?.call(_path) ?? WebSocketChannel.connect(Uri.parse(_path!));
_channel.stream.listen(
(data) {
(data) async {
final jsonData = json.decode(data);
if (jsonData['error'] != null) {
return _onConnectionError(jsonData['error']);
@@ -166,7 +166,7 @@ class WebSocket {
return;
}
logger.info('connection closed | closeCode: ${_channel.closeCode} | '
logger!.info('connection closed | closeCode: ${_channel.closeCode} | '
'closedReason: ${_channel.closeReason}');
if (!_reconnecting) {
@@ -180,10 +180,10 @@ class WebSocket {
}
final event = _decodeEvent(data);
logger.info('received new event: $data');
logger!.info('received new event: $data');
if (_lastEventAt == null) {
logger.info('connection estabilished');
logger!.info('connection estabilished');
_connecting = false;
_reconnecting = false;
_lastEventAt = DateTime.now();
@@ -199,14 +199,14 @@ class WebSocket {
_startHealthCheck();
}
handler(event);
handler!(event);
_lastEventAt = DateTime.now();
}
Future<void> _onConnectionError(error, [stacktrace]) async {
logger..severe('error connecting')..severe(error);
logger!..severe('error connecting')..severe(error);
if (stacktrace != null) {
logger.severe(stacktrace);
logger!.severe(stacktrace);
}
_connecting = false;
@@ -225,7 +225,7 @@ class WebSocket {
void _reconnectionTimer(_) {
final now = DateTime.now();
if (_lastEventAt != null &&
now.difference(_lastEventAt).inSeconds > reconnectionMonitorTimeout) {
now.difference(_lastEventAt!).inSeconds > reconnectionMonitorTimeout) {
_channel.sink.close();
}
}
@@ -244,18 +244,18 @@ class WebSocket {
return;
}
if (_connecting) {
logger.info('already connecting');
logger!.info('already connecting');
return;
}
logger.info('reconnecting..');
logger!.info('reconnecting..');
_cancelTimers();
try {
await connect();
} catch (e) {
logger.log(Level.SEVERE, e.toString());
logger!.log(Level.SEVERE, e.toString());
}
await Future.delayed(
Duration(seconds: min(_retryAttempt * 5, 25)),
@@ -267,7 +267,7 @@ class WebSocket {
}
Future<void> _reconnect() async {
logger.info('reconnect');
logger!.info('reconnect');
if (!_reconnecting) {
_reconnecting = true;
_connectionStatus = ConnectionStatus.connecting;
@@ -279,20 +279,20 @@ class WebSocket {
void _cancelTimers() {
_lastEventAt = null;
if (_healthCheck != null) {
_healthCheck.cancel();
_healthCheck!.cancel();
}
if (_reconnectionMonitor != null) {
_reconnectionMonitor.cancel();
_reconnectionMonitor!.cancel();
}
}
void _healthCheckTimer(_) {
logger.info('sending health.check');
logger!.info('sending health.check');
_channel.sink.add("{'type': 'health.check'}");
}
void _startHealthCheck() {
logger.info('start health check monitor');
logger!.info('start health check monitor');
_healthCheck = Timer.periodic(
Duration(seconds: healthCheckInterval),
@@ -311,7 +311,7 @@ class WebSocket {
if (_manuallyDisconnected) {
return;
}
logger.info('disconnecting');
logger!.info('disconnecting');
_connectionCompleter = Completer();
_cancelTimers();
_reconnecting = false;