Connection improvements

This commit is contained in:
estevez-dev
2019-04-05 11:48:41 +03:00
parent 8b046b7313
commit b2773635f5
3 changed files with 82 additions and 76 deletions

View File

@ -10,6 +10,8 @@ class Connection {
Connection._internal(); Connection._internal();
String _domain;
String _port;
String displayHostname; String displayHostname;
String _webSocketAPIEndpoint; String _webSocketAPIEndpoint;
String httpWebHost; String httpWebHost;
@ -17,6 +19,8 @@ class Connection {
String _tempToken; String _tempToken;
String oauthUrl; String oauthUrl;
String deviceName; String deviceName;
bool useLovelace = true;
bool settingsLoaded = false;
bool get isAuthenticated => _token != null; bool get isAuthenticated => _token != null;
StreamSubscription _socketSubscription; StreamSubscription _socketSubscription;
Duration connectTimeout = Duration(seconds: 15); Duration connectTimeout = Duration(seconds: 15);
@ -30,40 +34,55 @@ class Connection {
int _currentMessageId = 0; int _currentMessageId = 0;
Map<String, Completer> _messageResolver = {}; Map<String, Completer> _messageResolver = {};
Future init(onStateChange) async { Future init({bool loadSettings, bool forceReconnect: false}) async {
Completer completer = Completer(); Completer completer = Completer();
onStateChangeCallback = onStateChange; if (loadSettings) {
Logger.e("Loading settings...");
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
String domain = prefs.getString('hassio-domain'); useLovelace = prefs.getBool('use-lovelace') ?? true;
String port = prefs.getString('hassio-port'); _domain = prefs.getString('hassio-domain');
displayHostname = "$domain:$port"; _port = prefs.getString('hassio-port');
_webSocketAPIEndpoint = "${prefs.getString('hassio-protocol')}://$domain:$port/api/websocket"; displayHostname = "$_domain:$_port";
httpWebHost = "${prefs.getString('hassio-res-protocol')}://$domain:$port"; _webSocketAPIEndpoint = "${prefs.getString('hassio-protocol')}://$_domain:$_port/api/websocket";
httpWebHost = "${prefs.getString('hassio-res-protocol')}://$_domain:$_port";
//_token = prefs.getString('hassio-token'); //_token = prefs.getString('hassio-token');
final storage = new FlutterSecureStorage(); final storage = new FlutterSecureStorage();
try { try {
_token = await storage.read(key: "hacl_llt"); _token = await storage.read(key: "hacl_llt");
Logger.e("Long-lived token read successful");
} catch (e) { } catch (e) {
Logger.e("Cannt read secure storage. Need to relogin."); Logger.e("Cannt read secure storage. Need to relogin.");
_token = null; _token = null;
await storage.delete(key: "hacl_llt"); await storage.delete(key: "hacl_llt");
} }
if ((domain == null) || (port == null) ||
(domain.length == 0) || (port.length == 0)) {
completer.completeError({"errorCode": 5, "errorMessage": "Check connection settings"});
} else {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
deviceName = androidInfo.model; deviceName = androidInfo.model;
oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent('http://ha-client.homemade.systems/')}&redirect_uri=${Uri.encodeComponent('http://ha-client.homemade.systems/service/auth_callback.html')}"; oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent('http://ha-client.homemade.systems/')}&redirect_uri=${Uri.encodeComponent('http://ha-client.homemade.systems/service/auth_callback.html')}";
settingsLoaded = true;
}
if ((_domain == null) || (_port == null) ||
(_domain.isEmpty) || (_port.isEmpty)) {
completer.completeError({"errorCode": 5, "errorMessage": "Check connection settings"});
}
if (_token == null) { if (_token == null) {
await AuthManager().getTempToken( AuthManager().getTempToken(
oauthUrl: oauthUrl oauthUrl: oauthUrl
).then((token) { ).then((token) {
Logger.d("Token from AuthManager recived"); Logger.d("Token from AuthManager recived");
_tempToken = token; _tempToken = token;
_doConnect(completer: completer, forceReconnect: forceReconnect);
}); });
} else {
_doConnect(completer: completer, forceReconnect: forceReconnect);
} }
return completer.future;
}
void _doConnect({Completer completer, bool forceReconnect}) {
if (forceReconnect || !isConnected) {
_connect().timeout(connectTimeout, onTimeout: () { _connect().timeout(connectTimeout, onTimeout: () {
_disconnect().then((_) { _disconnect().then((_) {
completer.completeError( completer.completeError(
@ -72,8 +91,9 @@ class Connection {
}).then((_) => completer.complete()).catchError((e) { }).then((_) => completer.complete()).catchError((e) {
completer.completeError(e); completer.completeError(e);
}); });
} else {
completer.complete();
} }
return completer.future;
} }
Completer connecting; Completer connecting;
@ -121,6 +141,7 @@ class Connection {
} }
_disconnect() async { _disconnect() async {
isConnected = false;
Logger.d( "Socket disconnecting..."); Logger.d( "Socket disconnecting...");
if (_socketSubscription != null) { if (_socketSubscription != null) {
await _socketSubscription?.cancel(); await _socketSubscription?.cancel();

View File

@ -4,7 +4,7 @@ class HomeAssistant {
final Connection connection = Connection(); final Connection connection = Connection();
bool _useLovelace = false; //bool _useLovelace = false;
//bool isSettingsLoaded = false; //bool isSettingsLoaded = false;
@ -24,7 +24,7 @@ class HomeAssistant {
Duration fetchTimeout = Duration(seconds: 30); Duration fetchTimeout = Duration(seconds: 30);
String get locationName { String get locationName {
if (_useLovelace) { if (Connection().useLovelace) {
return ui?.title ?? ""; return ui?.title ?? "";
} else { } else {
return _instanceConfig["location_name"] ?? ""; return _instanceConfig["location_name"] ?? "";
@ -36,38 +36,22 @@ class HomeAssistant {
bool get isNoViews => ui == null || ui.isEmpty; bool get isNoViews => ui == null || ui.isEmpty;
//int get viewsCount => entities.views.length ?? 0; //int get viewsCount => entities.views.length ?? 0;
HomeAssistant(); HomeAssistant() {
Connection().onStateChangeCallback = _handleEntityStateChange;
Completer _connectCompleter;
Future init() {
if (_connectCompleter != null && !_connectCompleter.isCompleted) {
Logger.w("Previous connection pending...");
return _connectCompleter.future;
}
Logger.d("init...");
_connectCompleter = Completer();
connection.init(_handleEntityStateChange).then((_) {
SharedPreferences.getInstance().then((prefs) {
if (entities == null) entities = EntityCollection(connection.httpWebHost);
_useLovelace = prefs.getBool('use-lovelace') ?? true;
_connectCompleter.complete();
}).catchError((e) => _connectCompleter.completeError(e));
}).catchError((e) => _connectCompleter.completeError(e));
return _connectCompleter.future;
} }
Completer _fetchCompleter; Completer _fetchCompleter;
Future fetch() { Future fetchData() {
if (_fetchCompleter != null && !_fetchCompleter.isCompleted) { if (_fetchCompleter != null && !_fetchCompleter.isCompleted) {
Logger.w("Previous data fetch is not completed yet"); Logger.w("Previous data fetch is not completed yet");
return _fetchCompleter.future; return _fetchCompleter.future;
} }
if (entities == null) entities = EntityCollection(connection.httpWebHost);
_fetchCompleter = Completer(); _fetchCompleter = Completer();
List<Future> futures = []; List<Future> futures = [];
futures.add(_getStates()); futures.add(_getStates());
if (_useLovelace) { if (Connection().useLovelace) {
futures.add(_getLovelace()); futures.add(_getLovelace());
} }
futures.add(_getConfig()); futures.add(_getConfig());
@ -319,7 +303,7 @@ class HomeAssistant {
void _createUI() { void _createUI() {
ui = HomeAssistantUI(); ui = HomeAssistantUI();
if ((_useLovelace) && (_rawLovelaceData != null)) { if ((Connection().useLovelace) && (_rawLovelaceData != null)) {
Logger.d("Creating Lovelace UI"); Logger.d("Creating Lovelace UI");
_parseLovelace(); _parseLovelace();
} else { } else {

View File

@ -191,27 +191,28 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
_settingsSubscription = eventBus.on<SettingsChangedEvent>().listen((event) { _settingsSubscription = eventBus.on<SettingsChangedEvent>().listen((event) {
Logger.d("Settings change event: reconnect=${event.reconnect}"); Logger.d("Settings change event: reconnect=${event.reconnect}");
if (event.reconnect) { if (event.reconnect) {
_reLoad(); _fullLoad();
} }
}); });
_initialLoad(); _fullLoad();
} }
void _initialLoad() async { void _fullLoad() async {
_showInfoBottomBar(progress: true,); _showInfoBottomBar(progress: true,);
widget.homeAssistant.init().then((_){ _subscribe().then((_) {
_subscribe(); Connection().init(loadSettings: true, forceReconnect: true).then((__){
_fetchData(); _fetchData();
});
}, onError: (e) { }, onError: (e) {
_setErrorState(e); _setErrorState(e);
}); });
} }
void _reLoad() { void _quickLoad() {
_hideBottomBar(); _hideBottomBar();
_showInfoBottomBar(progress: true,); _showInfoBottomBar(progress: true,);
widget.homeAssistant.init().then((_){ Connection().init(loadSettings: false, forceReconnect: false).then((_){
_fetchData(); _fetchData();
}, onError: (e) { }, onError: (e) {
_setErrorState(e); _setErrorState(e);
@ -219,7 +220,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
} }
_fetchData() async { _fetchData() async {
await widget.homeAssistant.fetch().then((_) { await widget.homeAssistant.fetchData().then((_) {
_hideBottomBar(); _hideBottomBar();
int currentViewCount = widget.homeAssistant.ui?.views?.length ?? 0; int currentViewCount = widget.homeAssistant.ui?.views?.length ?? 0;
if (_previousViewCount != currentViewCount) { if (_previousViewCount != currentViewCount) {
@ -236,8 +237,8 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
Logger.d("$state"); Logger.d("$state");
if (state == AppLifecycleState.resumed) { if (state == AppLifecycleState.resumed && Connection().settingsLoaded) {
_reLoad(); _quickLoad();
} }
} }
@ -247,7 +248,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
_stateSubscription = eventBus.on<StateChangedEvent>().listen((event) { _stateSubscription = eventBus.on<StateChangedEvent>().listen((event) {
if (event.needToRebuildUI) { if (event.needToRebuildUI) {
Logger.d("New entity. Need to rebuild UI"); Logger.d("New entity. Need to rebuild UI");
_reLoad(); _quickLoad();
} else { } else {
setState(() {}); setState(() {});
} }
@ -255,7 +256,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
} }
if (_reloadUISubscription == null) { if (_reloadUISubscription == null) {
_reloadUISubscription = eventBus.on<ReloadUIEvent>().listen((event){ _reloadUISubscription = eventBus.on<ReloadUIEvent>().listen((event){
_reLoad(); _quickLoad();
}); });
} }
if (_serviceCallSubscription == null) { if (_serviceCallSubscription == null) {
@ -549,7 +550,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
child: Text("Retry", style: textStyle), child: Text("Retry", style: textStyle),
onPressed: () { onPressed: () {
//_scaffoldKey?.currentState?.hideCurrentSnackBar(); //_scaffoldKey?.currentState?.hideCurrentSnackBar();
_reLoad(); _quickLoad();
}, },
); );
break; break;
@ -571,7 +572,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
_bottomBarAction = FlatButton( _bottomBarAction = FlatButton(
child: Text("Login", style: textStyle), child: Text("Login", style: textStyle),
onPressed: () { onPressed: () {
_reLoad(); _fullLoad();
}, },
); );
break; break;
@ -582,7 +583,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
_bottomBarAction = FlatButton( _bottomBarAction = FlatButton(
child: Text("Try again", style: textStyle), child: Text("Try again", style: textStyle),
onPressed: () { onPressed: () {
_reLoad(); _fullLoad();
}, },
); );
break; break;
@ -592,7 +593,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
_bottomBarAction = FlatButton( _bottomBarAction = FlatButton(
child: Text("Login again", style: textStyle), child: Text("Login again", style: textStyle),
onPressed: () { onPressed: () {
_reLoad(); _fullLoad();
}, },
); );
break; break;
@ -603,7 +604,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
child: Text("Reload", style: textStyle), child: Text("Reload", style: textStyle),
onPressed: () { onPressed: () {
//_scaffoldKey?.currentState?.hideCurrentSnackBar(); //_scaffoldKey?.currentState?.hideCurrentSnackBar();
_reLoad(); _fullLoad();
}, },
); );
break; break;
@ -615,7 +616,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
_bottomBarAction = FlatButton( _bottomBarAction = FlatButton(
child: Text("Reconnect", style: textStyle), child: Text("Reconnect", style: textStyle),
onPressed: () { onPressed: () {
_reLoad(); _fullLoad();
}, },
); );
break; break;
@ -625,7 +626,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
_bottomBarAction = FlatButton( _bottomBarAction = FlatButton(
child: Text("Try again", style: textStyle), child: Text("Try again", style: textStyle),
onPressed: () { onPressed: () {
_reLoad(); _fullLoad();
}, },
); );
break; break;
@ -672,10 +673,10 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
items: popupMenuItems items: popupMenuItems
).then((String val) { ).then((String val) {
if (val == "reload") { if (val == "reload") {
_reLoad(); _quickLoad();
} else if (val == "logout") { } else if (val == "logout") {
widget.homeAssistant.logout().then((_) { widget.homeAssistant.logout().then((_) {
_reLoad(); _quickLoad();
}); });
} }
}); });