mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 13:08:42 +00:00
websocket automatic reconnection
This commit is contained in:
parent
e358cf2e57
commit
aa608be1e4
5 changed files with 57 additions and 18 deletions
3
devtools_options.yaml
Normal file
3
devtools_options.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
|
extensions:
|
||||||
|
|
@ -12,6 +12,7 @@ import 'package:twonly/src/proto/api/error.pb.dart';
|
||||||
import 'package:twonly/src/proto/api/server_to_client.pb.dart' as server;
|
import 'package:twonly/src/proto/api/server_to_client.pb.dart' as server;
|
||||||
import 'package:twonly/src/signal/signal_helper.dart';
|
import 'package:twonly/src/signal/signal_helper.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:web_socket_channel/io.dart';
|
||||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||||
|
|
||||||
class Result<T, E> {
|
class Result<T, E> {
|
||||||
|
|
@ -31,19 +32,19 @@ class ApiProvider {
|
||||||
final String apiUrl;
|
final String apiUrl;
|
||||||
final String? backupApiUrl;
|
final String? backupApiUrl;
|
||||||
final log = Logger("connect::ApiProvider");
|
final log = Logger("connect::ApiProvider");
|
||||||
final HashMap<String, List<Function>> _callbacks = HashMap();
|
Function(bool)? _connectionStateCallback;
|
||||||
|
|
||||||
final HashMap<Int64, server.ServerToClient?> messagesV0 = HashMap();
|
final HashMap<Int64, server.ServerToClient?> messagesV0 = HashMap();
|
||||||
|
|
||||||
WebSocketChannel? _channel;
|
IOWebSocketChannel? _channel;
|
||||||
|
|
||||||
Future<bool> _connectTo(String apiUrl) async {
|
Future<bool> _connectTo(String apiUrl) async {
|
||||||
try {
|
try {
|
||||||
var channel = WebSocketChannel.connect(
|
var channel = IOWebSocketChannel.connect(
|
||||||
Uri.parse(apiUrl),
|
Uri.parse(apiUrl),
|
||||||
);
|
);
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
_channel!.stream.listen(_onData);
|
_channel!.stream.listen(_onData, onDone: _onDone, onError: _onError);
|
||||||
await _channel!.ready;
|
await _channel!.ready;
|
||||||
log.info("Websocket is connected!");
|
log.info("Websocket is connected!");
|
||||||
print("Websocket is connected!");
|
print("Websocket is connected!");
|
||||||
|
|
@ -56,9 +57,14 @@ class ApiProvider {
|
||||||
|
|
||||||
Future<bool> connect(Function(bool)? callBack) async {
|
Future<bool> connect(Function(bool)? callBack) async {
|
||||||
print("Trying to connect to the backend $apiUrl!");
|
print("Trying to connect to the backend $apiUrl!");
|
||||||
|
if (callBack != null) {
|
||||||
|
_connectionStateCallback = callBack;
|
||||||
|
}
|
||||||
if (_channel != null && _channel!.closeCode != null) {
|
if (_channel != null && _channel!.closeCode != null) {
|
||||||
|
print("is connected");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Trying to connect to the backend $apiUrl!");
|
log.info("Trying to connect to the backend $apiUrl!");
|
||||||
if (await _connectTo(apiUrl)) {
|
if (await _connectTo(apiUrl)) {
|
||||||
if (callBack != null) callBack(true);
|
if (callBack != null) callBack(true);
|
||||||
|
|
@ -76,6 +82,37 @@ class ApiProvider {
|
||||||
|
|
||||||
bool get isConnected => _channel != null && _channel!.closeCode != null;
|
bool get isConnected => _channel != null && _channel!.closeCode != null;
|
||||||
|
|
||||||
|
void _onDone() {
|
||||||
|
if (_connectionStateCallback != null) {
|
||||||
|
_connectionStateCallback!(false);
|
||||||
|
}
|
||||||
|
_channel = null;
|
||||||
|
tryToReconnect(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onError(dynamic e) {
|
||||||
|
if (_connectionStateCallback != null) {
|
||||||
|
_connectionStateCallback!(false);
|
||||||
|
}
|
||||||
|
_channel = null;
|
||||||
|
tryToReconnect(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tryToReconnect(int delay) {
|
||||||
|
Future.delayed(Duration(seconds: delay)).then(
|
||||||
|
(value) async {
|
||||||
|
if (!await connect(_connectionStateCallback)) {
|
||||||
|
if (delay > 60 * 5) {
|
||||||
|
delay = 60 * 5;
|
||||||
|
} else {
|
||||||
|
delay = delay * 2;
|
||||||
|
}
|
||||||
|
tryToReconnect(delay);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _onData(dynamic msgBuffer) {
|
void _onData(dynamic msgBuffer) {
|
||||||
try {
|
try {
|
||||||
final msg = server.ServerToClient.fromBuffer(msgBuffer);
|
final msg = server.ServerToClient.fromBuffer(msgBuffer);
|
||||||
|
|
@ -89,13 +126,6 @@ class ApiProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addNotifier(String messageType, Function callBackFunction) {
|
|
||||||
if (!_callbacks.containsKey(messageType)) {
|
|
||||||
_callbacks[messageType] = [];
|
|
||||||
}
|
|
||||||
_callbacks[messageType]!.add(callBackFunction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: There must be a smarter move to do that :/
|
// TODO: There must be a smarter move to do that :/
|
||||||
Future<server.ServerToClient?> _waitForResponse(Int64 seq) async {
|
Future<server.ServerToClient?> _waitForResponse(Int64 seq) async {
|
||||||
final startTime = DateTime.now();
|
final startTime = DateTime.now();
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,17 @@ Future<bool> isUserCreated() async {
|
||||||
Future<UserData?> getUser() async {
|
Future<UserData?> getUser() async {
|
||||||
final storage = getSecureStorage();
|
final storage = getSecureStorage();
|
||||||
String? userJson = await storage.read(key: "user_data");
|
String? userJson = await storage.read(key: "user_data");
|
||||||
|
print(userJson);
|
||||||
if (userJson == null) {
|
if (userJson == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final userMap = jsonDecode(userJson) as Map<String, dynamic>;
|
final userMap = jsonDecode(userJson) as Map<String, dynamic>;
|
||||||
final user = UserData.fromJson(userMap);
|
final user = UserData.fromJson(userMap);
|
||||||
|
print(user);
|
||||||
return user;
|
return user;
|
||||||
} catch (_) {
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,10 +43,10 @@ class CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
|
|
||||||
final size = Size(50, 300);
|
final size = Size(50, 300);
|
||||||
|
|
||||||
_controller.initialize().then((_) {
|
// _controller.initialize().then((_) {
|
||||||
_controller.value = _controller.value.copyWith(previewSize: size);
|
// _controller.value = _controller.value.copyWith(previewSize: size);
|
||||||
setState(() {});
|
// setState(() {});
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Next, initialize the controller. This returns a Future.
|
// Next, initialize the controller. This returns a Future.
|
||||||
_initializeControllerFuture = _controller.initialize();
|
_initializeControllerFuture = _controller.initialize();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'package:twonly/src/model/user_data_json.dart';
|
||||||
|
|
||||||
import '../settings/settings_controller.dart';
|
import '../settings/settings_controller.dart';
|
||||||
import '../settings/settings_view.dart';
|
import '../settings/settings_view.dart';
|
||||||
import '../utils.dart';
|
import '../utils.dart';
|
||||||
|
|
@ -14,13 +16,14 @@ class ProfileView extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ProfileViewState extends State<ProfileView> {
|
class _ProfileViewState extends State<ProfileView> {
|
||||||
|
final Future<UserData?> _userData = getUser();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// var user = await getUser();
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: FutureBuilder(
|
title: FutureBuilder(
|
||||||
future: getUser(),
|
future: _userData,
|
||||||
builder: (context, snap) {
|
builder: (context, snap) {
|
||||||
if (snap.hasData) {
|
if (snap.hasData) {
|
||||||
return Text("Hello ${snap.data!.username}!");
|
return Text("Hello ${snap.data!.username}!");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue