diff --git a/Borepin/Borepin/App.xaml.cs b/Borepin/Borepin/App.xaml.cs index 76e7c3e..07201ec 100644 --- a/Borepin/Borepin/App.xaml.cs +++ b/Borepin/Borepin/App.xaml.cs @@ -11,6 +11,7 @@ using Borepin.Page.AddServerProcess; using Borepin.PageModel.AddServerProcess; using System; using Borepin.Service.Storage; +using NLog; namespace Borepin { @@ -18,7 +19,10 @@ namespace Borepin { public App(IPlatformInitializer platformInitializer) : base(platformInitializer) { - + var config = new NLog.Config.LoggingConfiguration(); + var logconsole = new NLog.Targets.ConsoleTarget("logconsole"); + config.AddRule(LogLevel.Trace, LogLevel.Fatal, logconsole); + LogManager.Configuration = config; } protected override async void OnInitialized() diff --git a/Borepin/Borepin/Base/ConnectionModelBase.cs b/Borepin/Borepin/Base/ConnectionModelBase.cs index 7cc07b3..1bed4f5 100644 --- a/Borepin/Borepin/Base/ConnectionModelBase.cs +++ b/Borepin/Borepin/Base/ConnectionModelBase.cs @@ -26,18 +26,29 @@ namespace Borepin.Base #endregion #region Methods - public void OnConnectionStatusChanged(object sender, ConnectionStatusChange args) + public async void OnConnectionStatusChanged(object sender, ConnectionStatusChange args) { switch(args) { case ConnectionStatusChange.Connected: IsConnected = true; - LoadAPIData(); + await LoadAPIData().ConfigureAwait(false); break; case ConnectionStatusChange.Reconnected: - ReloadAPIData(); + await ReloadAPIData().ConfigureAwait(false); break; case ConnectionStatusChange.ConnectionLoss: + try + { + await _API.Reconnect().ConfigureAwait(false); + } + catch + { + IsConnected = false; + await _API.Disconnect().ConfigureAwait(false); + _API.UnbindAllEvents(); + } + break; case ConnectionStatusChange.Disconnected: IsConnected = false; break; diff --git a/Borepin/Borepin/PageModel/AddServerProcess/SelectServerPageModel.cs b/Borepin/Borepin/PageModel/AddServerProcess/SelectServerPageModel.cs index b4fb613..2fbb07e 100644 --- a/Borepin/Borepin/PageModel/AddServerProcess/SelectServerPageModel.cs +++ b/Borepin/Borepin/PageModel/AddServerProcess/SelectServerPageModel.cs @@ -8,6 +8,7 @@ using System; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows.Input; +using Xamarin.Forms; namespace Borepin.PageModel.AddServerProcess { @@ -98,7 +99,7 @@ namespace Borepin.PageModel.AddServerProcess try { API api = new API(); - await api.TestConnection(_ConnectionData).ConfigureAwait(true); + await api.TestConnection(_ConnectionData).ConfigureAwait(false); } catch(ConnectingFailedException) { @@ -108,11 +109,14 @@ namespace Borepin.PageModel.AddServerProcess return; } - INavigationResult result = await _NavigationService.NavigateAsync("AddServerProcess_ChooseAuthTypePage").ConfigureAwait(false); - if (result.Exception != null) + Device.BeginInvokeOnMainThread(async () => { - Log.Fatal(result.Exception, "Navigating failed"); - } + INavigationResult result = await _NavigationService.NavigateAsync("AddServerProcess_ChooseAuthTypePage").ConfigureAwait(false); + if (result.Exception != null) + { + Log.Fatal(result.Exception, "Navigating failed"); + } + }); } private ICommand _ScanCodeCommand; diff --git a/Borepin/Borepin/PageModel/MachineListPageModel.cs b/Borepin/Borepin/PageModel/MachineListPageModel.cs index ea71b41..b02599d 100644 --- a/Borepin/Borepin/PageModel/MachineListPageModel.cs +++ b/Borepin/Borepin/PageModel/MachineListPageModel.cs @@ -12,6 +12,7 @@ using System; using NaturalSort.Extension; using System.Linq; using Borepin.Service; +using Xamarin.Forms; namespace Borepin.PageModel { @@ -101,7 +102,7 @@ namespace Borepin.PageModel get => _SelectInstanceCommand; set => SetProperty(ref _SelectInstanceCommand, value); } - public async void SelectInstanceCommandExecute(object obj) + public void SelectInstanceCommandExecute(object obj) { MachineListItemViewModel viewmodel = obj as MachineListItemViewModel; @@ -110,7 +111,14 @@ namespace Borepin.PageModel { "instance", viewmodel.Instance.Id }, }; - await _NavigationService.NavigateAsync($"MachinePage", parameters).ConfigureAwait(false); + Device.BeginInvokeOnMainThread(async () => + { + INavigationResult result = await _NavigationService.NavigateAsync($"MachinePage", parameters).ConfigureAwait(false); + if (result.Exception != null) + { + Log.Fatal(result.Exception, "Navigating failed"); + } + }); } private ICommand _ScanCodeCommand; @@ -154,7 +162,7 @@ namespace Borepin.PageModel #endregion #region IPageLifecycleAware - public async void OnAppearing() + public void OnAppearing() { if(_NextMachine != null) { @@ -164,8 +172,15 @@ namespace Borepin.PageModel }; _NextMachine = null; - - await _NavigationService.NavigateAsync("MachinePage", parameters).ConfigureAwait(false); + + Device.BeginInvokeOnMainThread(async () => + { + INavigationResult result = await _NavigationService.NavigateAsync("MachinePage", parameters).ConfigureAwait(false); + if (result.Exception != null) + { + Log.Fatal(result.Exception, "Navigating failed"); + } + }); } } diff --git a/Borepin/Borepin/PageModel/MachinePageModel.cs b/Borepin/Borepin/PageModel/MachinePageModel.cs index 9f2dfe5..2a3158f 100644 --- a/Borepin/Borepin/PageModel/MachinePageModel.cs +++ b/Borepin/Borepin/PageModel/MachinePageModel.cs @@ -8,6 +8,8 @@ using Borepin.Model; using Prism.Services; using Borepin.Service; using Borepin.Base.Exceptions; +using Capnp.Rpc; +using System; namespace Borepin.PageModel { @@ -74,10 +76,17 @@ namespace Borepin.PageModel if(_API.IsConnected) { - Machine.IUseInterface useInterface = _Machine.Use; + try + { + Machine.IUseInterface useInterface = _Machine.Use; - await useInterface.Use().ConfigureAwait(false); - await LoadAPIData().ConfigureAwait(false); + await useInterface.Use().ConfigureAwait(false); + await LoadAPIData().ConfigureAwait(false); + } + catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal)) + { + Log.Debug("RPC Connection Loss"); + } } IsBusy = false; @@ -96,10 +105,17 @@ namespace Borepin.PageModel if (_API.IsConnected) { - Machine.IInUseInterface inUseInterface = _Machine.Inuse; + try + { + Machine.IInUseInterface inUseInterface = _Machine.Inuse; - await inUseInterface.GiveBack().ConfigureAwait(false); - await LoadAPIData().ConfigureAwait(false); + await inUseInterface.GiveBack().ConfigureAwait(false); + await LoadAPIData().ConfigureAwait(false); + } + catch(RpcException exception) when(string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal)) + { + Log.Debug("RPC Connection Loss"); + } } IsBusy = false; diff --git a/Borepin/Borepin/PageModel/SetUpProcess/WelcomePageModel.cs b/Borepin/Borepin/PageModel/SetUpProcess/WelcomePageModel.cs index 2f82a3b..2db475e 100644 --- a/Borepin/Borepin/PageModel/SetUpProcess/WelcomePageModel.cs +++ b/Borepin/Borepin/PageModel/SetUpProcess/WelcomePageModel.cs @@ -2,8 +2,8 @@ using Prism.Commands; using Prism.Navigation; using Prism.Services; -using System.Threading.Tasks; using System.Windows.Input; +using Xamarin.Forms; namespace Borepin.PageModel.SetUpProcess { @@ -23,9 +23,17 @@ namespace Borepin.PageModel.SetUpProcess get => _NextCommand; set => SetProperty(ref _NextCommand, value); } - public async void NextCommandCommandExecute(object obj) + public void NextCommandCommandExecute(object obj) { - await _NavigationService.NavigateAsync("AddServerProcess_SelectServerPage").ConfigureAwait(false); + Device.BeginInvokeOnMainThread(async () => + { + INavigationResult result = await _NavigationService.NavigateAsync("AddServerProcess_SelectServerPage").ConfigureAwait(false); + if (result.Exception != null) + { + Log.Fatal(result.Exception, "Navigating failed"); + } + }); + } #endregion } diff --git a/FabAccessAPI/API.cs b/FabAccessAPI/API.cs index fe5cbdd..81e91bd 100644 --- a/FabAccessAPI/API.cs +++ b/FabAccessAPI/API.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Net.Security; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; +using System.Threading; using System.Threading.Tasks; namespace FabAccessAPI @@ -22,6 +23,8 @@ namespace FabAccessAPI #region Private Members private TcpRpcClient _TcpRpcClient; private IBootstrap _Bootstrap; + private static SemaphoreSlim _ConnectSemaphore = new SemaphoreSlim(1, 1); + private static SemaphoreSlim _ReconnectSemaphore = new SemaphoreSlim(1, 1); #endregion #region Constructors @@ -36,22 +39,10 @@ namespace FabAccessAPI public void OnTcpRpcConnectionChanged(object sender, ConnectionStateChange args) { - EventHandler eventHandler = ConnectionStatusChanged; - - if (eventHandler == null) - { - return; - } - - if (args.LastState == ConnectionState.Initializing && args.NewState == ConnectionState.Active) - { - Log.Trace("TcpRpcClient Event Connected"); - eventHandler(this, ConnectionStatusChange.Connected); - } if (args.LastState == ConnectionState.Active && args.NewState == ConnectionState.Down) { Log.Trace("TcpRpcClient Event ConnectionLoss"); - eventHandler(this, ConnectionStatusChange.ConnectionLoss); + ConnectionStatusChanged?.Invoke(this, ConnectionStatusChange.ConnectionLoss); _TcpRpcClient = null; } } @@ -92,39 +83,44 @@ namespace FabAccessAPI /// public async Task Connect(ConnectionData connectionData, TcpRpcClient tcpRpcClient = null) { - if (IsConnected) - { - await Disconnect(); - } - - if(tcpRpcClient == null) - { - _TcpRpcClient = new TcpRpcClient(); - } - else - { - _TcpRpcClient = tcpRpcClient; - } - + await _ConnectSemaphore.WaitAsync(); try { - _TcpRpcClient.ConnectionStateChanged += OnTcpRpcConnectionChanged; + if (IsConnected) + { + await Disconnect(); + } - await _ConnectAsync(_TcpRpcClient, connectionData).ConfigureAwait(false); - - _Bootstrap = _TcpRpcClient.GetMain(); - ConnectionInfo = await _GetConnectionInfo(_Bootstrap); + if (tcpRpcClient == null) + { + tcpRpcClient = new TcpRpcClient(); + } - Session = await _Authenticate(connectionData).ConfigureAwait(false); - ConnectionData = connectionData; + try + { + await _ConnectAsync(tcpRpcClient, connectionData).ConfigureAwait(false); - Log.Info("API connected"); + _Bootstrap = tcpRpcClient.GetMain(); + ConnectionInfo = await _GetConnectionInfo(_Bootstrap); + + Session = await _Authenticate(connectionData).ConfigureAwait(false); + ConnectionData = connectionData; + + _TcpRpcClient = tcpRpcClient; + tcpRpcClient.ConnectionStateChanged += OnTcpRpcConnectionChanged; + ConnectionStatusChanged?.Invoke(this, ConnectionStatusChange.Connected); + Log.Info("API connected"); + } + catch (System.Exception ex) + { + await Disconnect().ConfigureAwait(false); + Log.Warn(ex, "API connecting failed"); + throw ex; + } } - catch(System.Exception ex) + finally { - await Disconnect().ConfigureAwait(false); - Log.Warn(ex, "API connecting failed"); - throw ex; + _ConnectSemaphore.Release(); } } @@ -150,13 +146,22 @@ namespace FabAccessAPI public async Task Reconnect() { - if (ConnectionData != null) + await _ReconnectSemaphore.WaitAsync(); + try { - await Connect(ConnectionData); - } + if (ConnectionData != null && IsConnected == false) + { + await Connect(ConnectionData); + } - ConnectionStatusChanged?.Invoke(this, ConnectionStatusChange.Reconnected); - Log.Info("API reconnected"); + ConnectionStatusChanged?.Invoke(this, ConnectionStatusChange.Reconnected); + Log.Info("API reconnected"); + } + finally + { + _ReconnectSemaphore.Release(); + } + } public async Task TestConnection(ConnectionData connectionData, TcpRpcClient tcpRpcClient = null) diff --git a/external/capnproto-dotnetcore b/external/capnproto-dotnetcore index 0176a50..086bbc2 160000 --- a/external/capnproto-dotnetcore +++ b/external/capnproto-dotnetcore @@ -1 +1 @@ -Subproject commit 0176a503c8d0b0be66e0212e04200c8324e11fd9 +Subproject commit 086bbc2497785d2cc63e9252df6f6d3ee7599579