Better websocket reconnection and maintainer

This commit is contained in:
LittleSheep 2024-05-13 22:12:37 +08:00
parent b9461e5019
commit f43f9e91f6
7 changed files with 36 additions and 34 deletions

View File

@ -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 {

View File

@ -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) {

View File

@ -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) {
@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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(

View File

@ -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);