Smdn.Net.MuninNode version 1.2.0
·
59 commits
to main
since this release
Released package
Release notes
The full release notes are available at gist.
Change log
Change log in this release:
- 2023-07-27 update assembly version
- 2023-07-27 revert deleting ctor overload and mark as obsolete
- 2023-07-27 make PluginGraphAttributes.UpdateRate optional
- 2023-07-24 add PluginGraphAttributes.Order to configure 'graph_order' attribute
- 2023-07-24 add overload of PluginFactory.CreateField
- 2023-07-24 introduce IPluginProvider and mark NodeBase.Plugins as obsolete
- 2023-07-24 expose NodeBase.Logger
API changes
API changes in this release:
diff --git a/doc/api-list/Smdn.Net.MuninNode/Smdn.Net.MuninNode-net6.0.apilist.cs b/doc/api-list/Smdn.Net.MuninNode/Smdn.Net.MuninNode-net6.0.apilist.cs
index 421f9f1..4bf85bf 100644
--- a/doc/api-list/Smdn.Net.MuninNode/Smdn.Net.MuninNode-net6.0.apilist.cs
+++ b/doc/api-list/Smdn.Net.MuninNode/Smdn.Net.MuninNode-net6.0.apilist.cs
@@ -1,188 +1,210 @@
-// Smdn.Net.MuninNode.dll (Smdn.Net.MuninNode-1.1.0)
+// Smdn.Net.MuninNode.dll (Smdn.Net.MuninNode-1.2.0)
// Name: Smdn.Net.MuninNode
-// AssemblyVersion: 1.1.0.0
-// InformationalVersion: 1.1.0+8c512e91195981258988a30fdf9c0ff4c53a6acc
+// AssemblyVersion: 1.2.0.0
+// InformationalVersion: 1.2.0+b0e11cd6b408018ad93f29b49e58cab7e9ef6b1b
// TargetFramework: .NETCoreApp,Version=v6.0
// Configuration: Release
// Referenced assemblies:
// Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Smdn.Fundamental.Exception, Version=3.0.0.0, Culture=neutral
// System.Collections, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.ComponentModel, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.IO.Pipelines, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
// System.Linq, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Memory, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
// System.Net.Primitives, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Net.Sockets, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Security.Cryptography.Algorithms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Text.RegularExpressions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
#nullable enable annotations
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Smdn.Net.MuninNode;
using Smdn.Net.MuninPlugin;
namespace Smdn.Net.MuninNode {
public class LocalNode : NodeBase {
+ public LocalNode(IPluginProvider pluginProvider, string hostName, int port, ILogger? logger = null) {}
+ public LocalNode(IPluginProvider pluginProvider, string hostName, int port, IServiceProvider? serviceProvider = null) {}
public LocalNode(IReadOnlyCollection<IPlugin> plugins, int port, IServiceProvider? serviceProvider = null) {}
public LocalNode(IReadOnlyCollection<IPlugin> plugins, string hostName, int port, IServiceProvider? serviceProvider = null) {}
public IPEndPoint LocalEndPoint { get; }
protected override Socket CreateServerSocket() {}
protected override bool IsClientAcceptable(IPEndPoint remoteEndPoint) {}
}
public abstract class NodeBase :
IAsyncDisposable,
IDisposable
{
+ private protected class PluginProvider : IPluginProvider {
+ public PluginProvider(IReadOnlyCollection<IPlugin> plugins) {}
+
+ public IReadOnlyCollection<IPlugin> Plugins { get; }
+ public INodeSessionCallback? SessionCallback { get; }
+ }
+
+ protected NodeBase(IPluginProvider pluginProvider, string hostName, ILogger? logger) {}
protected NodeBase(IReadOnlyCollection<IPlugin> plugins, string hostName, ILogger? logger) {}
public virtual Encoding Encoding { get; }
public string HostName { get; }
+ protected ILogger? Logger { get; }
public virtual Version NodeVersion { get; }
+ [Obsolete("This member will be deprecated in future version.")]
public IReadOnlyCollection<IPlugin> Plugins { get; }
public async ValueTask AcceptAsync(bool throwIfCancellationRequested, CancellationToken cancellationToken) {}
public async ValueTask AcceptSingleSessionAsync(CancellationToken cancellationToken = default) {}
protected abstract Socket CreateServerSocket();
protected virtual void Dispose(bool disposing) {}
public void Dispose() {}
public async ValueTask DisposeAsync() {}
protected virtual async ValueTask DisposeAsyncCore() {}
protected abstract bool IsClientAcceptable(IPEndPoint remoteEndPoint);
public void Start() {}
}
}
namespace Smdn.Net.MuninPlugin {
public interface INodeSessionCallback {
ValueTask ReportSessionClosedAsync(string sessionId, CancellationToken cancellationToken);
ValueTask ReportSessionStartedAsync(string sessionId, CancellationToken cancellationToken);
}
public interface IPlugin {
IPluginDataSource DataSource { get; }
PluginGraphAttributes GraphAttributes { get; }
string Name { get; }
INodeSessionCallback? SessionCallback { get; }
}
public interface IPluginDataSource {
IReadOnlyCollection<IPluginField> Fields { get; }
}
public interface IPluginField {
PluginFieldAttributes Attributes { get; }
string Name { get; }
ValueTask<string> GetFormattedValueStringAsync(CancellationToken cancellationToken);
}
+ public interface IPluginProvider {
+ IReadOnlyCollection<IPlugin> Plugins { get; }
+ INodeSessionCallback? SessionCallback { get; }
+ }
+
public enum PluginFieldGraphStyle : int {
Area = 1,
AreaStack = 3,
Default = 0,
Line = 100,
LineStack = 200,
LineStackWidth1 = 201,
LineStackWidth2 = 202,
LineStackWidth3 = 203,
LineWidth1 = 101,
LineWidth2 = 102,
LineWidth3 = 103,
Stack = 2,
}
public class Plugin :
INodeSessionCallback,
IPlugin,
IPluginDataSource
{
public Plugin(string name, PluginGraphAttributes graphAttributes, IReadOnlyCollection<IPluginField> fields) {}
public IReadOnlyCollection<IPluginField> Fields { get; }
public PluginGraphAttributes GraphAttributes { get; }
public string Name { get; }
IPluginDataSource IPlugin.DataSource { get; }
INodeSessionCallback? IPlugin.SessionCallback { get; }
IReadOnlyCollection<IPluginField> IPluginDataSource.Fields { get; }
protected virtual ValueTask ReportSessionClosedAsync(string sessionId, CancellationToken cancellationToken) {}
protected virtual ValueTask ReportSessionStartedAsync(string sessionId, CancellationToken cancellationToken) {}
ValueTask INodeSessionCallback.ReportSessionClosedAsync(string sessionId, CancellationToken cancellationToken) {}
ValueTask INodeSessionCallback.ReportSessionStartedAsync(string sessionId, CancellationToken cancellationToken) {}
}
public static class PluginFactory {
public static IPluginField CreateField(string label, Func<double?> fetchValue) {}
public static IPluginField CreateField(string label, PluginFieldGraphStyle graphStyle, Func<double?> fetchValue) {}
public static IPluginField CreateField(string label, PluginFieldGraphStyle graphStyle, PluginFieldNormalValueRange normalRangeForWarning, PluginFieldNormalValueRange normalRangeForCritical, Func<double?> fetchValue) {}
+ public static IPluginField CreateField(string name, string label, PluginFieldGraphStyle graphStyle, PluginFieldNormalValueRange normalRangeForWarning, PluginFieldNormalValueRange normalRangeForCritical, Func<double?> fetchValue) {}
public static IPlugin CreatePlugin(string name, PluginGraphAttributes graphAttributes, IReadOnlyCollection<IPluginField> fields) {}
public static IPlugin CreatePlugin(string name, PluginGraphAttributes graphAttributes, IReadOnlyCollection<PluginFieldBase> fields) {}
public static IPlugin CreatePlugin(string name, PluginGraphAttributes graphAttributes, PluginFieldBase field) {}
public static IPlugin CreatePlugin(string name, string fieldLabel, Func<double?> fetchFieldValue, PluginGraphAttributes graphAttributes) {}
public static IPlugin CreatePlugin(string name, string fieldLabel, PluginFieldGraphStyle fieldGraphStyle, Func<double?> fetchFieldValue, PluginGraphAttributes graphAttributes) {}
}
public abstract class PluginFieldBase : IPluginField {
protected PluginFieldBase(string label, string? name, PluginFieldGraphStyle graphStyle = PluginFieldGraphStyle.Default, PluginFieldNormalValueRange normalRangeForWarning = default, PluginFieldNormalValueRange normalRangeForCritical = default) {}
public PluginFieldGraphStyle GraphStyle { get; }
public string Label { get; }
public string Name { get; }
public PluginFieldNormalValueRange NormalRangeForCritical { get; }
public PluginFieldNormalValueRange NormalRangeForWarning { get; }
PluginFieldAttributes IPluginField.Attributes { get; }
protected abstract ValueTask<double?> FetchValueAsync(CancellationToken cancellationToken);
async ValueTask<string> IPluginField.GetFormattedValueStringAsync(CancellationToken cancellationToken) {}
}
public sealed class PluginGraphAttributes {
+ [Obsolete("This member will be deprecated in future version.")]
public PluginGraphAttributes(string title, string category, string verticalLabel, bool scale, string arguments, TimeSpan updateRate, int? width = null, int? height = null) {}
+ public PluginGraphAttributes(string title, string category, string verticalLabel, bool scale, string arguments, TimeSpan? updateRate = null, int? width = null, int? height = null) {}
+ public PluginGraphAttributes(string title, string category, string verticalLabel, bool scale, string arguments, TimeSpan? updateRate, int? width, int? height, IEnumerable<string>? order) {}
public string Arguments { get; }
public string Category { get; }
public int? Height { get; }
+ public string? Order { get; }
public bool Scale { get; }
public string Title { get; }
- public TimeSpan UpdateRate { get; }
+ public TimeSpan? UpdateRate { get; }
public string VerticalLabel { get; }
public int? Width { get; }
}
public readonly struct PluginFieldAttributes {
public PluginFieldAttributes(string label, PluginFieldGraphStyle graphStyle = PluginFieldGraphStyle.Default) {}
public PluginFieldAttributes(string label, PluginFieldGraphStyle graphStyle = PluginFieldGraphStyle.Default, PluginFieldNormalValueRange normalRangeForWarning = default, PluginFieldNormalValueRange normalRangeForCritical = default) {}
public PluginFieldGraphStyle GraphStyle { get; }
public string Label { get; }
public PluginFieldNormalValueRange NormalRangeForCritical { get; }
public PluginFieldNormalValueRange NormalRangeForWarning { get; }
}
public readonly struct PluginFieldNormalValueRange {
public static readonly PluginFieldNormalValueRange None; // = "Smdn.Net.MuninPlugin.PluginFieldNormalValueRange"
public static PluginFieldNormalValueRange CreateMax(double max) {}
public static PluginFieldNormalValueRange CreateMin(double min) {}
public static PluginFieldNormalValueRange CreateRange(double min, double max) {}
public bool HasValue { get; }
public double? Max { get; }
public double? Min { get; }
}
}
// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.2.0.
// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/doc/api-list/Smdn.Net.MuninNode/Smdn.Net.MuninNode-netstandard2.1.apilist.cs b/doc/api-list/Smdn.Net.MuninNode/Smdn.Net.MuninNode-netstandard2.1.apilist.cs
index 2b85970..817c4b6 100644
--- a/doc/api-list/Smdn.Net.MuninNode/Smdn.Net.MuninNode-netstandard2.1.apilist.cs
+++ b/doc/api-list/Smdn.Net.MuninNode/Smdn.Net.MuninNode-netstandard2.1.apilist.cs
@@ -1,181 +1,203 @@
-// Smdn.Net.MuninNode.dll (Smdn.Net.MuninNode-1.1.0)
+// Smdn.Net.MuninNode.dll (Smdn.Net.MuninNode-1.2.0)
// Name: Smdn.Net.MuninNode
-// AssemblyVersion: 1.1.0.0
-// InformationalVersion: 1.1.0+8c512e91195981258988a30fdf9c0ff4c53a6acc
+// AssemblyVersion: 1.2.0.0
+// InformationalVersion: 1.2.0+b0e11cd6b408018ad93f29b49e58cab7e9ef6b1b
// TargetFramework: .NETStandard,Version=v2.1
// Configuration: Release
// Referenced assemblies:
// Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Smdn.Fundamental.Encoding.Buffer, Version=3.0.0.0, Culture=neutral
// Smdn.Fundamental.Exception, Version=3.0.0.0, Culture=neutral
// System.IO.Pipelines, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
// netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
#nullable enable annotations
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Smdn.Net.MuninNode;
using Smdn.Net.MuninPlugin;
namespace Smdn.Net.MuninNode {
public class LocalNode : NodeBase {
+ public LocalNode(IPluginProvider pluginProvider, string hostName, int port, ILogger? logger = null) {}
+ public LocalNode(IPluginProvider pluginProvider, string hostName, int port, IServiceProvider? serviceProvider = null) {}
public LocalNode(IReadOnlyCollection<IPlugin> plugins, int port, IServiceProvider? serviceProvider = null) {}
public LocalNode(IReadOnlyCollection<IPlugin> plugins, string hostName, int port, IServiceProvider? serviceProvider = null) {}
public IPEndPoint LocalEndPoint { get; }
protected override Socket CreateServerSocket() {}
protected override bool IsClientAcceptable(IPEndPoint remoteEndPoint) {}
}
public abstract class NodeBase :
IAsyncDisposable,
IDisposable
{
+ private protected class PluginProvider : IPluginProvider {
+ public PluginProvider(IReadOnlyCollection<IPlugin> plugins) {}
+
+ public IReadOnlyCollection<IPlugin> Plugins { get; }
+ public INodeSessionCallback? SessionCallback { get; }
+ }
+
+ protected NodeBase(IPluginProvider pluginProvider, string hostName, ILogger? logger) {}
protected NodeBase(IReadOnlyCollection<IPlugin> plugins, string hostName, ILogger? logger) {}
public virtual Encoding Encoding { get; }
public string HostName { get; }
+ protected ILogger? Logger { get; }
public virtual Version NodeVersion { get; }
+ [Obsolete("This member will be deprecated in future version.")]
public IReadOnlyCollection<IPlugin> Plugins { get; }
public async ValueTask AcceptAsync(bool throwIfCancellationRequested, CancellationToken cancellationToken) {}
public async ValueTask AcceptSingleSessionAsync(CancellationToken cancellationToken = default) {}
protected abstract Socket CreateServerSocket();
protected virtual void Dispose(bool disposing) {}
public void Dispose() {}
public async ValueTask DisposeAsync() {}
protected virtual ValueTask DisposeAsyncCore() {}
protected abstract bool IsClientAcceptable(IPEndPoint remoteEndPoint);
public void Start() {}
}
}
namespace Smdn.Net.MuninPlugin {
public interface INodeSessionCallback {
ValueTask ReportSessionClosedAsync(string sessionId, CancellationToken cancellationToken);
ValueTask ReportSessionStartedAsync(string sessionId, CancellationToken cancellationToken);
}
public interface IPlugin {
IPluginDataSource DataSource { get; }
PluginGraphAttributes GraphAttributes { get; }
string Name { get; }
INodeSessionCallback? SessionCallback { get; }
}
public interface IPluginDataSource {
IReadOnlyCollection<IPluginField> Fields { get; }
}
public interface IPluginField {
PluginFieldAttributes Attributes { get; }
string Name { get; }
ValueTask<string> GetFormattedValueStringAsync(CancellationToken cancellationToken);
}
+ public interface IPluginProvider {
+ IReadOnlyCollection<IPlugin> Plugins { get; }
+ INodeSessionCallback? SessionCallback { get; }
+ }
+
public enum PluginFieldGraphStyle : int {
Area = 1,
AreaStack = 3,
Default = 0,
Line = 100,
LineStack = 200,
LineStackWidth1 = 201,
LineStackWidth2 = 202,
LineStackWidth3 = 203,
LineWidth1 = 101,
LineWidth2 = 102,
LineWidth3 = 103,
Stack = 2,
}
public class Plugin :
INodeSessionCallback,
IPlugin,
IPluginDataSource
{
public Plugin(string name, PluginGraphAttributes graphAttributes, IReadOnlyCollection<IPluginField> fields) {}
public IReadOnlyCollection<IPluginField> Fields { get; }
public PluginGraphAttributes GraphAttributes { get; }
public string Name { get; }
IPluginDataSource IPlugin.DataSource { get; }
INodeSessionCallback? IPlugin.SessionCallback { get; }
IReadOnlyCollection<IPluginField> IPluginDataSource.Fields { get; }
protected virtual ValueTask ReportSessionClosedAsync(string sessionId, CancellationToken cancellationToken) {}
protected virtual ValueTask ReportSessionStartedAsync(string sessionId, CancellationToken cancellationToken) {}
ValueTask INodeSessionCallback.ReportSessionClosedAsync(string sessionId, CancellationToken cancellationToken) {}
ValueTask INodeSessionCallback.ReportSessionStartedAsync(string sessionId, CancellationToken cancellationToken) {}
}
public static class PluginFactory {
public static IPluginField CreateField(string label, Func<double?> fetchValue) {}
public static IPluginField CreateField(string label, PluginFieldGraphStyle graphStyle, Func<double?> fetchValue) {}
public static IPluginField CreateField(string label, PluginFieldGraphStyle graphStyle, PluginFieldNormalValueRange normalRangeForWarning, PluginFieldNormalValueRange normalRangeForCritical, Func<double?> fetchValue) {}
+ public static IPluginField CreateField(string name, string label, PluginFieldGraphStyle graphStyle, PluginFieldNormalValueRange normalRangeForWarning, PluginFieldNormalValueRange normalRangeForCritical, Func<double?> fetchValue) {}
public static IPlugin CreatePlugin(string name, PluginGraphAttributes graphAttributes, IReadOnlyCollection<IPluginField> fields) {}
public static IPlugin CreatePlugin(string name, PluginGraphAttributes graphAttributes, IReadOnlyCollection<PluginFieldBase> fields) {}
public static IPlugin CreatePlugin(string name, PluginGraphAttributes graphAttributes, PluginFieldBase field) {}
public static IPlugin CreatePlugin(string name, string fieldLabel, Func<double?> fetchFieldValue, PluginGraphAttributes graphAttributes) {}
public static IPlugin CreatePlugin(string name, string fieldLabel, PluginFieldGraphStyle fieldGraphStyle, Func<double?> fetchFieldValue, PluginGraphAttributes graphAttributes) {}
}
public abstract class PluginFieldBase : IPluginField {
protected PluginFieldBase(string label, string? name, PluginFieldGraphStyle graphStyle = PluginFieldGraphStyle.Default, PluginFieldNormalValueRange normalRangeForWarning = default, PluginFieldNormalValueRange normalRangeForCritical = default) {}
public PluginFieldGraphStyle GraphStyle { get; }
public string Label { get; }
public string Name { get; }
public PluginFieldNormalValueRange NormalRangeForCritical { get; }
public PluginFieldNormalValueRange NormalRangeForWarning { get; }
PluginFieldAttributes IPluginField.Attributes { get; }
protected abstract ValueTask<double?> FetchValueAsync(CancellationToken cancellationToken);
async ValueTask<string> IPluginField.GetFormattedValueStringAsync(CancellationToken cancellationToken) {}
}
public sealed class PluginGraphAttributes {
+ [Obsolete("This member will be deprecated in future version.")]
public PluginGraphAttributes(string title, string category, string verticalLabel, bool scale, string arguments, TimeSpan updateRate, int? width = null, int? height = null) {}
+ public PluginGraphAttributes(string title, string category, string verticalLabel, bool scale, string arguments, TimeSpan? updateRate = null, int? width = null, int? height = null) {}
+ public PluginGraphAttributes(string title, string category, string verticalLabel, bool scale, string arguments, TimeSpan? updateRate, int? width, int? height, IEnumerable<string>? order) {}
public string Arguments { get; }
public string Category { get; }
public int? Height { get; }
+ public string? Order { get; }
public bool Scale { get; }
public string Title { get; }
- public TimeSpan UpdateRate { get; }
+ public TimeSpan? UpdateRate { get; }
public string VerticalLabel { get; }
public int? Width { get; }
}
public readonly struct PluginFieldAttributes {
public PluginFieldAttributes(string label, PluginFieldGraphStyle graphStyle = PluginFieldGraphStyle.Default) {}
public PluginFieldAttributes(string label, PluginFieldGraphStyle graphStyle = PluginFieldGraphStyle.Default, PluginFieldNormalValueRange normalRangeForWarning = default, PluginFieldNormalValueRange normalRangeForCritical = default) {}
public PluginFieldGraphStyle GraphStyle { get; }
public string Label { get; }
public PluginFieldNormalValueRange NormalRangeForCritical { get; }
public PluginFieldNormalValueRange NormalRangeForWarning { get; }
}
public readonly struct PluginFieldNormalValueRange {
public static readonly PluginFieldNormalValueRange None; // = "Smdn.Net.MuninPlugin.PluginFieldNormalValueRange"
public static PluginFieldNormalValueRange CreateMax(double max) {}
public static PluginFieldNormalValueRange CreateMin(double min) {}
public static PluginFieldNormalValueRange CreateRange(double min, double max) {}
public bool HasValue { get; }
public double? Max { get; }
public double? Min { get; }
}
}
// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.2.0.
// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
Full changes
Full changes in this release:
diff --git a/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode.csproj b/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode.csproj
index ce3c7a3..9295e42 100644
--- a/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode.csproj
+++ b/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode.csproj
@@ -5,7 +5,7 @@ SPDX-License-Identifier: MIT
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.1;net6.0</TargetFrameworks>
- <VersionPrefix>1.1.0</VersionPrefix>
+ <VersionPrefix>1.2.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
<PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion>
<RootNamespace/> <!-- empty the root namespace so that the namespace is determined only by the directory name, for code style rule IDE0030 -->
diff --git a/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/LocalNode.cs b/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/LocalNode.cs
index 6844152..b42f9dc 100644
--- a/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/LocalNode.cs
+++ b/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/LocalNode.cs
@@ -59,11 +59,78 @@ public class LocalNode : NodeBase {
int port,
IServiceProvider? serviceProvider = null
)
- : base(
- plugins: plugins,
+ : this(
+ pluginProvider: new PluginProvider(plugins ?? throw new ArgumentNullException(nameof(plugins))),
+ hostName: hostName,
+ port: port,
+ serviceProvider: serviceProvider
+ )
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="LocalNode"/> class.
+ /// </summary>
+ /// <param name="pluginProvider">
+ /// The <see cref="IPluginProvider"/> that provides <see cref="IPlugin"/>s for this node.
+ /// </param>
+ /// <param name="hostName">
+ /// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
+ /// </param>
+ /// <param name="port">
+ /// The port number on which this node accepts connections.
+ /// </param>
+ /// <param name="serviceProvider">
+ /// The <see cref="IServiceProvider"/>.
+ /// This constructor overload attempts to get a service of <see cref="ILoggerFactory"/>, to create an <see cref="ILogger"/>.
+ /// </param>
+ /// <remarks>
+ /// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
+ /// </remarks>
+ public LocalNode(
+ IPluginProvider pluginProvider,
+ string hostName,
+ int port,
+ IServiceProvider? serviceProvider = null
+ )
+ : this(
+ pluginProvider: pluginProvider ?? throw new ArgumentNullException(nameof(pluginProvider)),
hostName: hostName,
+ port: port,
logger: serviceProvider?.GetService<ILoggerFactory>()?.CreateLogger<LocalNode>()
)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="LocalNode"/> class.
+ /// </summary>
+ /// <param name="pluginProvider">
+ /// The <see cref="IPluginProvider"/> that provides <see cref="IPlugin"/>s for this node.
+ /// </param>
+ /// <param name="hostName">
+ /// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
+ /// </param>
+ /// <param name="port">
+ /// The port number on which this node accepts connections.
+ /// </param>
+ /// <param name="logger">
+ /// The <see cref="ILogger"/> to report the situation.
+ /// </param>
+ /// <remarks>
+ /// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
+ /// </remarks>
+ public LocalNode(
+ IPluginProvider pluginProvider,
+ string hostName,
+ int port,
+ ILogger? logger = null
+ )
+ : base(
+ pluginProvider: pluginProvider,
+ hostName: hostName,
+ logger: logger
+ )
{
if (Socket.OSSupportsIPv6) {
LocalEndPoint = new IPEndPoint(
diff --git a/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.cs b/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.cs
index 84fe125..d3a7ebd 100644
--- a/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.cs
+++ b/src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.cs
@@ -31,22 +31,50 @@ namespace Smdn.Net.MuninNode;
public abstract class NodeBase : IDisposable, IAsyncDisposable {
private static readonly Version defaultNodeVersion = new(1, 0, 0, 0);
- public IReadOnlyCollection<IPlugin> Plugins { get; }
+ [Obsolete("This member will be deprecated in future version.")]
+ public IReadOnlyCollection<IPlugin> Plugins => pluginProvider.Plugins;
+
public string HostName { get; }
public virtual Version NodeVersion => defaultNodeVersion;
public virtual Encoding Encoding => Encoding.Default;
- private readonly ILogger? logger;
+ private readonly IPluginProvider pluginProvider;
+
+ protected ILogger? Logger { get; }
+
private Socket? server;
protected NodeBase(
IReadOnlyCollection<IPlugin> plugins,
string hostName,
ILogger? logger
+ )
+ : this(
+ pluginProvider: new PluginProvider(plugins ?? throw new ArgumentNullException(nameof(plugins))),
+ hostName: hostName,
+ logger: logger
+ )
+ {
+ }
+
+ private protected class PluginProvider : IPluginProvider {
+ public IReadOnlyCollection<IPlugin> Plugins { get; }
+ public INodeSessionCallback? SessionCallback => null;
+
+ public PluginProvider(IReadOnlyCollection<IPlugin> plugins)
+ {
+ Plugins = plugins;
+ }
+ }
+
+ protected NodeBase(
+ IPluginProvider pluginProvider,
+ string hostName,
+ ILogger? logger
)
{
- Plugins = plugins ?? throw new ArgumentNullException(nameof(plugins));
+ this.pluginProvider = pluginProvider ?? throw new ArgumentNullException(nameof(pluginProvider));
if (hostName == null)
throw new ArgumentNullException(nameof(hostName));
@@ -55,7 +83,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
HostName = hostName;
- this.logger = logger;
+ Logger = logger;
}
public void Dispose()
@@ -125,11 +153,11 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
if (server is not null)
throw new InvalidOperationException("already started");
- logger?.LogInformation($"starting");
+ Logger?.LogInformation($"starting");
server = CreateServerSocket() ?? throw new InvalidOperationException("cannot start server");
- logger?.LogInformation("started (end point: {LocalEndPoint})", server.LocalEndPoint);
+ Logger?.LogInformation("started (end point: {LocalEndPoint})", server.LocalEndPoint);
}
protected abstract bool IsClientAcceptable(IPEndPoint remoteEndPoint);
@@ -184,7 +212,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
if (server is null)
throw new InvalidOperationException("not started or already closed");
- logger?.LogInformation("accepting...");
+ Logger?.LogInformation("accepting...");
var client = await server
#if SYSTEM_NET_SOCKETS_SOCKET_ACCEPTASYNC_CANCELLATIONTOKEN
@@ -202,7 +230,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
remoteEndPoint = client.RemoteEndPoint as IPEndPoint;
if (remoteEndPoint is null) {
- logger?.LogWarning(
+ Logger?.LogWarning(
"cannot accept {RemoteEndPoint} ({RemoteEndPointAddressFamily})",
client.RemoteEndPoint?.ToString() ?? "(null)",
client.RemoteEndPoint?.AddressFamily
@@ -211,7 +239,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
}
if (!IsClientAcceptable(remoteEndPoint)) {
- logger?.LogWarning("access refused: {RemoteEndPoint}", remoteEndPoint);
+ Logger?.LogWarning("access refused: {RemoteEndPoint}", remoteEndPoint);
return;
}
@@ -219,7 +247,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
cancellationToken.ThrowIfCancellationRequested();
- logger?.LogDebug("[{RemoteEndPoint}] sending banner", remoteEndPoint);
+ Logger?.LogDebug("[{RemoteEndPoint}] sending banner", remoteEndPoint);
try {
await SendResponseAsync(
@@ -236,7 +264,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
SocketError.OperationAborted or // ECANCELED (125)
SocketError.ConnectionReset // ECONNRESET (104)
) {
- logger?.LogWarning(
+ Logger?.LogWarning(
"[{RemoteEndPoint}] client closed session while sending banner",
remoteEndPoint
);
@@ -245,7 +273,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
}
#pragma warning disable CA1031
catch (Exception ex) {
- logger?.LogCritical(
+ Logger?.LogCritical(
ex,
"[{RemoteEndPoint}] unexpected exception occured while sending banner",
remoteEndPoint
@@ -257,10 +285,13 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
cancellationToken.ThrowIfCancellationRequested();
- logger?.LogInformation("[{RemoteEndPoint}] session started; ID={SessionId}", remoteEndPoint, sessionId);
+ Logger?.LogInformation("[{RemoteEndPoint}] session started; ID={SessionId}", remoteEndPoint, sessionId);
try {
- foreach (var plugin in Plugins) {
+ if (pluginProvider.SessionCallback is not null)
+ await pluginProvider.SessionCallback.ReportSessionStartedAsync(sessionId, cancellationToken).ConfigureAwait(false);
+
+ foreach (var plugin in pluginProvider.Plugins) {
if (plugin.SessionCallback is not null)
await plugin.SessionCallback.ReportSessionStartedAsync(sessionId, cancellationToken).ConfigureAwait(false);
}
@@ -273,19 +304,22 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
ProcessCommandAsync(client, remoteEndPoint, pipe.Reader, cancellationToken)
).ConfigureAwait(false);
- logger?.LogInformation("[{RemoteEndPoint}] session closed; ID={SessionId}", remoteEndPoint, sessionId);
+ Logger?.LogInformation("[{RemoteEndPoint}] session closed; ID={SessionId}", remoteEndPoint, sessionId);
}
finally {
- foreach (var plugin in Plugins) {
+ foreach (var plugin in pluginProvider.Plugins) {
if (plugin.SessionCallback is not null)
await plugin.SessionCallback.ReportSessionClosedAsync(sessionId, cancellationToken).ConfigureAwait(false);
}
+
+ if (pluginProvider.SessionCallback is not null)
+ await pluginProvider.SessionCallback.ReportSessionClosedAsync(sessionId, cancellationToken).ConfigureAwait(false);
}
}
finally {
client.Close();
- logger?.LogInformation("[{RemoteEndPoint}] connection closed", remoteEndPoint);
+ Logger?.LogInformation("[{RemoteEndPoint}] connection closed", remoteEndPoint);
}
}
@@ -348,7 +382,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
SocketError.OperationAborted or // ECANCELED (125)
SocketError.ConnectionReset // ECONNRESET (104)
) {
- logger?.LogInformation(
+ Logger?.LogInformation(
"[{RemoteEndPoint}] expected socket exception ({NumericSocketErrorCode} {SocketErrorCode})",
remoteEndPoint,
(int)ex.SocketErrorCode,
@@ -357,14 +391,14 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
break; // expected exception
}
catch (ObjectDisposedException) {
- logger?.LogInformation(
+ Logger?.LogInformation(
"[{RemoteEndPoint}] socket has been disposed",
remoteEndPoint
);
break; // expected exception
}
catch (OperationCanceledException) {
- logger?.LogInformation(
+ Logger?.LogInformation(
"[{RemoteEndPoint}] operation canceled",
remoteEndPoint
);
@@ -372,7 +406,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
}
#pragma warning disable CA1031
catch (Exception ex) {
- logger?.LogCritical(
+ Logger?.LogCritical(
ex,
"[{RemoteEndPoint}] unexpected exception while receiving",
remoteEndPoint
@@ -417,7 +451,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
}
}
catch (OperationCanceledException) {
- logger?.LogInformation(
+ Logger?.LogInformation(
"[{RemoteEndPoint}] operation canceled",
remoteEndPoint
);
@@ -425,7 +459,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
}
#pragma warning disable CA1031
catch (Exception ex) {
- logger?.LogCritical(
+ Logger?.LogCritical(
ex,
"[{RemoteEndPoint}] unexpected exception while processing command",
remoteEndPoint
@@ -720,7 +754,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
return SendResponseAsync(
client: client,
encoding: Encoding,
- responseLine: string.Join(" ", Plugins.Select(static plugin => plugin.Name)),
+ responseLine: string.Join(" ", pluginProvider.Plugins.Select(static plugin => plugin.Name)),
cancellationToken: cancellationToken
);
}
@@ -731,7 +765,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
CancellationToken cancellationToken
)
{
- var plugin = Plugins.FirstOrDefault(
+ var plugin = pluginProvider.Plugins.FirstOrDefault(
plugin => string.Equals(Encoding.GetString(arguments), plugin.Name, StringComparison.Ordinal)
);
@@ -792,7 +826,7 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
CancellationToken cancellationToken
)
{
- var plugin = Plugins.FirstOrDefault(
+ var plugin = pluginProvider.Plugins.FirstOrDefault(
plugin => string.Equals(Encoding.GetString(arguments), plugin.Name, StringComparison.Ordinal)
);
@@ -816,13 +850,16 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
$"graph_args {graphAttrs.Arguments}",
$"graph_scale {(graphAttrs.Scale ? "yes" : "no")}",
$"graph_vlabel {graphAttrs.VerticalLabel}",
- $"update_rate {(int)graphAttrs.UpdateRate.TotalSeconds}",
};
+ if (graphAttrs.UpdateRate.HasValue)
+ responseLines.Add($"update_rate {(int)graphAttrs.UpdateRate.Value.TotalSeconds}");
if (graphAttrs.Width.HasValue)
responseLines.Add($"graph_width {graphAttrs.Width.Value}");
if (graphAttrs.Height.HasValue)
responseLines.Add($"graph_height {graphAttrs.Height.Value}");
+ if (!string.IsNullOrEmpty(graphAttrs.Order))
+ responseLines.Add($"graph_order {graphAttrs.Order}");
foreach (var field in plugin.DataSource.Fields) {
var fieldAttrs = field.Attributes;
diff --git a/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/IPluginProvider.cs b/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/IPluginProvider.cs
new file mode 100644
index 0000000..875400c
--- /dev/null
+++ b/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/IPluginProvider.cs
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: 2023 smdn <[email protected]>
+// SPDX-License-Identifier: MIT
+
+using System.Collections.Generic;
+
+namespace Smdn.Net.MuninPlugin;
+
+/// <summary>
+/// Provides an interface that abstracts the plugin provider.
+/// </summary>
+public interface IPluginProvider {
+ /// <summary>Gets a readonly collection of <see cref="IPlugin"/> provided by this provider.</summary>
+ /// <remarks>
+ /// <para>This property is referenced each time a during processing of a request session from the <c>munin-update</c>, such as fetching data or getting configurations.</para>
+ /// <para>The the collection returned from this property should not be changed during the processing of each request session.</para>
+ /// </remarks>
+ /// <seealso cref="IPlugin"/>
+ /// <seealso cref="MuninNode.NodeBase"/>
+ IReadOnlyCollection<IPlugin> Plugins { get; }
+
+ /// <summary>Gets a <see cref="INodeSessionCallback"/>, which defines the callbacks when a request session from the <c>munin-update</c> starts or ends, such as fetching data or getting configurations.
+ /// <seealso cref="INodeSessionCallback"/>
+ /// <seealso cref="MuninNode.NodeBase"/>
+ INodeSessionCallback? SessionCallback { get; }
+}
diff --git a/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/PluginFactory.CreateField.cs b/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/PluginFactory.CreateField.cs
index 7366e86..50ec013 100644
--- a/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/PluginFactory.CreateField.cs
+++ b/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/PluginFactory.CreateField.cs
@@ -52,6 +52,23 @@ partial class PluginFactory {
fetchValue: fetchValue
);
+ public static IPluginField CreateField(
+ string name,
+ string label,
+ PluginFieldGraphStyle graphStyle,
+ PluginFieldNormalValueRange normalRangeForWarning,
+ PluginFieldNormalValueRange normalRangeForCritical,
+ Func<double?> fetchValue
+ )
+ => new ValueFromFuncPluginField(
+ label: label,
+ name: name,
+ graphStyle: graphStyle,
+ normalRangeForWarning: normalRangeForWarning,
+ normalRangeForCritical: normalRangeForCritical,
+ fetchValue: fetchValue
+ );
+
private sealed class ValueFromFuncPluginField : PluginFieldBase {
private readonly Func<double?> fetchValue;
diff --git a/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/PluginGraphAttributes.cs b/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/PluginGraphAttributes.cs
index f5f5010..0331728 100644
--- a/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/PluginGraphAttributes.cs
+++ b/src/Smdn.Net.MuninNode/Smdn.Net.MuninPlugin/PluginGraphAttributes.cs
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: MIT
using System;
+using System.Collections.Generic;
namespace Smdn.Net.MuninPlugin;
@@ -36,7 +37,7 @@ public sealed class PluginGraphAttributes {
/// <summary>Gets a value for the <c>update_rate</c>.</summary>
/// <seealso href="http://guide.munin-monitoring.org/en/latest/reference/plugin.html#update-rate">Plugin reference - Global attributes - update_rate</seealso>
- public TimeSpan UpdateRate { get; }
+ public TimeSpan? UpdateRate { get; }
/// <summary>Gets a value for the <c>graph_width</c>.</summary>
/// <seealso href="http://guide.munin-monitoring.org/en/latest/reference/plugin.html#graph-width">Plugin reference - Global attributes - graph_width</seealso>
@@ -46,6 +47,35 @@ public sealed class PluginGraphAttributes {
/// <seealso href="http://guide.munin-monitoring.org/en/latest/reference/plugin.html#graph-height">Plugin reference - Global attributes - graph_height</seealso>
public int? Height { get; }
+ /// <summary>Gets a value for the <c>graph_order</c>.</summary>
+ /// <seealso href="http://guide.munin-monitoring.org/en/latest/reference/plugin.html#graph-order">Plugin reference - Global attributes - graph_order</seealso>
+ public string? Order { get; }
+
+ public PluginGraphAttributes(
+ string title,
+ string category,
+ string verticalLabel,
+ bool scale,
+ string arguments,
+ TimeSpan? updateRate = null,
+ int? width = null,
+ int? height = null
+ )
+ : this(
+ title: title,
+ category: category,
+ verticalLabel: verticalLabel,
+ scale: scale,
+ arguments: arguments,
+ updateRate: updateRate,
+ width: width,
+ height: height,
+ order: null
+ )
+ {
+ }
+
+ [Obsolete("This member will be deprecated in future version.")]
public PluginGraphAttributes(
string title,
string category,
@@ -55,6 +85,31 @@ public sealed class PluginGraphAttributes {
TimeSpan updateRate,
int? width = null,
int? height = null
+ )
+ : this(
+ title: title,
+ category: category,
+ verticalLabel: verticalLabel,
+ scale: scale,
+ arguments: arguments,
+ updateRate: updateRate,
+ width: width,
+ height: height,
+ order: null
+ )
+ {
+ }
+
+ public PluginGraphAttributes(
+ string title,
+ string category,
+ string verticalLabel,
+ bool scale,
+ string arguments,
+ TimeSpan? updateRate,
+ int? width,
+ int? height,
+ IEnumerable<string>? order
)
{
if (title == null)
@@ -85,8 +140,9 @@ public sealed class PluginGraphAttributes {
VerticalLabel = verticalLabel;
Width = width;
Height = height;
+ Order = order is null ? null : string.Join(" ", order);
- if (updateRate < TimeSpan.FromSeconds(1.0))
+ if (updateRate.HasValue && updateRate.Value < TimeSpan.FromSeconds(1.0))
throw new ArgumentOutOfRangeException(nameof(updateRate), updateRate, "must be at least 1 seconds");
UpdateRate = updateRate;
Notes
Full Changelog: releases/Smdn.Net.MuninNode-1.1.0...releases/Smdn.Net.MuninNode-1.2.0