Skip to content

Commit 501aca1

Browse files
committed
make LocalNode abstract
1 parent d769413 commit 501aca1

File tree

5 files changed

+224
-210
lines changed

5 files changed

+224
-210
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// SPDX-FileCopyrightText: 2024 smdn <smdn@smdn.jp>
2+
// SPDX-License-Identifier: MIT
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Net;
6+
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.Logging;
9+
10+
using Smdn.Net.MuninPlugin;
11+
12+
namespace Smdn.Net.MuninNode;
13+
14+
#pragma warning disable IDE0040
15+
partial class LocalNode {
16+
#pragma warning restore IDE0040
17+
private class ReadOnlyCollectionPluginProvider : IPluginProvider {
18+
public IReadOnlyCollection<IPlugin> Plugins { get; }
19+
public INodeSessionCallback? SessionCallback => null;
20+
21+
public ReadOnlyCollectionPluginProvider(IReadOnlyCollection<IPlugin> plugins)
22+
{
23+
Plugins = plugins;
24+
}
25+
}
26+
27+
private sealed class ConcreteLocalNode : LocalNode {
28+
public override IPluginProvider PluginProvider { get; }
29+
public override string HostName { get; }
30+
31+
private readonly int port;
32+
33+
public ConcreteLocalNode(
34+
IPluginProvider pluginProvider,
35+
string hostName,
36+
int port,
37+
IServiceProvider? serviceProvider = null
38+
)
39+
: base(
40+
logger: serviceProvider?.GetService<ILoggerFactory>()?.CreateLogger<LocalNode>()
41+
)
42+
{
43+
PluginProvider = pluginProvider;
44+
HostName = hostName;
45+
this.port = port;
46+
}
47+
48+
protected override EndPoint GetLocalEndPointToBind()
49+
=> new IPEndPoint(
50+
address: ((IPEndPoint)base.GetLocalEndPointToBind()).Address,
51+
port: port
52+
);
53+
}
54+
55+
/// <summary>
56+
/// Creates a new instance of the <see cref="LocalNode"/> class.
57+
/// </summary>
58+
/// <param name="plugins">
59+
/// The readolny collection of <see cref="IPlugin"/>s provided by this node.
60+
/// </param>
61+
/// <param name="port">
62+
/// The port number on which this node accepts connections.
63+
/// </param>
64+
/// <param name="hostName">
65+
/// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
66+
/// If <see langword="null"/> or empty, the default hostname is used.
67+
/// </param>
68+
/// <param name="serviceProvider">
69+
/// The <see cref="IServiceProvider"/>.
70+
/// This constructor overload attempts to get a service of <see cref="ILoggerFactory"/>, to create an <see cref="ILogger"/>.
71+
/// </param>
72+
/// <remarks>
73+
/// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
74+
/// </remarks>
75+
public static LocalNode Create(
76+
IReadOnlyCollection<IPlugin> plugins,
77+
int port,
78+
string? hostName = null,
79+
IServiceProvider? serviceProvider = null
80+
)
81+
=> Create(
82+
pluginProvider: new ReadOnlyCollectionPluginProvider(plugins ?? throw new ArgumentNullException(nameof(plugins))),
83+
hostName: string.IsNullOrEmpty(hostName) ? DefaultHostName : hostName,
84+
port: port,
85+
serviceProvider: serviceProvider
86+
);
87+
88+
/// <summary>
89+
/// Creates a new instance of the <see cref="LocalNode"/> class.
90+
/// </summary>
91+
/// <param name="pluginProvider">
92+
/// The <see cref="IPluginProvider"/> that provides <see cref="IPlugin"/>s for this node.
93+
/// </param>
94+
/// <param name="port">
95+
/// The port number on which this node accepts connections.
96+
/// </param>
97+
/// <param name="hostName">
98+
/// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
99+
/// If <see langword="null"/> or empty, the default hostname is used.
100+
/// </param>
101+
/// <param name="serviceProvider">
102+
/// The <see cref="IServiceProvider"/>.
103+
/// This constructor overload attempts to get a service of <see cref="ILoggerFactory"/>, to create an <see cref="ILogger"/>.
104+
/// </param>
105+
/// <remarks>
106+
/// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
107+
/// </remarks>
108+
public static LocalNode Create(
109+
IPluginProvider pluginProvider,
110+
int port,
111+
string? hostName = null,
112+
IServiceProvider? serviceProvider = null
113+
)
114+
=> new ConcreteLocalNode(
115+
pluginProvider: pluginProvider ?? throw new ArgumentNullException(nameof(pluginProvider)),
116+
hostName: string.IsNullOrEmpty(hostName) ? DefaultHostName : hostName,
117+
port: port,
118+
serviceProvider: serviceProvider
119+
);
120+
}

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/LocalNode.cs

Lines changed: 24 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,174 +1,61 @@
11
// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
22
// SPDX-License-Identifier: MIT
33
using System;
4-
using System.Collections.Generic;
54
using System.Net;
65
using System.Net.Sockets;
76

8-
using Microsoft.Extensions.DependencyInjection;
97
using Microsoft.Extensions.Logging;
108

11-
using Smdn.Net.MuninPlugin;
12-
139
namespace Smdn.Net.MuninNode;
1410

1511
/// <summary>
1612
/// Implement a <c>Munin-Node</c> that acts as a node on the localhost and only accepts connections from the local loopback address (127.0.0.1, ::1).
1713
/// </summary>
18-
public class LocalNode : NodeBase {
14+
public abstract partial class LocalNode : NodeBase {
1915
private const string DefaultHostName = "munin-node.localhost";
20-
private static readonly int MaxClients = 1;
21-
22-
public override string HostName { get; }
23-
public IPEndPoint LocalEndPoint { get; }
24-
25-
/// <inheritdoc cref="LocalNode(IReadOnlyCollection{IPlugin}, string, int, IServiceProvider)"/>
26-
public LocalNode(
27-
IReadOnlyCollection<IPlugin> plugins,
28-
int port,
29-
IServiceProvider? serviceProvider = null
30-
)
31-
: this(
32-
plugins: plugins,
33-
hostName: DefaultHostName,
34-
port: port,
35-
serviceProvider: serviceProvider
36-
)
37-
{
38-
}
39-
40-
/// <summary>
41-
/// Initializes a new instance of the <see cref="LocalNode"/> class.
42-
/// </summary>
43-
/// <param name="plugins">
44-
/// The collection of plugins provided by this node.
45-
/// </param>
46-
/// <param name="hostName">
47-
/// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
48-
/// </param>
49-
/// <param name="port">
50-
/// The port number on which this node accepts connections.
51-
/// </param>
52-
/// <param name="serviceProvider">
53-
/// The <see cref="IServiceProvider"/>.
54-
/// This constructor overload attempts to get a service of <see cref="ILoggerFactory"/>, to create an <see cref="ILogger"/>.
55-
/// </param>
56-
/// <remarks>
57-
/// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
58-
/// </remarks>
59-
public LocalNode(
60-
IReadOnlyCollection<IPlugin> plugins,
61-
string hostName,
62-
int port,
63-
IServiceProvider? serviceProvider = null
64-
)
65-
: this(
66-
pluginProvider: new PluginProvider(plugins ?? throw new ArgumentNullException(nameof(plugins))),
67-
hostName: hostName,
68-
port: port,
69-
serviceProvider: serviceProvider
70-
)
71-
{
72-
}
7316

7417
/// <summary>
7518
/// Initializes a new instance of the <see cref="LocalNode"/> class.
7619
/// </summary>
77-
/// <param name="pluginProvider">
78-
/// The <see cref="IPluginProvider"/> that provides <see cref="IPlugin"/>s for this node.
79-
/// </param>
80-
/// <param name="hostName">
81-
/// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
82-
/// </param>
83-
/// <param name="port">
84-
/// The port number on which this node accepts connections.
85-
/// </param>
86-
/// <param name="serviceProvider">
87-
/// The <see cref="IServiceProvider"/>.
88-
/// This constructor overload attempts to get a service of <see cref="ILoggerFactory"/>, to create an <see cref="ILogger"/>.
89-
/// </param>
90-
/// <remarks>
91-
/// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
92-
/// </remarks>
93-
public LocalNode(
94-
IPluginProvider pluginProvider,
95-
string hostName,
96-
int port,
97-
IServiceProvider? serviceProvider = null
98-
)
99-
: this(
100-
pluginProvider: pluginProvider ?? throw new ArgumentNullException(nameof(pluginProvider)),
101-
hostName: hostName,
102-
port: port,
103-
logger: serviceProvider?.GetService<ILoggerFactory>()?.CreateLogger<LocalNode>()
104-
)
105-
{
106-
}
107-
108-
/// <summary>
109-
/// Initializes a new instance of the <see cref="LocalNode"/> class.
110-
/// </summary>
111-
/// <param name="pluginProvider">
112-
/// The <see cref="IPluginProvider"/> that provides <see cref="IPlugin"/>s for this node.
113-
/// </param>
114-
/// <param name="hostName">
115-
/// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
116-
/// </param>
117-
/// <param name="port">
118-
/// The port number on which this node accepts connections.
119-
/// </param>
12020
/// <param name="logger">
12121
/// The <see cref="ILogger"/> to report the situation.
12222
/// </param>
123-
/// <remarks>
124-
/// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
125-
/// </remarks>
126-
public LocalNode(
127-
IPluginProvider pluginProvider,
128-
string hostName,
129-
int port,
23+
protected LocalNode(
13024
ILogger? logger = null
13125
)
13226
: base(
133-
pluginProvider: pluginProvider,
13427
logger: logger
13528
)
13629
{
137-
if (hostName == null)
138-
throw new ArgumentNullException(nameof(hostName));
139-
if (hostName.Length == 0)
140-
throw ExceptionUtils.CreateArgumentMustBeNonEmptyString(nameof(hostName));
141-
142-
HostName = hostName;
143-
144-
if (Socket.OSSupportsIPv6) {
145-
LocalEndPoint = new IPEndPoint(
146-
address: IPAddress.IPv6Loopback,
147-
port: port
148-
);
149-
}
150-
#pragma warning disable IDE0045
151-
else if (Socket.OSSupportsIPv4) {
152-
#pragma warning restore IDE0045
153-
LocalEndPoint = new IPEndPoint(
154-
address: IPAddress.Loopback,
155-
port: port
156-
);
157-
}
158-
else {
159-
throw new NotSupportedException();
160-
}
16130
}
16231

32+
/// <summary>
33+
/// Gets the <see cref="EndPoint"/> to be bound as the <c>Munin-Node</c>'s endpoint.
34+
/// </summary>
35+
/// <returns>
36+
/// An <see cref="EndPoint"/>.
37+
/// The default implementation returns an <see cref="IPEndPoint"/> with the port number <c>0</c>
38+
/// and <see cref="IPAddress.IPv6Loopback"/>/<see cref="IPAddress.Loopback"/>.
39+
/// </returns>
40+
protected virtual EndPoint GetLocalEndPointToBind()
41+
=> new IPEndPoint(
42+
address:
43+
Socket.OSSupportsIPv6
44+
? IPAddress.IPv6Loopback
45+
: Socket.OSSupportsIPv4
46+
? IPAddress.Loopback
47+
: throw new NotSupportedException(),
48+
port: 0
49+
);
50+
16351
protected override Socket CreateServerSocket()
16452
{
53+
const int MaxClients = 1;
54+
16555
Socket? server = null;
16656

16757
try {
168-
var endPoint = new IPEndPoint(
169-
address: Socket.OSSupportsIPv6 ? IPAddress.IPv6Any : IPAddress.Any,
170-
port: LocalEndPoint.Port
171-
);
58+
var endPoint = GetLocalEndPointToBind();
17259

17360
server = new Socket(
17461
endPoint.AddressFamily,
@@ -186,9 +73,7 @@ protected override Socket CreateServerSocket()
18673
return server;
18774
}
18875
catch {
189-
#pragma warning disable CA1508
19076
server?.Dispose();
191-
#pragma warning restore CA1508
19277
throw;
19378
}
19479
}

0 commit comments

Comments
 (0)