Skip to content

Commit 9e286ba

Browse files
Tom BrewerTom Brewer
authored andcommitted
feat: auto install functionality
feat: improved settings registration methods that work with DI
1 parent d71d4bd commit 9e286ba

File tree

4 files changed

+97
-3
lines changed

4 files changed

+97
-3
lines changed

Mythetech.Framework.Desktop/Updates/VelopackUpdateService.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ public async Task CheckForUpdatesAsync(CancellationToken cancellationToken = def
118118

119119
await _messageBus.PublishAsync(new UpdateCheckCompleted(updateInfo));
120120
await _messageBus.PublishAsync(new UpdateAvailable(updateInfo));
121+
122+
var settings = _settingsProvider?.GetSettings<UpdateSettings>();
123+
if (settings?.AutoDownload == true)
124+
{
125+
_logger.LogInformation("Auto-downloading update per settings");
126+
await DownloadUpdateAsync(cancellationToken);
127+
}
121128
}
122129
catch (Exception ex)
123130
{
@@ -163,7 +170,6 @@ public async Task DownloadUpdateAsync(CancellationToken cancellationToken = defa
163170

164171
await manager.DownloadUpdatesAsync(veloUpdate, progress =>
165172
{
166-
// Fire and forget progress updates - they're informational
167173
_ = _messageBus.PublishAsync(new UpdateDownloadProgress(AvailableUpdate, progress));
168174
});
169175

Mythetech.Framework.Test/Infrastructure/Settings/SettingsProviderTests.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Bunit;
22
using Microsoft.Extensions.DependencyInjection;
33
using Microsoft.Extensions.Logging;
4+
using Microsoft.Extensions.Options;
45
using Mythetech.Framework.Infrastructure.MessageBus;
56
using Mythetech.Framework.Infrastructure.Settings;
67
using Mythetech.Framework.Infrastructure.Settings.Events;
@@ -23,7 +24,12 @@ public SettingsProviderTests()
2324
Array.Empty<IConsumerFilter>());
2425
Services.AddSingleton(_bus);
2526

26-
_provider = new SettingsProvider(_bus, Substitute.For<ILogger<SettingsProvider>>());
27+
var options = Options.Create(new SettingsRegistrationOptions());
28+
_provider = new SettingsProvider(
29+
_bus,
30+
Substitute.For<ILogger<SettingsProvider>>(),
31+
Services.BuildServiceProvider(),
32+
options);
2733
}
2834

2935
[Fact(DisplayName = "Can register and retrieve settings by type")]

Mythetech.Framework/Infrastructure/Settings/SettingsProvider.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Reflection;
22
using System.Text.Json;
3+
using Microsoft.Extensions.DependencyInjection;
34
using Microsoft.Extensions.Logging;
5+
using Microsoft.Extensions.Options;
46
using Mythetech.Framework.Infrastructure.MessageBus;
57
using Mythetech.Framework.Infrastructure.Settings.Events;
68

@@ -21,10 +23,23 @@ public class SettingsProvider : ISettingsProvider
2123
/// </summary>
2224
/// <param name="bus">The message bus for publishing change events.</param>
2325
/// <param name="logger">Logger for diagnostics.</param>
24-
public SettingsProvider(IMessageBus bus, ILogger<SettingsProvider> logger)
26+
/// <param name="serviceProvider">Service provider for resolving settings instances.</param>
27+
/// <param name="options">Options containing discovered settings types.</param>
28+
public SettingsProvider(
29+
IMessageBus bus,
30+
ILogger<SettingsProvider> logger,
31+
IServiceProvider serviceProvider,
32+
IOptions<SettingsRegistrationOptions> options)
2533
{
2634
_bus = bus;
2735
_logger = logger;
36+
37+
// Auto-register settings that were discovered during service configuration
38+
foreach (var type in options.Value.DiscoveredSettingsTypes)
39+
{
40+
var instance = (SettingsBase)serviceProvider.GetRequiredService(type);
41+
RegisterSettings(instance);
42+
}
2843
}
2944

3045
/// <inheritdoc />

Mythetech.Framework/Infrastructure/Settings/SettingsRegistrationExtensions.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@
88

99
namespace Mythetech.Framework.Infrastructure.Settings;
1010

11+
/// <summary>
12+
/// Options for tracking settings types discovered during service configuration.
13+
/// </summary>
14+
public class SettingsRegistrationOptions
15+
{
16+
/// <summary>
17+
/// Types discovered via RegisterSettingsFromAssembly on IServiceCollection.
18+
/// </summary>
19+
public List<Type> DiscoveredSettingsTypes { get; } = new();
20+
}
21+
1122
/// <summary>
1223
/// Extension methods for registering settings framework services.
1324
/// </summary>
@@ -125,13 +136,66 @@ public static IServiceCollection AddSettingsStorage(this IServiceCollection serv
125136
return services;
126137
}
127138

139+
/// <summary>
140+
/// Scans an assembly for SettingsBase implementations, registers them as singletons,
141+
/// and configures the SettingsProvider to auto-discover them.
142+
/// This allows consumers to inject settings models directly.
143+
/// </summary>
144+
/// <param name="services">The service collection.</param>
145+
/// <param name="assembly">The assembly to scan for settings types.</param>
146+
/// <returns>The service collection for chaining.</returns>
147+
public static IServiceCollection RegisterSettingsFromAssembly(
148+
this IServiceCollection services,
149+
Assembly assembly)
150+
{
151+
var settingsTypes = assembly.GetTypes()
152+
.Where(t => !t.IsAbstract && typeof(SettingsBase).IsAssignableFrom(t))
153+
.Where(t => t.GetConstructor(Type.EmptyTypes) != null);
154+
155+
foreach (var type in settingsTypes)
156+
{
157+
services.AddSingleton(type);
158+
}
159+
160+
services.Configure<SettingsRegistrationOptions>(options =>
161+
{
162+
foreach (var type in settingsTypes)
163+
{
164+
if (!options.DiscoveredSettingsTypes.Contains(type))
165+
options.DiscoveredSettingsTypes.Add(type);
166+
}
167+
});
168+
169+
return services;
170+
}
171+
172+
/// <summary>
173+
/// Scans multiple assemblies for SettingsBase implementations, registers them as singletons,
174+
/// and configures the SettingsProvider to auto-discover them.
175+
/// This allows consumers to inject settings models directly.
176+
/// </summary>
177+
/// <param name="services">The service collection.</param>
178+
/// <param name="assemblies">The assemblies to scan for settings types.</param>
179+
/// <returns>The service collection for chaining.</returns>
180+
public static IServiceCollection RegisterSettingsFromAssemblies(
181+
this IServiceCollection services,
182+
params Assembly[] assemblies)
183+
{
184+
foreach (var assembly in assemblies)
185+
{
186+
services.RegisterSettingsFromAssembly(assembly);
187+
}
188+
return services;
189+
}
190+
128191
/// <summary>
129192
/// Registers a settings model with the provider.
130193
/// Call after building the service provider.
131194
/// </summary>
132195
/// <typeparam name="T">The settings type to register.</typeparam>
133196
/// <param name="serviceProvider">The built service provider.</param>
134197
/// <returns>The service provider for chaining.</returns>
198+
[Obsolete("Use IServiceCollection.RegisterSettingsFromAssembly() instead for DI-injectable settings.")]
135199
public static IServiceProvider RegisterSettings<T>(this IServiceProvider serviceProvider)
136200
where T : SettingsBase, new()
137201
{
@@ -147,6 +211,7 @@ public static IServiceProvider RegisterSettings<T>(this IServiceProvider service
147211
/// <param name="serviceProvider">The built service provider.</param>
148212
/// <param name="settings">The settings instance to register.</param>
149213
/// <returns>The service provider for chaining.</returns>
214+
[Obsolete("Use IServiceCollection.RegisterSettingsFromAssembly() instead for DI-injectable settings.")]
150215
public static IServiceProvider RegisterSettings(this IServiceProvider serviceProvider, SettingsBase settings)
151216
{
152217
var provider = serviceProvider.GetRequiredService<ISettingsProvider>();
@@ -161,6 +226,7 @@ public static IServiceProvider RegisterSettings(this IServiceProvider servicePro
161226
/// <param name="serviceProvider">The built service provider.</param>
162227
/// <param name="assembly">The assembly to scan for settings types.</param>
163228
/// <returns>The service provider for chaining.</returns>
229+
[Obsolete("Use IServiceCollection.RegisterSettingsFromAssembly() instead for DI-injectable settings.")]
164230
public static IServiceProvider RegisterSettingsFromAssembly(this IServiceProvider serviceProvider, Assembly assembly)
165231
{
166232
var provider = serviceProvider.GetRequiredService<ISettingsProvider>();
@@ -184,6 +250,7 @@ public static IServiceProvider RegisterSettingsFromAssembly(this IServiceProvide
184250
/// <param name="serviceProvider">The built service provider.</param>
185251
/// <param name="assemblies">The assemblies to scan for settings types.</param>
186252
/// <returns>The service provider for chaining.</returns>
253+
[Obsolete("Use IServiceCollection.RegisterSettingsFromAssemblies() instead for DI-injectable settings.")]
187254
public static IServiceProvider RegisterSettingsFromAssemblies(
188255
this IServiceProvider serviceProvider,
189256
params Assembly[] assemblies)

0 commit comments

Comments
 (0)