Skip to content

Commit cd5cd23

Browse files
authored
Merge pull request #17 from smdn/add-di-apis
Add APIs to support dependency injection
2 parents 96e3be3 + b96210c commit cd5cd23

21 files changed

+2455
-23
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-FileCopyrightText: 2025 smdn <smdn@smdn.jp>
2+
// SPDX-License-Identifier: MIT
3+
4+
using System;
5+
using System.Net;
6+
7+
using Microsoft.Extensions.Logging;
8+
9+
using Smdn.Net.MuninNode.AccessRules;
10+
using Smdn.Net.MuninNode.Transport;
11+
using Smdn.Net.MuninPlugin;
12+
13+
namespace Smdn.Net.MuninNode.DependencyInjection;
14+
15+
/// <summary>
16+
/// Implement a <c>Munin-Node</c> that can be configured by IServiceProvider or other interfaces.
17+
/// </summary>
18+
internal sealed class DefaultMuninNode : NodeBase, IMuninNode {
19+
private readonly MuninNodeOptions options;
20+
21+
public override string HostName => options.HostName;
22+
public override IPluginProvider PluginProvider { get; }
23+
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="DefaultMuninNode"/> class.
26+
/// </summary>
27+
/// <param name="options">
28+
/// The <see cref="MuninNodeOptions"/> to configure the <c>Munin-Node</c>.
29+
/// </param>
30+
/// <param name="pluginProvider">
31+
/// The <see cref="IPluginProvider"/> to provide <c>Munin plugins</c> for this instance.
32+
/// </param>
33+
/// <param name="listenerFactory">
34+
/// The <see cref="IMuninNodeListenerFactory"/> to create a listener for this instance.
35+
/// If <see langword="null"/>, the default factory will be used.
36+
/// </param>
37+
/// <param name="logger">
38+
/// The <see cref="ILogger"/> to report the situation.
39+
/// </param>
40+
/// <remarks>
41+
/// If <see cref="MuninNodeOptions.AccessRule"/> is <see langword="null"/>, only allow access from the loopback address.
42+
/// </remarks>
43+
/// <exception cref="ArgumentNullException">
44+
/// <paramref name="options"/> is <see langword="null"/>, or
45+
/// <paramref name="pluginProvider"/> is <see langword="null"/>.
46+
/// </exception>
47+
public DefaultMuninNode(
48+
MuninNodeOptions options,
49+
IPluginProvider pluginProvider,
50+
IMuninNodeListenerFactory? listenerFactory,
51+
ILogger? logger
52+
)
53+
: base(
54+
listenerFactory: listenerFactory ?? MuninNodeListenerFactory.Instance,
55+
accessRule: (options ?? throw new ArgumentNullException(nameof(options))).AccessRule ?? LoopbackOnlyAccessRule.Instance,
56+
logger: logger
57+
)
58+
{
59+
this.options = options;
60+
PluginProvider = pluginProvider ?? throw new ArgumentNullException(nameof(pluginProvider));
61+
}
62+
63+
protected override EndPoint GetLocalEndPointToBind()
64+
=> new IPEndPoint(options.Address, options.Port);
65+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// SPDX-FileCopyrightText: 2025 smdn <smdn@smdn.jp>
2+
// SPDX-License-Identifier: MIT
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
8+
using Microsoft.Extensions.DependencyInjection;
9+
using Microsoft.Extensions.Logging;
10+
using Microsoft.Extensions.Options;
11+
12+
using Smdn.Net.MuninNode.Transport;
13+
using Smdn.Net.MuninPlugin;
14+
15+
namespace Smdn.Net.MuninNode.DependencyInjection;
16+
17+
internal sealed class DefaultMuninNodeBuilder : IMuninNodeBuilder {
18+
private readonly List<Func<IServiceProvider, IPlugin>> pluginFactories = new(capacity: 4);
19+
private Func<IServiceProvider, IPluginProvider>? buildPluginProvider;
20+
private Func<IServiceProvider, INodeSessionCallback>? buildSessionCallback;
21+
private Func<IServiceProvider, IMuninNodeListenerFactory>? buildListenerFactory;
22+
23+
public IServiceCollection Services { get; }
24+
public string ServiceKey { get; }
25+
26+
public DefaultMuninNodeBuilder(IMuninServiceBuilder serviceBuilder, string serviceKey)
27+
{
28+
Services = (serviceBuilder ?? throw new ArgumentNullException(nameof(serviceBuilder))).Services;
29+
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
30+
}
31+
32+
public void AddPluginFactory(Func<IServiceProvider, IPlugin> buildPlugin)
33+
{
34+
if (buildPlugin is null)
35+
throw new ArgumentNullException(nameof(buildPlugin));
36+
37+
pluginFactories.Add(serviceProvider => buildPlugin(serviceProvider));
38+
}
39+
40+
public void SetPluginProviderFactory(
41+
Func<IServiceProvider, IPluginProvider> buildPluginProvider
42+
)
43+
{
44+
if (buildPluginProvider is null)
45+
throw new ArgumentNullException(nameof(buildPluginProvider));
46+
47+
this.buildPluginProvider = buildPluginProvider;
48+
}
49+
50+
public void SetSessionCallbackFactory(
51+
Func<IServiceProvider, INodeSessionCallback> buildSessionCallback
52+
)
53+
{
54+
if (buildSessionCallback is null)
55+
throw new ArgumentNullException(nameof(buildSessionCallback));
56+
57+
this.buildSessionCallback = buildSessionCallback;
58+
}
59+
60+
public void SetListenerFactory(
61+
Func<IServiceProvider, IMuninNodeListenerFactory> buildListenerFactory
62+
)
63+
{
64+
if (buildListenerFactory is null)
65+
throw new ArgumentNullException(nameof(buildListenerFactory));
66+
67+
this.buildListenerFactory = buildListenerFactory;
68+
}
69+
70+
public IMuninNode Build(IServiceProvider serviceProvider)
71+
{
72+
if (serviceProvider is null)
73+
throw new ArgumentNullException(nameof(serviceProvider));
74+
75+
return new DefaultMuninNode(
76+
options: serviceProvider.GetRequiredService<IOptionsMonitor<MuninNodeOptions>>().Get(name: ServiceKey),
77+
pluginProvider: buildPluginProvider is null
78+
? new PluginProvider(
79+
plugins: pluginFactories.Select(factory => factory(serviceProvider)).ToList(),
80+
sessionCallback: buildSessionCallback?.Invoke(serviceProvider)
81+
)
82+
: buildPluginProvider.Invoke(serviceProvider),
83+
listenerFactory: buildListenerFactory?.Invoke(serviceProvider),
84+
logger: serviceProvider.GetService<ILoggerFactory>()?.CreateLogger<DefaultMuninNode>()
85+
);
86+
}
87+
88+
private sealed class PluginProvider : IPluginProvider {
89+
public IReadOnlyCollection<IPlugin> Plugins { get; }
90+
public INodeSessionCallback? SessionCallback { get; }
91+
92+
public PluginProvider(
93+
IReadOnlyCollection<IPlugin> plugins,
94+
INodeSessionCallback? sessionCallback
95+
)
96+
{
97+
Plugins = plugins ?? throw new ArgumentNullException(nameof(plugins));
98+
SessionCallback = sessionCallback;
99+
}
100+
}
101+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-FileCopyrightText: 2025 smdn <smdn@smdn.jp>
2+
// SPDX-License-Identifier: MIT
3+
#pragma warning disable CS0419
4+
5+
using System;
6+
7+
using Microsoft.Extensions.DependencyInjection;
8+
9+
namespace Smdn.Net.MuninNode.DependencyInjection;
10+
11+
/// <summary>
12+
/// An interface for configuring the <c>Munin-Node</c> service providers.
13+
/// </summary>
14+
/// <see cref="IMuninNodeBuilderExtensions.AddPlugin"/>
15+
/// <see cref="IMuninNodeBuilderExtensions.UseListenerFactory"/>
16+
/// <see cref="IMuninNodeBuilderExtensions.UseSessionCallback"/>
17+
public interface IMuninNodeBuilder {
18+
/// <summary>
19+
/// Gets the <see cref="IServiceCollection"/> where the <c>Munin-Node</c> services are configured.
20+
/// </summary>
21+
IServiceCollection Services { get; }
22+
23+
/// <summary>
24+
/// Gets the <see cref="string"/> key of <c>Munin-Node</c> service.
25+
/// </summary>
26+
/// <remarks>
27+
/// The value set as the hostname of the <c>Munin-Node</c> (see <see cref="MuninNodeOptions.HostName"/>) is used as the service key.
28+
/// </remarks>
29+
/// <see cref="IMuninServiceBuilderExtensions.AddNode(IMuninServiceBuilder, Action{MuninNodeOptions})"/>
30+
string ServiceKey { get; }
31+
32+
/// <summary>
33+
/// Builds the <c>Munin-Node</c> with current configurations.
34+
/// </summary>
35+
/// <param name="serviceProvider">
36+
/// An <see cref="IServiceProvider"/> that provides the services to be used by the <see cref="IMuninNode"/> being built.
37+
/// </param>
38+
/// <returns>An initialized <see cref="IMuninNode"/>.</returns>
39+
IMuninNode Build(IServiceProvider serviceProvider);
40+
}

0 commit comments

Comments
 (0)