Skip to content

Commit 77100c0

Browse files
committed
feat: extensions now use idiomatic C# config system
1 parent d3c8e50 commit 77100c0

17 files changed

Lines changed: 623 additions & 681 deletions

File tree

src/extensions/Flowthru.Extensions.Http/Data/Storage/HttpStorageMediumProvider.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Flowthru.Core.Data.Storage.Medium;
22
using Flowthru.Extensions.Http;
3+
using Microsoft.Extensions.Options;
34

45
namespace Flowthru.Core.Data.Storage;
56

@@ -23,20 +24,21 @@ public sealed class HttpStorageMediumProvider : IStorageMediumProvider
2324
private readonly HttpCacheOptions? _cache;
2425

2526
/// <summary>
26-
/// Creates a new HTTP provider using the supplied client and optional cache options.
27+
/// Creates a new HTTP provider using options resolved from DI.
2728
/// </summary>
28-
public HttpStorageMediumProvider(HttpClient httpClient, HttpCacheOptions? cache = null)
29+
public HttpStorageMediumProvider(IOptions<HttpOptions> options)
2930
{
30-
_httpClient = httpClient;
31-
_cache = cache;
31+
var opts = options.Value;
32+
_httpClient = opts.CreateClient();
33+
_cache = opts.Cache;
3234
}
3335

3436
/// <summary>
3537
/// Creates a new HTTP provider with a default <see cref="HttpClient"/> and no caching.
3638
/// Use this for direct construction outside the DI container.
3739
/// </summary>
3840
public HttpStorageMediumProvider()
39-
: this(new HttpClient()) { }
41+
: this(Microsoft.Extensions.Options.Options.Create(new HttpOptions())) { }
4042

4143
/// <inheritdoc/>
4244
public bool CanHandle(Uri uri) =>

src/extensions/Flowthru.Extensions.Http/Services/FlowthruServiceBuilderHttpExtensions.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
using Flowthru.Core.Data.Storage;
22
using Flowthru.Core.Services;
33
using Flowthru.Extensions.Http;
4+
using Microsoft.Extensions.Configuration;
45
using Microsoft.Extensions.DependencyInjection;
56

67
namespace Flowthru.Extensions.Http.Services;
78

89
/// <summary>
9-
/// Extension methods for registering HTTP storage support with <see cref="FlowthruServiceBuilder"/>.
10+
/// Extension methods for registering HTTP storage support with <see cref="IFlowthruBuilder"/>.
1011
/// </summary>
1112
public static class FlowthruServiceBuilderHttpExtensions
1213
{
@@ -25,9 +26,13 @@ public static class FlowthruServiceBuilderHttpExtensions
2526
/// <see cref="Flowthru.Core.Data.Storage.Medium.HttpStorageMedium"/>.
2627
/// </para>
2728
/// <para>
29+
/// Configuration is bound from the <c>Flowthru:Http</c> section. Properties not
30+
/// present in configuration retain their default values.
31+
/// </para>
32+
/// <para>
2833
/// <strong>Example:</strong>
2934
/// <code>
30-
/// services.AddFlowthru(flowthru =>
35+
/// services.AddFlowthru(configuration, flowthru =>
3136
/// {
3237
/// flowthru.UseHttp();
3338
/// flowthru.RegisterCatalog(sp => new MyCatalog(
@@ -42,20 +47,33 @@ public static class FlowthruServiceBuilderHttpExtensions
4247
/// to <see cref="Flowthru.Core.Data.Storage.Medium.FileStorageMedium"/>.
4348
/// </para>
4449
/// </remarks>
45-
public static IFlowthruBuilder UseHttp(this IFlowthruBuilder builder) =>
46-
builder.UseHttp(_ => { });
50+
public static IFlowthruBuilder UseHttp(this IFlowthruBuilder builder)
51+
{
52+
builder
53+
.Services.AddOptions<HttpOptions>()
54+
.Configure<IConfiguration>((opts, cfg) => cfg.GetSection("Flowthru:Http").Bind(opts))
55+
.ValidateOnStart();
56+
57+
builder.Services.AddSingleton<IStorageMediumProvider, HttpStorageMediumProvider>();
58+
59+
return builder;
60+
}
4761

4862
/// <summary>
49-
/// Enables HTTP(S) remote file access with custom configuration.
63+
/// Enables HTTP(S) remote file access with code-first configuration overrides.
5064
/// </summary>
5165
/// <param name="builder">The Flowthru service builder.</param>
52-
/// <param name="configure">Action to configure HTTP options (timeout, user-agent, etc.).</param>
66+
/// <param name="configure">Action to override HTTP options after config-file binding.</param>
5367
/// <returns>The builder for method chaining.</returns>
5468
/// <remarks>
5569
/// <para>
70+
/// The <paramref name="configure"/> callback runs after <c>Flowthru:Http</c> section
71+
/// binding, so it can selectively override specific values.
72+
/// </para>
73+
/// <para>
5674
/// <strong>Example (custom timeout for large remote files):</strong>
5775
/// <code>
58-
/// services.AddFlowthru(flowthru =>
76+
/// services.AddFlowthru(configuration, flowthru =>
5977
/// {
6078
/// flowthru.UseHttp(http =>
6179
/// {
@@ -71,17 +89,8 @@ public static IFlowthruBuilder UseHttp(
7189
Action<HttpOptions> configure
7290
)
7391
{
74-
var options = new HttpOptions();
75-
configure(options);
76-
77-
builder.ConfigureServices(services =>
78-
{
79-
services.AddSingleton<IStorageMediumProvider>(_ => new HttpStorageMediumProvider(
80-
options.CreateClient(),
81-
options.Cache
82-
));
83-
});
84-
92+
builder.UseHttp();
93+
builder.Services.PostConfigure(configure);
8594
return builder;
8695
}
8796
}

src/extensions/Flowthru.Extensions.Python/Execution/SubprocessPythonExecutor.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Flowthru.Extensions.Python.Marshalling;
77
using Flowthru.Extensions.Python.Runtime;
88
using Microsoft.Extensions.Logging;
9+
using Microsoft.Extensions.Options;
910

1011
namespace Flowthru.Extensions.Python.Execution;
1112

@@ -48,11 +49,11 @@ public sealed class SubprocessPythonExecutor : IPythonExecutor, IDisposable
4849
/// <param name="logger">The logger instance.</param>
4950
/// <exception cref="ArgumentNullException"></exception>
5051
public SubprocessPythonExecutor(
51-
PythonRuntimeOptions options,
52+
IOptions<PythonRuntimeOptions> options,
5253
ILogger<SubprocessPythonExecutor> logger
5354
)
5455
{
55-
_options = options ?? throw new ArgumentNullException(nameof(options));
56+
_options = options?.Value ?? throw new ArgumentNullException(nameof(options));
5657
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
5758
}
5859

@@ -146,7 +147,7 @@ private void EnsureStarted()
146147

147148
private void StartWorker()
148149
{
149-
var pyExe = _options.GetResolvedPythonExe();
150+
var pyExe = PythonEnvironmentResolver.ResolvePythonExe(_options);
150151
var workerScript = Path.Combine(AppContext.BaseDirectory, "flowthru_worker.py");
151152

152153
if (!File.Exists(workerScript))
@@ -180,8 +181,8 @@ private void StartWorker()
180181

181182
// Build init message: sys.path includes configured search paths + the base directory
182183
// (so flowthru_worker.py can import _flowthru_arrow from the same directory)
183-
var sysPaths = _options
184-
.GetResolvedModuleSearchPaths()
184+
var sysPaths = PythonEnvironmentResolver
185+
.ResolveModuleSearchPaths(_options)
185186
.Concat(new[] { AppContext.BaseDirectory })
186187
.Distinct()
187188
.Select(p => (JsonNode?)JsonValue.Create(p))

src/extensions/Flowthru.Extensions.Python/Flowthru.Extensions.Python.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
<PackageTags>data-engineering;pipeline;python;pythonnet</PackageTags>
1313
</PropertyGroup>
1414

15+
<ItemGroup>
16+
<!-- Expose internal test helpers to the Python test project -->
17+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
18+
<_Parameter1>Flowthru.Extensions.Python.Tests</_Parameter1>
19+
</AssemblyAttribute>
20+
</ItemGroup>
21+
1522
<ItemGroup>
1623
<!-- Core Flowthru library -->
1724
<ProjectReference Include="../../core/Flowthru.Core/Flowthru.Core.csproj" />

0 commit comments

Comments
 (0)