@@ -27,15 +27,33 @@ mixin RealtimeMixin {
27
27
int _retries = 0;
28
28
StreamSubscription? _websocketSubscription;
29
29
bool _creatingSocket = false;
30
+ Timer? _heartbeatTimer;
30
31
31
32
Future<dynamic > _closeConnection() async {
33
+ _stopHeartbeat();
32
34
await _websocketSubscription?.cancel();
33
35
await _websok?.sink.close(status.normalClosure, 'Ending session');
34
36
_lastUrl = null;
35
37
_retries = 0;
36
38
_reconnect = false;
37
39
}
38
40
41
+ void _startHeartbeat() {
42
+ _stopHeartbeat();
43
+ _heartbeatTimer = Timer.periodic(Duration(seconds: 20), (_) {
44
+ if (_websok != null) {
45
+ _websok!.sink.add(jsonEncode({
46
+ "type": "ping"
47
+ }));
48
+ }
49
+ });
50
+ }
51
+
52
+ void _stopHeartbeat() {
53
+ _heartbeatTimer?.cancel();
54
+ _heartbeatTimer = null;
55
+ }
56
+
39
57
_createSocket() async {
40
58
if(_creatingSocket || _channels.isEmpty) return;
41
59
_creatingSocket = true;
@@ -78,6 +96,10 @@ mixin RealtimeMixin {
78
96
}));
79
97
}
80
98
}
99
+ _startHeartbeat(); // Start heartbeat after successful connection
100
+ break;
101
+ case 'pong':
102
+ debugPrint('Received heartbeat response from realtime server');
81
103
break;
82
104
case 'event':
83
105
final message = RealtimeMessage.fromMap(data.data);
@@ -91,8 +113,10 @@ mixin RealtimeMixin {
91
113
break;
92
114
}
93
115
}, onDone: () {
116
+ _stopHeartbeat();
94
117
_retry();
95
118
}, onError: (err, stack) {
119
+ _stopHeartbeat();
96
120
for (var subscription in _subscriptions.values) {
97
121
subscription.controller.addError(err, stack);
98
122
}
@@ -187,4 +211,4 @@ mixin RealtimeMixin {
187
211
_retry();
188
212
}
189
213
}
190
- }
214
+ }
0 commit comments