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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy