Skip to content

Commit b4bc878

Browse files
committed
Release 3.0.13
1 parent d41b00e commit b4bc878

17 files changed

+237
-149
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## [3.0.13] - May 17, 2021
2+
* Fixed file type mis mapping bug
3+
* Added `cancelUploadingFileMessage` in `BaseChannel`
4+
* Added `joinedAt` in `GroupChannel`
5+
* Improved stability
6+
17
## [3.0.12] - Apr 25, 2021
28
* Fixed to apply option to `SendbirdSdk` properly
39
* Fixed `sendFileMessage` progress inconsistency

lib/core/channel/base/base_channel_messages.dart

Lines changed: 88 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -150,78 +150,104 @@ extension Messages on BaseChannel {
150150
pending.sender = Sender.fromUser(_sdk.state.currentUser, this);
151151

152152
final queue = _sdk.getMsgQueue(channelUrl);
153-
queue.enqueue(AsyncSimpleTask(() async {
154-
if (params.uploadFile.hasBinary) {
155-
upload = await _sdk.api
156-
.uploadFile(
157-
channelUrl: channelUrl,
158-
requestId: pending.requestId,
159-
params: params,
160-
progress: progress)
161-
.timeout(
162-
Duration(seconds: _sdk.options.fileTransferTimeout),
163-
onTimeout: () {
164-
logger.e('upload timeout');
165-
if (onCompleted != null) {
166-
onCompleted(
167-
pending..sendingStatus = MessageSendingStatus.failed,
168-
SBError(
169-
message: 'upload timeout',
170-
code: ErrorCode.fileUploadTimeout,
171-
),
172-
);
153+
final task = AsyncSimpleTask(
154+
() async {
155+
if (params.uploadFile.hasBinary) {
156+
try {
157+
upload = await _sdk.api
158+
.uploadFile(
159+
channelUrl: channelUrl,
160+
requestId: pending.requestId,
161+
params: params,
162+
progress: progress)
163+
.timeout(
164+
Duration(seconds: _sdk.options.fileTransferTimeout),
165+
onTimeout: () {
166+
logger.e('upload timeout');
167+
if (onCompleted != null) {
168+
onCompleted(
169+
pending..sendingStatus = MessageSendingStatus.failed,
170+
SBError(
171+
message: 'upload timeout',
172+
code: ErrorCode.fileUploadTimeout,
173+
),
174+
);
175+
}
176+
return;
177+
},
178+
);
179+
if (upload == null) {
180+
throw SBError(code: ErrorCode.fileUploadTimeout);
173181
}
174-
return;
175-
},
182+
fileSize = upload.fileSize;
183+
url = upload.url;
184+
} catch (e) {
185+
rethrow;
186+
}
187+
}
188+
189+
if (fileSize != null) params.uploadFile.fileSize = fileSize;
190+
if (url != null) params.uploadFile.url = url;
191+
192+
final cmd = Command.buildFileMessage(
193+
channelUrl: channelUrl,
194+
params: params,
195+
requestId: pending.requestId,
196+
requireAuth: upload?.requireAuth,
197+
thumbnails: upload?.thumbnails,
176198
);
177-
if (upload == null) throw SBError(code: ErrorCode.fileUploadTimeout);
178199

179-
fileSize = upload.fileSize;
180-
url = upload.url;
181-
}
182-
183-
if (fileSize != null) params.uploadFile.fileSize = fileSize;
184-
if (url != null) params.uploadFile.url = url;
185-
186-
final cmd = Command.buildFileMessage(
187-
channelUrl: channelUrl,
188-
params: params,
189-
requestId: pending.requestId,
190-
requireAuth: upload?.requireAuth,
191-
thumbnails: upload?.thumbnails,
192-
);
193-
194-
final msgFromPayload = BaseMessage.msgFromJson<FileMessage>(
195-
cmd.payload,
196-
channelType: channelType,
197-
);
200+
final msgFromPayload = BaseMessage.msgFromJson<FileMessage>(
201+
cmd.payload,
202+
channelType: channelType,
203+
);
198204

199-
if (!_sdk.state.hasActiveUser) {
200-
final error = ConnectionRequiredError();
201-
msgFromPayload
202-
..errorCode = error.code
203-
..sendingStatus = MessageSendingStatus.failed;
204-
if (onCompleted != null) onCompleted(msgFromPayload, error);
205-
return msgFromPayload;
206-
}
207-
208-
_sdk.cmdManager.sendCommand(cmd).then((cmdResult) {
209-
final msg = BaseMessage.msgFromJson<FileMessage>(cmdResult.payload);
210-
if (onCompleted != null) onCompleted(msg, null);
211-
}).catchError((e) {
212-
// pending.errorCode = e?.code ?? ErrorCode.unknownError;
213-
pending
214-
..errorCode = e.code
215-
..sendingStatus = MessageSendingStatus.failed;
216-
if (onCompleted != null) onCompleted(pending, e);
217-
});
218-
}));
205+
if (!_sdk.state.hasActiveUser) {
206+
final error = ConnectionRequiredError();
207+
msgFromPayload
208+
..errorCode = error.code
209+
..sendingStatus = MessageSendingStatus.failed;
210+
if (onCompleted != null) onCompleted(msgFromPayload, error);
211+
return msgFromPayload;
212+
}
213+
214+
_sdk.cmdManager.sendCommand(cmd).then((cmdResult) {
215+
final msg = BaseMessage.msgFromJson<FileMessage>(cmdResult.payload);
216+
if (onCompleted != null) onCompleted(msg, null);
217+
}).catchError((e) {
218+
// pending.errorCode = e?.code ?? ErrorCode.unknownError;
219+
pending
220+
..errorCode = e.code
221+
..sendingStatus = MessageSendingStatus.failed;
222+
if (onCompleted != null) onCompleted(pending, e);
223+
});
224+
},
225+
onCancel: () {
226+
if (onCompleted != null) onCompleted(pending, OperationCancelError());
227+
},
228+
);
219229

230+
queue.enqueue(task);
231+
_sdk.setUploadTask(pending.requestId, task);
220232
_sdk.setMsgQueue(channelUrl, queue);
221233

222234
return pending;
223235
}
224236

237+
bool cancelUploadingFileMessage(String requestId) {
238+
if (requestId == null || requestId == '') {
239+
throw InvalidParameterError();
240+
}
241+
final task = _sdk.getUploadTask(requestId);
242+
if (task == null) {
243+
throw NotFoundError();
244+
}
245+
246+
final queue = _sdk.getMsgQueue(channelUrl);
247+
_sdk.api.cancelUploadingFile(requestId);
248+
return queue.cancel(task.hashCode);
249+
}
250+
225251
/// Resends failed [FileMessage] on this channel with [message].
226252
///
227253
/// It returns [FileMessage] with [MessageSendingStatus.pending] and

lib/core/channel/group/group_channel.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,15 @@ class GroupChannel extends BaseChannel {
122122
/// User who invited
123123
Member inviter;
124124

125-
/// The time stamp when current user got a invitation
125+
/// Timestamp when current user got a invitation
126126
/// from other user in the channel
127+
@JsonKey(defaultValue: 0)
127128
int invitedAt;
128129

130+
/// Timestamp when current user joined on this channel
131+
@JsonKey(name: 'joined_ts', defaultValue: 0)
132+
int joinedAt;
133+
129134
/// True if this channel is hidden
130135
bool isHidden;
131136

@@ -166,6 +171,7 @@ class GroupChannel extends BaseChannel {
166171
this.members,
167172
this.memberCount,
168173
this.joinedMemberCount,
174+
this.joinedAt,
169175
this.myPushTriggerOption,
170176
this.myMemberState,
171177
this.myRole,

lib/core/channel/group/group_channel_operations.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ extension GroupChannelOperations on GroupChannel {
6161
/// [ChannelEventHandler.onUserLeaved] will be invoked.
6262
Future<void> leave() async {
6363
await _sdk.api.leaveGroupChannel(channelUrl: channelUrl);
64+
invitedAt = 0;
65+
joinedAt = 0;
6466
}
6567

6668
/// Resets (clear) any previous messages on this channel.

lib/core/message/base_message.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,12 @@ class BaseMessage {
337337
reactions,
338338
);
339339

340-
static T msgFromJson<T extends BaseMessage>(Map<String, dynamic> json,
341-
{ChannelType channelType}) {
342-
final cmd = json['type'] as String;
340+
static T msgFromJson<T extends BaseMessage>(
341+
Map<String, dynamic> json, {
342+
ChannelType channelType,
343+
String type,
344+
}) {
345+
final cmd = type ?? json['type'] as String;
343346
T msg;
344347
//basemessage backward compatibility -
345348
if (json['custom'] != null) json['data'] = json['custom'];

lib/core/models/error.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,7 @@ class InvalidAccessTokenError extends SBError {
114114
}
115115

116116
class UnknownError extends SBError {}
117+
118+
class NotFoundError extends SBError {}
119+
120+
class OperationCancelError extends SBError {}

lib/managers/command_manager.dart

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,13 @@ class CommandManager with SdkAccessor {
5959
Future<Command> sendCommand(Command cmd) async {
6060
if (appState.currentUser == null) {
6161
//NOTE: some test cases execute async socket data
62-
//even after test case was finished
63-
// print('[E] ${this.hashCode}');
6462
logger.e('sendCommand: connection is requred');
6563
throw ConnectionRequiredError();
6664
}
6765
if (cmd == null) {
6866
logger.e('sendCommand: command parameter is null');
6967
throw InvalidParameterError();
7068
}
71-
// if (!webSocket.isConnected()) {
72-
// logger.e('sendCommand: Websocket connection is closed');
73-
// throw WebSocketConnectionClosedError();
74-
// }
7569

7670
try {
7771
await ConnectionManager.readyToExecuteWSRequest();
@@ -668,6 +662,7 @@ class CommandManager with SdkAccessor {
668662
if (member.isCurrentUser) {
669663
channel.myMemberState = MemberState.none;
670664
channel.invitedAt = 0;
665+
channel.joinedAt = 0;
671666
channel.clearUnreadCount();
672667
if (!channel.isPublic) {
673668
channel.removeFromCache();

lib/sdk/internal/sendbird_sdk_internal.dart

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import 'package:sendbird_sdk/utils/async/async_queue.dart';
2424
import 'package:sendbird_sdk/utils/logger.dart';
2525
import 'package:sendbird_sdk/utils/parsers.dart';
2626

27-
const sdk_version = '3.0.12';
27+
const sdk_version = '3.0.13';
2828
const platform = 'flutter';
2929

3030
/// Internal implementation for main class. Do not directly access this class.
@@ -42,12 +42,14 @@ class SendbirdSdkInternal with WidgetsBindingObserver {
4242
Completer<User> _loginCompleter;
4343

4444
Options _options;
45+
AsyncQueue _commandQueue = AsyncQueue<String>();
4546
Map<String, AsyncQueue> _messageQueues = {};
47+
Map<String, AsyncSimpleTask> _uploads = {};
4648

4749
Timer _reconnectTimer;
4850
ConnectivityResult _connectionResult;
4951
StreamSubscription _connectionSub;
50-
AsyncQueue _commandQueue = AsyncQueue<String>();
52+
5153
Map<String, String> _extensions = {};
5254
List<String> _extraDatas = [
5355
constants.sbExtraDataPremiumFeatureList,
@@ -90,6 +92,9 @@ class SendbirdSdkInternal with WidgetsBindingObserver {
9092
_messageQueues[channelUrl] ?? AsyncQueue();
9193
void setMsgQueue(String channelUrl, AsyncQueue queue) =>
9294
_messageQueues[channelUrl] = queue;
95+
AsyncSimpleTask getUploadTask(String requestId) => _uploads[requestId];
96+
void setUploadTask(String requestId, AsyncSimpleTask task) =>
97+
_uploads[requestId] = task;
9398

9499
// socket callbacks
95100

@@ -123,22 +128,19 @@ class SendbirdSdkInternal with WidgetsBindingObserver {
123128
//NOTE: compute does not gaurantee the order of commands
124129
final op = AsyncTask<String>(func: parseCommand, arg: stringCommand);
125130
final cmd = await _commandQueue.enqueue(op);
126-
// cmdManager.processCommand(cmd);
127-
runZoned(() async {
131+
132+
runZonedGuarded(() async {
128133
try {
129134
_cmdManager.processCommand(cmd);
130135
} catch (e) {
131136
rethrow;
132137
}
133-
}, onError: (e, s) {
134-
//handle error how to toss this..?
135-
//get waiting func and error?
138+
}, (e, trace) {
136139
if (_loginCompleter != null) {
137140
_loginCompleter?.completeError(e);
138141
} else {
139142
logger.e('fatal error thrown ${e.toString()}');
140143
}
141-
// throw e;
142144
});
143145
}
144146

@@ -270,6 +272,13 @@ class SendbirdSdkInternal with WidgetsBindingObserver {
270272
_cmdManager = CommandManager();
271273
_streamManager.reset();
272274

275+
_commandQueue.cleanUp();
276+
_messageQueues.forEach((key, q) => q.cleanUp());
277+
_messageQueues = {};
278+
_uploads.forEach((key, value) => _api.cancelUploadingFile(key));
279+
_uploads = {};
280+
_loginCompleter = null;
281+
273282
_api = ApiClient();
274283
_api.initialize(appId: _state.appId);
275284

@@ -280,10 +289,6 @@ class SendbirdSdkInternal with WidgetsBindingObserver {
280289
WidgetsBinding.instance?.removeObserver(this);
281290
_connectionSub?.cancel();
282291

283-
_commandQueue.cleanUp();
284-
_messageQueues = {};
285-
_loginCompleter = null;
286-
287292
ConnectionManager.flushCompleters(error: ConnectionClosedError());
288293
}
289294

lib/services/network/api_client.dart

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -721,19 +721,23 @@ class ApiClient {
721721
body['thumbnail${index + 1}'] =
722722
'${value.width.round()},${value.height.round()}');
723723

724-
final res = await client.multipartRequest(
725-
method: Method.post,
726-
url: url,
727-
body: body,
728-
progress: progress,
729-
);
730-
return UploadResponse.fromJson(res);
724+
try {
725+
final res = await client.multipartRequest(
726+
method: Method.post,
727+
url: url,
728+
body: body,
729+
progress: progress,
730+
);
731+
return UploadResponse.fromJson(res);
732+
} catch (_) {
733+
rethrow;
734+
}
731735
}
732736

733737
// https://github.com/dart-lang/http/issues/424
734-
// Future<void> cancelUploading {
735-
736-
// }
738+
bool cancelUploadingFile(String requestId) {
739+
return client.cancelUploadRequest(requestId);
740+
}
737741

738742
Future<UserMessage> translateUserMessage({
739743
@required ChannelType channelType,

0 commit comments

Comments
 (0)