Initial Commit
This commit is contained in:
283
lib/connection/connection_state.dart
Normal file
283
lib/connection/connection_state.dart
Normal file
@@ -0,0 +1,283 @@
|
||||
import 'dart:async';
|
||||
|
||||
|
||||
enum ConnectionState {
|
||||
|
||||
disconnected,
|
||||
|
||||
|
||||
connecting,
|
||||
|
||||
|
||||
connected,
|
||||
|
||||
|
||||
ready,
|
||||
|
||||
|
||||
reconnecting,
|
||||
|
||||
|
||||
error,
|
||||
|
||||
|
||||
disabled,
|
||||
}
|
||||
|
||||
|
||||
class ConnectionInfo {
|
||||
final ConnectionState state;
|
||||
final DateTime timestamp;
|
||||
final String? message;
|
||||
final Map<String, dynamic>? metadata;
|
||||
final int? attemptNumber;
|
||||
final Duration? reconnectDelay;
|
||||
final String? serverUrl;
|
||||
final int? latency;
|
||||
|
||||
ConnectionInfo({
|
||||
required this.state,
|
||||
required this.timestamp,
|
||||
this.message,
|
||||
this.metadata,
|
||||
this.attemptNumber,
|
||||
this.reconnectDelay,
|
||||
this.serverUrl,
|
||||
this.latency,
|
||||
});
|
||||
|
||||
ConnectionInfo copyWith({
|
||||
ConnectionState? state,
|
||||
DateTime? timestamp,
|
||||
String? message,
|
||||
Map<String, dynamic>? metadata,
|
||||
int? attemptNumber,
|
||||
Duration? reconnectDelay,
|
||||
String? serverUrl,
|
||||
int? latency,
|
||||
}) {
|
||||
return ConnectionInfo(
|
||||
state: state ?? this.state,
|
||||
timestamp: timestamp ?? this.timestamp,
|
||||
message: message ?? this.message,
|
||||
metadata: metadata ?? this.metadata,
|
||||
attemptNumber: attemptNumber ?? this.attemptNumber,
|
||||
reconnectDelay: reconnectDelay ?? this.reconnectDelay,
|
||||
serverUrl: serverUrl ?? this.serverUrl,
|
||||
latency: latency ?? this.latency,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
bool get isActive =>
|
||||
state == ConnectionState.ready || state == ConnectionState.connected;
|
||||
|
||||
|
||||
bool get canSendMessages => state == ConnectionState.ready;
|
||||
|
||||
|
||||
bool get isConnecting =>
|
||||
state == ConnectionState.connecting ||
|
||||
state == ConnectionState.reconnecting;
|
||||
|
||||
|
||||
bool get hasError => state == ConnectionState.error;
|
||||
|
||||
|
||||
bool get isDisconnected =>
|
||||
state == ConnectionState.disconnected ||
|
||||
state == ConnectionState.disabled;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer();
|
||||
buffer.write('ConnectionInfo(state: $state');
|
||||
if (message != null) buffer.write(', message: $message');
|
||||
if (attemptNumber != null) buffer.write(', attempt: $attemptNumber');
|
||||
if (serverUrl != null) buffer.write(', server: $serverUrl');
|
||||
if (latency != null) buffer.write(', latency: ${latency}ms');
|
||||
buffer.write(')');
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ConnectionStateManager {
|
||||
static final ConnectionStateManager _instance =
|
||||
ConnectionStateManager._internal();
|
||||
factory ConnectionStateManager() => _instance;
|
||||
ConnectionStateManager._internal();
|
||||
|
||||
ConnectionInfo _currentInfo = ConnectionInfo(
|
||||
state: ConnectionState.disconnected,
|
||||
timestamp: DateTime.now(),
|
||||
);
|
||||
|
||||
final StreamController<ConnectionInfo> _stateController =
|
||||
StreamController<ConnectionInfo>.broadcast();
|
||||
|
||||
|
||||
ConnectionInfo get currentInfo => _currentInfo;
|
||||
|
||||
|
||||
Stream<ConnectionInfo> get stateStream => _stateController.stream;
|
||||
|
||||
|
||||
final List<ConnectionInfo> _stateHistory = [];
|
||||
|
||||
|
||||
List<ConnectionInfo> get stateHistory => List.unmodifiable(_stateHistory);
|
||||
|
||||
|
||||
void setState(
|
||||
ConnectionState newState, {
|
||||
String? message,
|
||||
Map<String, dynamic>? metadata,
|
||||
int? attemptNumber,
|
||||
Duration? reconnectDelay,
|
||||
String? serverUrl,
|
||||
int? latency,
|
||||
}) {
|
||||
final oldState = _currentInfo.state;
|
||||
final newInfo = _currentInfo.copyWith(
|
||||
state: newState,
|
||||
timestamp: DateTime.now(),
|
||||
message: message,
|
||||
metadata: metadata,
|
||||
attemptNumber: attemptNumber,
|
||||
reconnectDelay: reconnectDelay,
|
||||
serverUrl: serverUrl,
|
||||
latency: latency,
|
||||
);
|
||||
|
||||
_currentInfo = newInfo;
|
||||
_addToHistory(newInfo);
|
||||
_stateController.add(newInfo);
|
||||
|
||||
|
||||
_logStateChange(oldState, newState, message);
|
||||
}
|
||||
|
||||
|
||||
void updateMetadata(Map<String, dynamic> metadata) {
|
||||
final updatedInfo = _currentInfo.copyWith(
|
||||
metadata: {...?(_currentInfo.metadata), ...metadata},
|
||||
);
|
||||
_currentInfo = updatedInfo;
|
||||
_stateController.add(updatedInfo);
|
||||
}
|
||||
|
||||
|
||||
void updateReconnectDelay(Duration delay) {
|
||||
final updatedInfo = _currentInfo.copyWith(reconnectDelay: delay);
|
||||
_currentInfo = updatedInfo;
|
||||
_stateController.add(updatedInfo);
|
||||
}
|
||||
|
||||
|
||||
void updateLatency(int latencyMs) {
|
||||
final updatedInfo = _currentInfo.copyWith(latency: latencyMs);
|
||||
_currentInfo = updatedInfo;
|
||||
_stateController.add(updatedInfo);
|
||||
}
|
||||
|
||||
|
||||
Duration get timeInCurrentState {
|
||||
return DateTime.now().difference(_currentInfo.timestamp);
|
||||
}
|
||||
|
||||
|
||||
int get connectionAttempts {
|
||||
return _stateHistory
|
||||
.where((info) => info.state == ConnectionState.connecting)
|
||||
.length;
|
||||
}
|
||||
|
||||
|
||||
int get errorCount {
|
||||
return _stateHistory
|
||||
.where((info) => info.state == ConnectionState.error)
|
||||
.length;
|
||||
}
|
||||
|
||||
|
||||
double get averageLatency {
|
||||
final latencies = _stateHistory
|
||||
.where((info) => info.latency != null)
|
||||
.map((info) => info.latency!)
|
||||
.toList();
|
||||
|
||||
if (latencies.isEmpty) return 0.0;
|
||||
return latencies.reduce((a, b) => a + b) / latencies.length;
|
||||
}
|
||||
|
||||
|
||||
Map<ConnectionState, int> get stateStatistics {
|
||||
final stats = <ConnectionState, int>{};
|
||||
for (final info in _stateHistory) {
|
||||
stats[info.state] = (stats[info.state] ?? 0) + 1;
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
List<ConnectionInfo> getLastStates(int count) {
|
||||
final start = _stateHistory.length - count;
|
||||
return _stateHistory.sublist(start < 0 ? 0 : start);
|
||||
}
|
||||
|
||||
|
||||
void clearHistory() {
|
||||
_stateHistory.clear();
|
||||
}
|
||||
|
||||
|
||||
void reset() {
|
||||
setState(ConnectionState.disconnected, message: 'Состояние сброшено');
|
||||
clearHistory();
|
||||
}
|
||||
|
||||
void _addToHistory(ConnectionInfo info) {
|
||||
_stateHistory.add(info);
|
||||
|
||||
|
||||
if (_stateHistory.length > 50) {
|
||||
_stateHistory.removeAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
void _logStateChange(
|
||||
ConnectionState from,
|
||||
ConnectionState to,
|
||||
String? message,
|
||||
) {
|
||||
final fromStr = _getStateDisplayName(from);
|
||||
final toStr = _getStateDisplayName(to);
|
||||
final messageStr = message != null ? ' ($message)' : '';
|
||||
|
||||
print('🔄 Состояние подключения: $fromStr → $toStr$messageStr');
|
||||
}
|
||||
|
||||
String _getStateDisplayName(ConnectionState state) {
|
||||
switch (state) {
|
||||
case ConnectionState.disconnected:
|
||||
return 'Отключен';
|
||||
case ConnectionState.connecting:
|
||||
return 'Подключение';
|
||||
case ConnectionState.connected:
|
||||
return 'Подключен';
|
||||
case ConnectionState.ready:
|
||||
return 'Готов';
|
||||
case ConnectionState.reconnecting:
|
||||
return 'Переподключение';
|
||||
case ConnectionState.error:
|
||||
return 'Ошибка';
|
||||
case ConnectionState.disabled:
|
||||
return 'Отключен';
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_stateController.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user