Skip to content

Commit bad5320

Browse files
committed
async handling of dependency load in app
1 parent c21072f commit bad5320

File tree

1 file changed

+54
-49
lines changed

1 file changed

+54
-49
lines changed

App/App.xaml.cs

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public partial class App : Application
4646

4747
private readonly ISettingsManager _settingsManager;
4848

49+
private readonly IHostApplicationLifetime _appLifetime;
50+
4951
public App()
5052
{
5153
var builder = Host.CreateApplicationBuilder();
@@ -119,6 +121,7 @@ public App()
119121
_logger = (ILogger<App>)_services.GetService(typeof(ILogger<App>))!;
120122
_uriHandler = (IUriHandler)_services.GetService(typeof(IUriHandler))!;
121123
_settingsManager = (ISettingsManager)_services.GetService(typeof(ISettingsManager))!;
124+
_appLifetime = (IHostApplicationLifetime)_services.GetRequiredService<IHostApplicationLifetime>();
122125

123126
InitializeComponent();
124127
}
@@ -140,71 +143,73 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
140143
{
141144
_logger.LogInformation("new instance launched");
142145

143-
// Load the credentials in the background.
144-
var credentialManagerCts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
146+
_ = InitializeServicesAsync(_appLifetime.ApplicationStopping);
147+
148+
// Prevent the TrayWindow from closing, just hide it.
149+
var trayWindow = _services.GetRequiredService<TrayWindow>();
150+
trayWindow.Closed += (_, closedArgs) =>
151+
{
152+
if (!_handleWindowClosed) return;
153+
closedArgs.Handled = true;
154+
trayWindow.AppWindow.Hide();
155+
};
156+
}
157+
158+
/// <summary>
159+
/// Loads stored VPN credentials, reconnects the RPC controller,
160+
/// and (optionally) starts the VPN tunnel on application launch.
161+
/// </summary>
162+
private async Task InitializeServicesAsync(CancellationToken cancellationToken = default)
163+
{
145164
var credentialManager = _services.GetRequiredService<ICredentialManager>();
146-
credentialManager.LoadCredentials(credentialManagerCts.Token).ContinueWith(t =>
165+
var rpcController = _services.GetRequiredService<IRpcController>();
166+
167+
using var credsCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
168+
credsCts.CancelAfter(TimeSpan.FromSeconds(15));
169+
170+
Task loadCredsTask = credentialManager.LoadCredentials(credsCts.Token);
171+
Task reconnectTask = rpcController.Reconnect(cancellationToken);
172+
173+
try
147174
{
148-
if (t.Exception != null)
149-
{
150-
_logger.LogError(t.Exception, "failed to load credentials");
151-
#if DEBUG
152-
Debug.WriteLine(t.Exception);
153-
Debugger.Break();
154-
#endif
155-
}
175+
await Task.WhenAll(loadCredsTask, reconnectTask);
176+
}
177+
catch (Exception)
178+
{
179+
if (loadCredsTask.IsFaulted)
180+
_logger.LogError(loadCredsTask.Exception!.GetBaseException(),
181+
"Failed to load credentials");
156182

157-
credentialManagerCts.Dispose();
158-
});
183+
if (reconnectTask.IsFaulted)
184+
_logger.LogError(reconnectTask.Exception!.GetBaseException(),
185+
"Failed to connect to VPN service");
159186

187+
return;
188+
}
160189

161-
// Start connecting to the manager in the background.
162-
var rpcController = _services.GetRequiredService<IRpcController>();
163-
_ = rpcController.Reconnect(CancellationToken.None).ContinueWith(t =>
190+
if (_settingsManager.ConnectOnLaunch)
164191
{
165-
if (t.Exception != null)
192+
try
166193
{
167-
_logger.LogError(t.Exception, "failed to connect to VPN service");
168-
#if DEBUG
169-
Debug.WriteLine(t.Exception);
170-
Debugger.Break();
171-
#endif
172-
return;
194+
await rpcController.StartVpn(cancellationToken);
173195
}
174-
if (_settingsManager.ConnectOnLaunch)
196+
catch (Exception ex)
175197
{
176-
_logger.LogInformation("RPC lifecycle is disconnected, but ConnectOnLaunch is enabled; attempting to connect");
177-
_ = rpcController.StartVpn(CancellationToken.None).ContinueWith(connectTask =>
178-
{
179-
if (connectTask.Exception != null)
180-
{
181-
_logger.LogError(connectTask.Exception, "failed to connect on launch");
182-
}
183-
});
198+
_logger.LogError(ex, "Failed to connect on launch");
184199
}
185-
});
200+
}
186201

187202
// Initialize file sync.
188203
var syncSessionCts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
189204
var syncSessionController = _services.GetRequiredService<ISyncSessionController>();
190-
_ = syncSessionController.RefreshState(syncSessionCts.Token).ContinueWith(t =>
205+
try
191206
{
192-
if (t.IsCanceled || t.Exception != null)
193-
{
194-
_logger.LogError(t.Exception, "failed to refresh sync state (canceled = {canceled})", t.IsCanceled);
195-
}
196-
197-
syncSessionCts.Dispose();
198-
}, CancellationToken.None);
199-
200-
// Prevent the TrayWindow from closing, just hide it.
201-
var trayWindow = _services.GetRequiredService<TrayWindow>();
202-
trayWindow.Closed += (_, closedArgs) =>
207+
await syncSessionController.RefreshState(syncSessionCts.Token);
208+
}
209+
catch(Exception ex)
203210
{
204-
if (!_handleWindowClosed) return;
205-
closedArgs.Handled = true;
206-
trayWindow.AppWindow.Hide();
207-
};
211+
_logger.LogError($"Failed to refresh sync session state {ex.Message}", ex);
212+
}
208213
}
209214

210215
public void OnActivated(object? sender, AppActivationArguments args)

0 commit comments

Comments
 (0)