Читать статью на Habr
class SocketApi {
SocketApi();
IOWebSocketChannel? _socket;
StreamSubscription? _socketSubscription;
Completer<bool> _connecting = Completer<bool>();
}
int? _profileId;
Future<void> setProfile({required final int profileId}) async {
_profileId = profileId;
await _connect();
}
void removeProfile() {
_profileId = null;
_close();
}
Future<void> _connect() async {
await _close();
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('TOKEN');
assert(_profileId != null);
final wsUrl = Uri.parse('ws://my-base-url/ws/chat/$_profileId/?token=$token');
try {
_socket = IOWebSocketChannel.connect(
wsUrl,
pingInterval: const Duration(seconds: 5),
);
_socketSubscription = _socket!.stream.listen(
_onMessage,
onDone: _onDone,
onError: (Object err, StackTrace stackTrace) {
print('Listen err $err, $stackTrace');
},
);
_connecting.complete(true);
debugPrint('connected');
} catch (_) {
debugPrint('cant connected');
}
}
Future<void> _close() async {
_connecting = Completer<bool>();
await _socketSubscription?.cancel();
_socketSubscription = null;
try {
await _socket?.sink.close(status.normalClosure);
} catch (_) {
debugPrint('Socket already closed.');
}
if (_socket != null) {
print(['disconnected', _socket?.closeCode, _socket?.closeReason]);
}
_socket = null;
}
Future<void> _onDone() async {
await _close();
await Future<void>.delayed(const Duration(seconds: 1), () async {
await _connect();
});
}
void _onMessage(dynamic message) {
debugPrint('✅ RECEIVED: $message');
final msg = jsonDecode(message.toString()) as Map<String, dynamic>;
final chatJson = msg['chat'] as Map<String, dynamic>;
final event = msg['type'] as String;
if (event == 'write_message') {
// Реализуем обработчики различных типов событий чата
} else if (event == 'read_messages') {
// то же
}
}
Future<void> _send(
String cmd,
int chatId,
String? message, {
Map<String, dynamic>? data,
}) async {
if (_socket == null) {
await _connect();
}
final connectionResult = await _connecting.future;
if (connectionResult != true) {
return;
}
final d = <String, dynamic>{
'type': cmd,
'chat_id': chatId,
'message': message,
};
d.removeWhere((key, value) => value == null);
final json = jsonEncode(d);
debugPrint('💬 SEND: $d');
_socket!.sink.add(json);
}
Future<void> sendTextMessage({
required final String text,
required final int chatId,
}) async {
await _send('write_message', chatId, text);
}
Future<void> setMessagesRead({required final int chatId}) async {
await _send('read_message', chatId, null);
}