Skip to content

Commit 64b8b96

Browse files
authored
fix(realtime_client): No exception is thrown when connection is closed. (supabase#620)
* fix: realtime throwing error when connection is closed * fix: adjust test case to align with js client
1 parent c155f69 commit 64b8b96

File tree

3 files changed

+29
-5
lines changed

3 files changed

+29
-5
lines changed

packages/realtime_client/lib/src/realtime_channel.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ class RealtimeChannel {
328328
/// Registers a callback that will be executed when the channel encounteres an error.
329329
void onError(void Function(String?) callback) {
330330
onEvents(ChannelEvents.error.eventName(), ChannelFilter(),
331-
(reason, [ref]) => callback(reason.toString()));
331+
(reason, [ref]) => callback(reason?.toString()));
332332
}
333333

334334
RealtimeChannel on(

packages/realtime_client/lib/src/realtime_client.dart

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,26 @@ typedef RealtimeDecode = void Function(
2626
void Function(dynamic result) callback,
2727
);
2828

29+
/// Event details for when the connection closed.
30+
class RealtimeCloseEvent {
31+
/// Web socket protocol status codes for when a connection is closed.
32+
///
33+
/// The full list can be found at the following:
34+
///
35+
/// https://datatracker.ietf.org/doc/html/rfc6455#section-7.4
36+
final int code;
37+
38+
/// Connection closed reason sent from the server
39+
///
40+
/// https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6
41+
final String? reason;
42+
43+
const RealtimeCloseEvent({
44+
required this.code,
45+
required this.reason,
46+
});
47+
}
48+
2949
class RealtimeClient {
3050
String? accessToken;
3151
List<RealtimeChannel> channels = [];
@@ -387,13 +407,17 @@ class RealtimeClient {
387407

388408
/// communication has been closed
389409
void _onConnClose() {
390-
final event = conn?.closeReason ?? '';
410+
final statusCode = conn?.closeCode;
411+
RealtimeCloseEvent? event;
412+
if (statusCode != null) {
413+
event = RealtimeCloseEvent(code: statusCode, reason: conn?.closeReason);
414+
}
391415
log('transport', 'close', event);
392416

393417
/// SocketStates.disconnected: by user with socket.disconnect()
394418
/// SocketStates.closed: NOT by user, should try to reconnect
395419
if (connState == SocketStates.closed) {
396-
_triggerChanError(event);
420+
_triggerChanError();
397421
reconnectTimer.scheduleTimeout();
398422
}
399423
if (heartbeatTimer != null) heartbeatTimer!.cancel();

packages/realtime_client/test/mock_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,9 @@ void main() {
289289
});
290290

291291
test("correct CHANNEL_ERROR data on heartbeat timeout", () async {
292-
final subscribeCallback = expectAsync2((event, [data]) {
292+
final subscribeCallback = expectAsync2((event, [error]) {
293293
if (event == "CHANNEL_ERROR") {
294-
expect(data, "heartbeat timeout");
294+
expect(error, isNull);
295295
} else {
296296
expect(event, "CLOSED");
297297
}

0 commit comments

Comments
 (0)