👔 No longer rapid websocket reconnect (stops after 5 times in a minute)
This commit is contained in:
@@ -52,6 +52,11 @@ class WebSocketService {
|
|||||||
DateTime? _heartbeatAt;
|
DateTime? _heartbeatAt;
|
||||||
Duration? heartbeatDelay;
|
Duration? heartbeatDelay;
|
||||||
|
|
||||||
|
// Reconnection tracking
|
||||||
|
int _reconnectCount = 0;
|
||||||
|
DateTime? _reconnectWindowStart;
|
||||||
|
static const int _maxReconnectsPerMinute = 5;
|
||||||
|
|
||||||
Stream<WebSocketPacket> get dataStream => _streamController.stream;
|
Stream<WebSocketPacket> get dataStream => _streamController.stream;
|
||||||
Stream<WebSocketState> get statusStream => _statusStreamController.stream;
|
Stream<WebSocketState> get statusStream => _statusStreamController.stream;
|
||||||
|
|
||||||
@@ -79,8 +84,9 @@ class WebSocketService {
|
|||||||
_scheduleHeartbeat();
|
_scheduleHeartbeat();
|
||||||
_channel!.stream.listen(
|
_channel!.stream.listen(
|
||||||
(data) {
|
(data) {
|
||||||
final dataStr =
|
final dataStr = data is Uint8List
|
||||||
data is Uint8List ? utf8.decode(data) : data.toString();
|
? utf8.decode(data)
|
||||||
|
: data.toString();
|
||||||
final packet = WebSocketPacket.fromJson(jsonDecode(dataStr));
|
final packet = WebSocketPacket.fromJson(jsonDecode(dataStr));
|
||||||
if (packet.type == 'error.dupe') {
|
if (packet.type == 'error.dupe') {
|
||||||
_statusStreamController.sink.add(WebSocketState.duplicateDevice());
|
_statusStreamController.sink.add(WebSocketState.duplicateDevice());
|
||||||
@@ -123,6 +129,34 @@ class WebSocketService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _scheduleReconnect() {
|
void _scheduleReconnect() {
|
||||||
|
// Check if we've exceeded the reconnect limit
|
||||||
|
final now = DateTime.now();
|
||||||
|
if (_reconnectWindowStart == null ||
|
||||||
|
now.difference(_reconnectWindowStart!).inMinutes >= 1) {
|
||||||
|
// Reset window if it's been more than 1 minute since the window started
|
||||||
|
_reconnectWindowStart = now;
|
||||||
|
_reconnectCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_reconnectCount++;
|
||||||
|
|
||||||
|
if (_reconnectCount > _maxReconnectsPerMinute) {
|
||||||
|
talker.error(
|
||||||
|
'[WebSocket] Reconnect limit exceeded: $_maxReconnectsPerMinute reconnections in the last minute. Stopping auto-reconnect.',
|
||||||
|
);
|
||||||
|
_statusStreamController.sink.add(WebSocketState.serverDown());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_reconnectTimer?.cancel();
|
||||||
|
_reconnectTimer = Timer(const Duration(milliseconds: 500), () {
|
||||||
|
_statusStreamController.sink.add(WebSocketState.connecting());
|
||||||
|
connect(_ref);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void manualReconnect() {
|
||||||
|
talker.info('[WebSocket] Manual reconnect triggered by user');
|
||||||
_reconnectTimer?.cancel();
|
_reconnectTimer?.cancel();
|
||||||
_reconnectTimer = Timer(const Duration(milliseconds: 500), () {
|
_reconnectTimer = Timer(const Duration(milliseconds: 500), () {
|
||||||
_statusStreamController.sink.add(WebSocketState.connecting());
|
_statusStreamController.sink.add(WebSocketState.connecting());
|
||||||
@@ -204,4 +238,9 @@ class WebSocketStateNotifier extends Notifier<WebSocketState> {
|
|||||||
_reconnectTimer?.cancel();
|
_reconnectTimer?.cancel();
|
||||||
state = const WebSocketState.disconnected();
|
state = const WebSocketState.disconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void manualReconnect() {
|
||||||
|
final service = ref.read(websocketProvider);
|
||||||
|
service.manualReconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -530,6 +530,7 @@ class _WebSocketIndicator extends HookConsumerWidget {
|
|||||||
|
|
||||||
Color indicatorColor;
|
Color indicatorColor;
|
||||||
String indicatorText;
|
String indicatorText;
|
||||||
|
bool isInteractive = false;
|
||||||
|
|
||||||
if (websocketState == WebSocketState.connected()) {
|
if (websocketState == WebSocketState.connected()) {
|
||||||
indicatorColor = Colors.green;
|
indicatorColor = Colors.green;
|
||||||
@@ -537,12 +538,16 @@ class _WebSocketIndicator extends HookConsumerWidget {
|
|||||||
} else if (websocketState == WebSocketState.connecting()) {
|
} else if (websocketState == WebSocketState.connecting()) {
|
||||||
indicatorColor = Colors.teal;
|
indicatorColor = Colors.teal;
|
||||||
indicatorText = 'connectionReconnecting';
|
indicatorText = 'connectionReconnecting';
|
||||||
|
} else if (websocketState == WebSocketState.serverDown()) {
|
||||||
|
indicatorColor = Colors.red;
|
||||||
|
indicatorText = 'connectionServerDown';
|
||||||
|
isInteractive = true;
|
||||||
} else {
|
} else {
|
||||||
indicatorColor = Colors.red;
|
indicatorColor = Colors.red;
|
||||||
indicatorText = 'connectionDisconnected';
|
indicatorText = 'connectionDisconnected';
|
||||||
}
|
}
|
||||||
|
|
||||||
return AnimatedPositioned(
|
final widget = AnimatedPositioned(
|
||||||
duration: Duration(milliseconds: 1850),
|
duration: Duration(milliseconds: 1850),
|
||||||
top:
|
top:
|
||||||
user.value == null ||
|
user.value == null ||
|
||||||
@@ -554,7 +559,6 @@ class _WebSocketIndicator extends HookConsumerWidget {
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
height: indicatorHeight,
|
height: indicatorHeight,
|
||||||
child: IgnorePointer(
|
|
||||||
child: Material(
|
child: Material(
|
||||||
elevation:
|
elevation:
|
||||||
user.value == null || websocketState == WebSocketState.connected()
|
user.value == null || websocketState == WebSocketState.connected()
|
||||||
@@ -563,6 +567,12 @@ class _WebSocketIndicator extends HookConsumerWidget {
|
|||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
color: indicatorColor,
|
color: indicatorColor,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: isInteractive
|
||||||
|
? () {
|
||||||
|
ref.read(websocketStateProvider.notifier).manualReconnect();
|
||||||
|
}
|
||||||
|
: null,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
indicatorText,
|
indicatorText,
|
||||||
@@ -573,5 +583,7 @@ class _WebSocketIndicator extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return isInteractive ? widget : IgnorePointer(child: widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user