⚡ Better websocket reconnection and maintainer
This commit is contained in:
		| @@ -17,11 +17,11 @@ import 'package:solian/utils/services_url.dart'; | ||||
| import 'package:solian/widgets/chat/call/exts.dart'; | ||||
| import 'package:solian/widgets/exts.dart'; | ||||
| import 'package:wakelock_plus/wakelock_plus.dart'; | ||||
| import 'package:web_socket_channel/web_socket_channel.dart'; | ||||
| import 'package:web_socket_channel/io.dart'; | ||||
| import 'package:web_socket_channel/status.dart' as status; | ||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||
|  | ||||
| class ChatProvider extends ChangeNotifier { | ||||
|   bool isOpened = false; | ||||
|   bool isCallShown = false; | ||||
|  | ||||
|   Call? ongoingCall; | ||||
| @@ -31,12 +31,16 @@ class ChatProvider extends ChangeNotifier { | ||||
|  | ||||
|   PagingController<int, Message>? historyPagingController; | ||||
|  | ||||
|   WebSocketChannel? _channel; | ||||
|   IOWebSocketChannel? _channel; | ||||
|  | ||||
|   Future<WebSocketChannel?> connect(AuthProvider auth, {noRetry = false}) async { | ||||
|   Future<IOWebSocketChannel?> connect(AuthProvider auth, {noRetry = false}) async { | ||||
|     if (auth.client == null) await auth.loadClient(); | ||||
|     if (!await auth.isAuthorized()) return null; | ||||
|  | ||||
|     if (_channel != null && (_channel!.innerWebSocket?.readyState ?? 0) < 2) { | ||||
|       return _channel; | ||||
|     } | ||||
|  | ||||
|     var ori = getRequestUri('messaging', '/api/ws'); | ||||
|     var uri = Uri( | ||||
|       scheme: ori.scheme.replaceFirst('http', 'ws'), | ||||
| @@ -46,10 +50,8 @@ class ChatProvider extends ChangeNotifier { | ||||
|       queryParameters: {'tk': Uri.encodeComponent(auth.client!.currentToken!)}, | ||||
|     ); | ||||
|  | ||||
|     isOpened = true; | ||||
|  | ||||
|     try { | ||||
|       _channel = WebSocketChannel.connect(uri); | ||||
|       _channel = IOWebSocketChannel.connect(uri); | ||||
|       await _channel!.ready; | ||||
|     } catch (e) { | ||||
|       if (!noRetry) { | ||||
| @@ -108,8 +110,7 @@ class ChatProvider extends ChangeNotifier { | ||||
|   } | ||||
|  | ||||
|   void disconnect() { | ||||
|     _channel = null; | ||||
|     isOpened = false; | ||||
|     _channel?.sink.close(status.goingAway); | ||||
|   } | ||||
|  | ||||
|   Future<void> fetchMessages(int pageKey, BuildContext context) async { | ||||
|   | ||||
| @@ -45,13 +45,11 @@ class KeypairProvider extends ChangeNotifier { | ||||
|   void receiveKeypair(Keypair kp) { | ||||
|     keys[kp.id] = kp; | ||||
|     requestingKeys.remove(kp.id); | ||||
|     saveKeys(); | ||||
|     notifyListeners(); | ||||
|     saveKeys(); | ||||
|   } | ||||
|  | ||||
|   Keypair? provideKeypair(String id) { | ||||
|     print(id); | ||||
|     print(keys[id]); | ||||
|     return keys[id]; | ||||
|   } | ||||
|  | ||||
| @@ -79,9 +77,11 @@ class KeypairProvider extends ChangeNotifier { | ||||
|     saveKeys(); | ||||
|   } | ||||
|  | ||||
|   bool requestKey(String id, String algorithm, int uid) { | ||||
|     if (channel == null) return false; | ||||
|     if (requestingKeys.contains(id)) return false; | ||||
|   void requestKey(String id, String algorithm, int uid) { | ||||
|     if (channel == null) return; | ||||
|     if (requestingKeys.contains(id)) return; | ||||
|  | ||||
|     print('requested $id'); | ||||
|  | ||||
|     channel!.sink.add(jsonEncode( | ||||
|       NetworkPackage(method: 'kex.request', payload: { | ||||
| @@ -95,7 +95,6 @@ class KeypairProvider extends ChangeNotifier { | ||||
|  | ||||
|     requestingKeys.add(id); | ||||
|     notifyListeners(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   String? encodeViaAESKey(String keypairId, String content) { | ||||
|   | ||||
| @@ -10,11 +10,11 @@ import 'package:solian/models/pagination.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/utils/services_url.dart'; | ||||
| import 'package:solian/models/notification.dart' as model; | ||||
| import 'package:web_socket_channel/web_socket_channel.dart'; | ||||
| import 'package:web_socket_channel/io.dart'; | ||||
| import 'package:web_socket_channel/status.dart' as status; | ||||
| import 'dart:math' as math; | ||||
|  | ||||
| class NotifyProvider extends ChangeNotifier { | ||||
|   bool isOpened = false; | ||||
|   int unreadAmount = 0; | ||||
|  | ||||
|   List<model.Notification> notifications = List.empty(growable: true); | ||||
| @@ -64,10 +64,9 @@ class NotifyProvider extends ChangeNotifier { | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   WebSocketChannel? _channel; | ||||
|   IOWebSocketChannel? _channel; | ||||
|  | ||||
|   Future<WebSocketChannel?> connect( | ||||
|     AuthProvider auth, { | ||||
|   Future<IOWebSocketChannel?> connect(AuthProvider auth, { | ||||
|     Keypair? Function(String id)? onKexRequest, | ||||
|     Function(Keypair kp)? onKexProvide, | ||||
|     bool noRetry = false, | ||||
| @@ -75,8 +74,9 @@ class NotifyProvider extends ChangeNotifier { | ||||
|     if (auth.client == null) await auth.loadClient(); | ||||
|     if (!await auth.isAuthorized()) return null; | ||||
|  | ||||
|     await auth.client!.refreshToken(auth.client!.currentRefreshToken!); | ||||
|  | ||||
|     if (_channel != null && (_channel!.innerWebSocket?.readyState ?? 0) < 2) { | ||||
|       return _channel; | ||||
|     } | ||||
|     var ori = getRequestUri('passport', '/api/ws'); | ||||
|     var uri = Uri( | ||||
|       scheme: ori.scheme.replaceFirst('http', 'ws'), | ||||
| @@ -86,10 +86,8 @@ class NotifyProvider extends ChangeNotifier { | ||||
|       queryParameters: {'tk': Uri.encodeComponent(auth.client!.currentToken!)}, | ||||
|     ); | ||||
|  | ||||
|     isOpened = true; | ||||
|  | ||||
|     try { | ||||
|       _channel = WebSocketChannel.connect(uri); | ||||
|       _channel = IOWebSocketChannel.connect(uri); | ||||
|       await _channel!.ready; | ||||
|     } catch (e) { | ||||
|       if (!noRetry) { | ||||
| @@ -101,7 +99,7 @@ class NotifyProvider extends ChangeNotifier { | ||||
|     } | ||||
|  | ||||
|     _channel!.stream.listen( | ||||
|       (event) { | ||||
|           (event) { | ||||
|         final result = NetworkPackage.fromJson(jsonDecode(event)); | ||||
|         switch (result.method) { | ||||
|           case 'notifications.new': | ||||
| @@ -143,8 +141,7 @@ class NotifyProvider extends ChangeNotifier { | ||||
|   } | ||||
|  | ||||
|   void disconnect() { | ||||
|     _channel = null; | ||||
|     isOpened = false; | ||||
|     _channel?.sink.close(status.goingAway); | ||||
|   } | ||||
|  | ||||
|   void notifyMessage(String title, String body) { | ||||
|   | ||||
| @@ -38,7 +38,6 @@ class _ChatMemberScreenState extends State<ChatMemberScreen> { | ||||
|     _selfId = prof['id']; | ||||
|  | ||||
|     var uri = getRequestUri('messaging', '/api/channels/${widget.realm}/${widget.channel.alias}/members'); | ||||
|     print(uri); | ||||
|  | ||||
|     var res = await auth.client!.get(uri); | ||||
|     if (res.statusCode == 200) { | ||||
|   | ||||
| @@ -162,7 +162,7 @@ class _ChatWidgetState extends State<ChatWidget> { | ||||
|     Future.delayed(Duration.zero, () async { | ||||
|       final auth = context.read<AuthProvider>(); | ||||
|  | ||||
|       if (!_chat.isOpened) await _chat.connect(auth); | ||||
|       await _chat.connect(auth); | ||||
|  | ||||
|       _chat.fetchOngoingCall(widget.alias, widget.realm); | ||||
|       _chat.fetchChannel(context, auth, widget.alias, widget.realm).then((result) { | ||||
|   | ||||
| @@ -55,12 +55,11 @@ class _ChatMessageContentState extends State<ChatMessageContent> { | ||||
|           final keypair = context.watch<KeypairProvider>(); | ||||
|           if (keypair.keys[widget.item.decodedContent['keypair_id']] == null) { | ||||
|             WidgetsBinding.instance.addPostFrameCallback((_) { | ||||
|               if (keypair.requestKey( | ||||
|               keypair.requestKey( | ||||
|                 widget.item.decodedContent['keypair_id'], | ||||
|                 widget.item.decodedContent['algorithm'], | ||||
|                 widget.item.sender.account.externalId!, | ||||
|               )) { | ||||
|               } | ||||
|               ); | ||||
|             }); | ||||
|           } else { | ||||
|             content = keypair.decodeViaAESKey( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| import 'dart:async'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| @@ -43,6 +45,11 @@ class _ProviderInitializerState extends State<ProviderInitializer> { | ||||
|           onKexRequest: keypair.provideKeypair, | ||||
|           onKexProvide: keypair.receiveKeypair, | ||||
|         ); | ||||
|  | ||||
|         Timer.periodic(const Duration(seconds: 1), (timer) { | ||||
|           nty.connect(auth); | ||||
|           chat.connect(auth); | ||||
|         }); | ||||
|       } | ||||
|     } catch (e) { | ||||
|       context.showErrorDialog(e); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user