Skip to content

Commit 0e785ed

Browse files
committed
add support for building with custom MuninNodeBuilder types
1 parent 2d0cd1d commit 0e785ed

File tree

3 files changed

+150
-13
lines changed

3 files changed

+150
-13
lines changed

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode.DependencyInjection/IMuninServiceBuilderExtensions.cs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ public static IMuninNodeBuilder AddNode(
3838
this IMuninServiceBuilder builder,
3939
Action<MuninNodeOptions> configure
4040
)
41-
=> AddNode<MuninNodeOptions>(
41+
=> AddNode<
42+
MuninNodeOptions,
43+
MuninNodeBuilder
44+
>(
4245
builder: builder ?? throw new ArgumentNullException(nameof(builder)),
43-
configure: configure ?? throw new ArgumentNullException(nameof(configure))
46+
configure: configure ?? throw new ArgumentNullException(nameof(configure)),
47+
createBuilder: static (serviceBuilder, serviceKey) => new(serviceBuilder, serviceKey)
4448
);
4549

4650
/// <summary>
@@ -49,32 +53,52 @@ Action<MuninNodeOptions> configure
4953
/// <typeparam name="TMuninNodeOptions">
5054
/// The extended type of <see cref="MuninNodeOptions"/> to configure the <c>Munin-Node</c>.
5155
/// </typeparam>
56+
/// <typeparam name="TMuninNodeBuilder">
57+
/// The extended type of <see cref="MuninNodeBuilder"/> to build the <c>Munin-Node</c>.
58+
/// </typeparam>
5259
/// <param name="builder">
5360
/// An <see cref="IMuninServiceBuilder"/> that the built <c>Munin-Node</c> will be added to.
5461
/// </param>
5562
/// <param name="configure">
5663
/// An <see cref="Action{TMuninNodeOptions}"/> to setup <typeparamref name="TMuninNodeOptions"/> to
5764
/// configure the <c>Munin-Node</c> to be built.
5865
/// </param>
66+
/// <param name="createBuilder">
67+
/// An <see cref="Func{TMuninNodeBuilder}"/> to create <typeparamref name="TMuninNodeBuilder"/> to build
68+
/// the <c>Munin-Node</c>.
69+
/// </param>
5970
/// <returns>The current <see cref="IMuninNodeBuilder"/> so that additional calls can be chained.</returns>
60-
public static IMuninNodeBuilder AddNode<TMuninNodeOptions>(
71+
/// <exception cref="ArgumentNullException">
72+
/// <paramref name="builder"/> is <see langword="null"/>, or
73+
/// <paramref name="configure"/> is <see langword="null"/>, or
74+
/// <paramref name="createBuilder"/> is <see langword="null"/>.
75+
/// </exception>
76+
public static
77+
IMuninNodeBuilder AddNode<
78+
TMuninNodeOptions,
79+
TMuninNodeBuilder
80+
>(
6181
this IMuninServiceBuilder builder,
62-
Action<TMuninNodeOptions> configure
82+
Action<TMuninNodeOptions> configure,
83+
Func<IMuninServiceBuilder, string, TMuninNodeBuilder> createBuilder
6384
)
6485
where TMuninNodeOptions : MuninNodeOptions, new()
86+
where TMuninNodeBuilder : MuninNodeBuilder
6587
{
6688
if (builder is null)
6789
throw new ArgumentNullException(nameof(builder));
6890
if (configure is null)
6991
throw new ArgumentNullException(nameof(configure));
92+
if (createBuilder is null)
93+
throw new ArgumentNullException(nameof(createBuilder));
7094

7195
var configuredOptions = new TMuninNodeOptions();
7296

7397
configure(configuredOptions);
7498

75-
var nodeBuilder = new MuninNodeBuilder(
76-
serviceBuilder: builder,
77-
serviceKey: configuredOptions.HostName // use configured hostname as a service key and option name
99+
var nodeBuilder = createBuilder(
100+
/* serviceBuilder: */ builder,
101+
/* serviceKey: */ configuredOptions.HostName // use configured hostname as a service key and option name
78102
);
79103

80104
_ = builder.Services.Configure<TMuninNodeOptions>(

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode.DependencyInjection/MuninNodeBuilder.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class MuninNodeBuilder : IMuninNodeBuilder {
2323
public IServiceCollection Services { get; }
2424
public string ServiceKey { get; }
2525

26-
internal MuninNodeBuilder(IMuninServiceBuilder serviceBuilder, string serviceKey)
26+
protected internal MuninNodeBuilder(IMuninServiceBuilder serviceBuilder, string serviceKey)
2727
{
2828
Services = (serviceBuilder ?? throw new ArgumentNullException(nameof(serviceBuilder))).Services;
2929
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
@@ -72,16 +72,15 @@ public IMuninNode Build(IServiceProvider serviceProvider)
7272
if (serviceProvider is null)
7373
throw new ArgumentNullException(nameof(serviceProvider));
7474

75-
return new DefaultMuninNode(
76-
options: GetConfiguredOptions<MuninNodeOptions>(serviceProvider),
75+
return Build(
7776
pluginProvider: buildPluginProvider is null
7877
? new PluginProvider(
7978
plugins: pluginFactories.Select(factory => factory(serviceProvider)).ToList(),
8079
sessionCallback: buildSessionCallback?.Invoke(serviceProvider)
8180
)
8281
: buildPluginProvider.Invoke(serviceProvider),
8382
listenerFactory: buildListenerFactory?.Invoke(serviceProvider),
84-
logger: serviceProvider.GetService<ILoggerFactory>()?.CreateLogger<DefaultMuninNode>()
83+
serviceProvider: serviceProvider
8584
);
8685
}
8786

@@ -99,6 +98,23 @@ public PluginProvider(
9998
}
10099
}
101100

101+
protected virtual IMuninNode Build(
102+
IPluginProvider pluginProvider,
103+
IMuninNodeListenerFactory? listenerFactory,
104+
IServiceProvider serviceProvider
105+
)
106+
{
107+
if (serviceProvider is null)
108+
throw new ArgumentNullException(nameof(serviceProvider));
109+
110+
return new DefaultMuninNode(
111+
options: GetConfiguredOptions<MuninNodeOptions>(serviceProvider),
112+
pluginProvider: pluginProvider,
113+
listenerFactory: listenerFactory,
114+
logger: serviceProvider.GetService<ILoggerFactory>()?.CreateLogger<DefaultMuninNode>()
115+
);
116+
}
117+
102118
protected TMuninNodeOptions GetConfiguredOptions<TMuninNodeOptions>(IServiceProvider serviceProvider)
103119
where TMuninNodeOptions : MuninNodeOptions
104120
{

tests/Smdn.Net.MuninNode/Smdn.Net.MuninNode.DependencyInjection/IMuninServiceBuilderExtensions.cs

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
using NUnit.Framework;
1010

11+
using Smdn.Net.MuninNode.Transport;
12+
using Smdn.Net.MuninPlugin;
13+
1114
namespace Smdn.Net.MuninNode.DependencyInjection;
1215

1316
[TestFixture]
@@ -163,6 +166,91 @@ public void AddNode_Multiple_GetKeyedService(string hostName)
163166
Assert.That(node, Is.Not.SameAs(anotherNode));
164167
}
165168

169+
private class CustomMuninNodeBuilder<TMuninNodeOptions> : MuninNodeBuilder
170+
where TMuninNodeOptions : MuninNodeOptions
171+
{
172+
private readonly Func<TMuninNodeOptions, IPluginProvider, IMuninNodeListenerFactory?, IServiceProvider, IMuninNode> nodeFactory;
173+
174+
public CustomMuninNodeBuilder(
175+
IMuninServiceBuilder serviceBuilder,
176+
string serviceKey,
177+
Func<TMuninNodeOptions, IPluginProvider, IMuninNodeListenerFactory?, IServiceProvider, IMuninNode> nodeFactory
178+
)
179+
: base(serviceBuilder, serviceKey)
180+
{
181+
this.nodeFactory = nodeFactory;
182+
}
183+
184+
protected override IMuninNode Build(
185+
IPluginProvider pluginProvider,
186+
IMuninNodeListenerFactory? listenerFactory,
187+
IServiceProvider serviceProvider
188+
)
189+
=> nodeFactory(
190+
GetConfiguredOptions<TMuninNodeOptions>(serviceProvider),
191+
pluginProvider,
192+
listenerFactory,
193+
serviceProvider
194+
);
195+
}
196+
197+
private class CustomMuninNode : LocalNode {
198+
public MuninNodeOptions Options { get; }
199+
public override string HostName => Options.HostName;
200+
public override IPluginProvider PluginProvider { get; }
201+
202+
public CustomMuninNode(
203+
MuninNodeOptions options,
204+
IPluginProvider pluginProvider,
205+
IMuninNodeListenerFactory? listenerFactory
206+
)
207+
: base(
208+
listenerFactory: listenerFactory,
209+
accessRule: null,
210+
logger: null
211+
)
212+
{
213+
Options = options;
214+
PluginProvider = pluginProvider;
215+
}
216+
}
217+
218+
[Test]
219+
public void AddNode_CustomBuilderType()
220+
{
221+
const string HostName = "munin-node.localhost";
222+
var services = new ServiceCollection();
223+
224+
services.AddMunin(configure: builder => {
225+
builder.AddNode<MuninNodeOptions, CustomMuninNodeBuilder<MuninNodeOptions>>(
226+
configure: options => options.HostName = HostName,
227+
createBuilder: static (serviceBuilder, serviceKey) => new CustomMuninNodeBuilder<MuninNodeOptions>(
228+
serviceBuilder: serviceBuilder,
229+
serviceKey: serviceKey,
230+
nodeFactory: static (options, pluginProvider, listenerFactory, serviceProvider) => new CustomMuninNode(
231+
options,
232+
pluginProvider,
233+
listenerFactory
234+
)
235+
)
236+
);
237+
});
238+
239+
var serviceProvider = services.BuildServiceProvider();
240+
241+
var node = serviceProvider.GetService<IMuninNode>();
242+
243+
Assert.That(node, Is.Not.Null);
244+
Assert.That(node, Is.TypeOf<CustomMuninNode>());
245+
Assert.That(node.HostName, Is.EqualTo(HostName));
246+
247+
var keyedNode = serviceProvider.GetKeyedService<IMuninNode>(HostName);
248+
249+
Assert.That(keyedNode, Is.Not.Null);
250+
Assert.That(keyedNode, Is.TypeOf<CustomMuninNode>());
251+
Assert.That(keyedNode.HostName, Is.EqualTo(HostName));
252+
}
253+
166254
private class CustomMuninNodeOptions : MuninNodeOptions {
167255
public string? ExtraOption { get; set; }
168256

@@ -184,11 +272,20 @@ public void AddNode_CustomOptionsType()
184272
var services = new ServiceCollection();
185273

186274
services.AddMunin(configure: builder => {
187-
builder.AddNode<CustomMuninNodeOptions>(
275+
builder.AddNode<CustomMuninNodeOptions, CustomMuninNodeBuilder<CustomMuninNodeOptions>>(
188276
configure: options => {
189277
options.HostName = HostName;
190278
options.ExtraOption = ExtraOptionValue;
191-
}
279+
},
280+
createBuilder: static (serviceBuilder, serviceKey) => new CustomMuninNodeBuilder<CustomMuninNodeOptions>(
281+
serviceBuilder: serviceBuilder,
282+
serviceKey: serviceKey,
283+
nodeFactory: static (options, pluginProvider, listenerFactory, serviceProvider) => new CustomMuninNode(
284+
options,
285+
pluginProvider,
286+
listenerFactory
287+
)
288+
)
192289
);
193290
});
194291

0 commit comments

Comments
 (0)