diff --git a/App/App.xaml.cs b/App/App.xaml.cs index 5b82ced..06ab676 100644 --- a/App/App.xaml.cs +++ b/App/App.xaml.cs @@ -165,20 +165,22 @@ protected override void OnLaunched(LaunchActivatedEventArgs args) }, CancellationToken.None); // Initialize file sync. - var syncSessionCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var syncSessionController = _services.GetRequiredService(); - _ = syncSessionController.RefreshState(syncSessionCts.Token).ContinueWith(t => - { - if (t.IsCanceled || t.Exception != null) - { - _logger.LogError(t.Exception, "failed to refresh sync state (canceled = {canceled})", t.IsCanceled); -#if DEBUG - Debugger.Break(); -#endif - } + // We're adding a 5s delay here to avoid race conditions when loading the mutagen binary. - syncSessionCts.Dispose(); - }, CancellationToken.None); + _ = Task.Delay(5000).ContinueWith((_) => + { + var syncSessionCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var syncSessionController = _services.GetRequiredService(); + syncSessionController.RefreshState(syncSessionCts.Token).ContinueWith( + t => + { + if (t.IsCanceled || t.Exception != null) + { + _logger.LogError(t.Exception, "failed to refresh sync state (canceled = {canceled})", t.IsCanceled); + } + syncSessionCts.Dispose(); + }, CancellationToken.None); + }); // Prevent the TrayWindow from closing, just hide it. var trayWindow = _services.GetRequiredService(); diff --git a/App/Services/RpcController.cs b/App/Services/RpcController.cs index 7beff66..7461ba8 100644 --- a/App/Services/RpcController.cs +++ b/App/Services/RpcController.cs @@ -313,7 +313,7 @@ private void SpeakerOnError(Exception e) Debug.WriteLine($"Error: {e}"); try { - Reconnect(CancellationToken.None).Wait(); + using var _ = Reconnect(CancellationToken.None); } catch { diff --git a/App/ViewModels/FileSyncListViewModel.cs b/App/ViewModels/FileSyncListViewModel.cs index 4777183..cb84f56 100644 --- a/App/ViewModels/FileSyncListViewModel.cs +++ b/App/ViewModels/FileSyncListViewModel.cs @@ -143,9 +143,9 @@ public void Initialize(Window window, DispatcherQueue dispatcherQueue) var rpcModel = _rpcController.GetState(); var credentialModel = _credentialManager.GetCachedCredentials(); - MaybeSetUnavailableMessage(rpcModel, credentialModel); var syncSessionState = _syncSessionController.GetState(); UpdateSyncSessionState(syncSessionState); + MaybeSetUnavailableMessage(rpcModel, credentialModel, syncSessionState); } private void RpcControllerStateChanged(object? sender, RpcModel rpcModel) @@ -159,7 +159,8 @@ private void RpcControllerStateChanged(object? sender, RpcModel rpcModel) } var credentialModel = _credentialManager.GetCachedCredentials(); - MaybeSetUnavailableMessage(rpcModel, credentialModel); + var syncSessionState = _syncSessionController.GetState(); + MaybeSetUnavailableMessage(rpcModel, credentialModel, syncSessionState); } private void CredentialManagerCredentialsChanged(object? sender, CredentialModel credentialModel) @@ -173,7 +174,8 @@ private void CredentialManagerCredentialsChanged(object? sender, CredentialModel } var rpcModel = _rpcController.GetState(); - MaybeSetUnavailableMessage(rpcModel, credentialModel); + var syncSessionState = _syncSessionController.GetState(); + MaybeSetUnavailableMessage(rpcModel, credentialModel, syncSessionState); } private void SyncSessionStateChanged(object? sender, SyncSessionControllerStateModel syncSessionState) @@ -189,7 +191,7 @@ private void SyncSessionStateChanged(object? sender, SyncSessionControllerStateM UpdateSyncSessionState(syncSessionState); } - private void MaybeSetUnavailableMessage(RpcModel rpcModel, CredentialModel credentialModel) + private void MaybeSetUnavailableMessage(RpcModel rpcModel, CredentialModel credentialModel, SyncSessionControllerStateModel syncSessionState) { var oldMessage = UnavailableMessage; if (rpcModel.RpcLifecycle != RpcLifecycle.Connected) @@ -205,6 +207,10 @@ private void MaybeSetUnavailableMessage(RpcModel rpcModel, CredentialModel crede { UnavailableMessage = "Please start Coder Connect from the tray window to access file sync."; } + else if (syncSessionState.Lifecycle == SyncSessionControllerLifecycle.Uninitialized) + { + UnavailableMessage = "Sync session controller is not initialized. Please wait..."; + } else { UnavailableMessage = null; @@ -219,6 +225,13 @@ private void MaybeSetUnavailableMessage(RpcModel rpcModel, CredentialModel crede private void UpdateSyncSessionState(SyncSessionControllerStateModel syncSessionState) { + // This should never happen. + if (syncSessionState == null) + return; + if (syncSessionState.Lifecycle == SyncSessionControllerLifecycle.Uninitialized) + { + MaybeSetUnavailableMessage(_rpcController.GetState(), _credentialManager.GetCachedCredentials(), syncSessionState); + } Error = syncSessionState.DaemonError; Sessions = syncSessionState.SyncSessions.Select(s => new SyncSessionViewModel(this, s)).ToList(); } diff --git a/App/ViewModels/TrayWindowDisconnectedViewModel.cs b/App/ViewModels/TrayWindowDisconnectedViewModel.cs index 5fe16a2..ce6582c 100644 --- a/App/ViewModels/TrayWindowDisconnectedViewModel.cs +++ b/App/ViewModels/TrayWindowDisconnectedViewModel.cs @@ -1,8 +1,9 @@ -using System.Threading.Tasks; using Coder.Desktop.App.Models; using Coder.Desktop.App.Services; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using System; +using System.Threading.Tasks; namespace Coder.Desktop.App.ViewModels; @@ -11,6 +12,8 @@ public partial class TrayWindowDisconnectedViewModel : ObservableObject private readonly IRpcController _rpcController; [ObservableProperty] public partial bool ReconnectButtonEnabled { get; set; } = true; + [ObservableProperty] public partial string ErrorMessage { get; set; } = string.Empty; + [ObservableProperty] public partial bool ReconnectFailed { get; set; } = false; public TrayWindowDisconnectedViewModel(IRpcController rpcController) { @@ -26,6 +29,16 @@ private void UpdateFromRpcModel(RpcModel rpcModel) [RelayCommand] public async Task Reconnect() { - await _rpcController.Reconnect(); + try + { + ReconnectFailed = false; + ErrorMessage = string.Empty; + await _rpcController.Reconnect(); + } + catch (Exception ex) + { + ErrorMessage = ex.Message; + ReconnectFailed = true; + } } } diff --git a/App/Views/Pages/TrayWindowDisconnectedPage.xaml b/App/Views/Pages/TrayWindowDisconnectedPage.xaml index 6675f8d..936c65f 100644 --- a/App/Views/Pages/TrayWindowDisconnectedPage.xaml +++ b/App/Views/Pages/TrayWindowDisconnectedPage.xaml @@ -30,6 +30,19 @@ + + + +