diff --git a/seqcli.sln.DotSettings b/seqcli.sln.DotSettings
index 6c5c917e..6c218398 100644
--- a/seqcli.sln.DotSettings
+++ b/seqcli.sln.DotSettings
@@ -1,4 +1,6 @@
+ IO
+ IP
MS
True
True
@@ -16,6 +18,7 @@
True
True
True
+ True
True
True
True
@@ -32,4 +35,5 @@
True
True
True
+ True
True
\ No newline at end of file
diff --git a/src/Roastery/Fake/Person.cs b/src/Roastery/Fake/Person.cs
index 53394561..56c0ae0c 100644
--- a/src/Roastery/Fake/Person.cs
+++ b/src/Roastery/Fake/Person.cs
@@ -14,7 +14,7 @@ public Person(string? name, string? address)
}
static readonly string[] Forenames =
- {
+ [
"Akeem",
"Alice",
"Alok",
@@ -40,10 +40,10 @@ public Person(string? name, string? address)
"Yoshi",
"Zach",
"Zeynep"
- };
+ ];
static readonly string[] Surnames =
- {
+ [
"Anderson",
"Alvarez",
"Brookes",
@@ -60,10 +60,10 @@ public Person(string? name, string? address)
"Smith",
"Xia",
"Zheng"
- };
+ ];
static readonly string[] Streets =
- {
+ [
"Lilac Road",
"Lilly Street",
"Carnation Street",
@@ -78,7 +78,7 @@ public Person(string? name, string? address)
"Trillium Creek Parkway",
"Grevillea Street",
"Kurrajong Street"
- };
+ ];
public static Person Generate()
{
diff --git a/src/Roastery/Web/FaultInjectionMiddleware.cs b/src/Roastery/Web/FaultInjectionMiddleware.cs
index 27dae6d8..0c6f472e 100644
--- a/src/Roastery/Web/FaultInjectionMiddleware.cs
+++ b/src/Roastery/Web/FaultInjectionMiddleware.cs
@@ -18,15 +18,15 @@ public FaultInjectionMiddleware(ILogger logger, HttpServer next)
{
_logger = logger.ForContext();
_next = next;
- _faults = new Func>[]
- {
+ _faults =
+ [
Unauthorized,
Unauthorized,
Unauthorized,
Timeout,
Timeout,
Disposed
- };
+ ];
}
Task Unauthorized(HttpRequest request)
diff --git a/src/Roastery/Web/Router.cs b/src/Roastery/Web/Router.cs
index 5df8d7ed..0c9f7be9 100644
--- a/src/Roastery/Web/Router.cs
+++ b/src/Roastery/Web/Router.cs
@@ -63,7 +63,7 @@ public Router(IEnumerable controllers, ILogger logger)
{
using var _ = LogContext.PushProperty("Controller", controllerName);
using var __ = LogContext.PushProperty("Action", actionName);
- return (Task) method.Invoke(controller, new object[] {r})!;
+ return (Task) method.Invoke(controller, [r])!;
});
_logger.Debug("Binding route HTTP {HttpMethod} {RouteTemplate} to action method {Controller}.{Action}()",
diff --git a/src/SeqCli/Apps/Definitions/AppMetadataReader.cs b/src/SeqCli/Apps/Definitions/AppMetadataReader.cs
index 8abd7be0..58269661 100644
--- a/src/SeqCli/Apps/Definitions/AppMetadataReader.cs
+++ b/src/SeqCli/Apps/Definitions/AppMetadataReader.cs
@@ -79,21 +79,15 @@ static Dictionary GetAvailableSettings(Type mainRe
});
}
- static readonly HashSet IntegerTypes = new()
- {
+ static readonly HashSet IntegerTypes =
+ [
typeof(short), typeof(ushort), typeof(int), typeof(uint),
typeof(long), typeof(ulong)
- };
+ ];
- static readonly HashSet DecimalTypes = new()
- {
- typeof(float), typeof(double), typeof(decimal)
- };
+ static readonly HashSet DecimalTypes = [typeof(float), typeof(double), typeof(decimal)];
- static readonly HashSet BooleanTypes = new()
- {
- typeof(bool)
- };
+ static readonly HashSet BooleanTypes = [typeof(bool)];
internal static AppSettingType GetSettingType(Type type)
{
diff --git a/src/SeqCli/Cli/Commands/ApiKey/RemoveCommand.cs b/src/SeqCli/Cli/Commands/ApiKey/RemoveCommand.cs
index d10beb63..8935f178 100644
--- a/src/SeqCli/Cli/Commands/ApiKey/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/ApiKey/RemoveCommand.cs
@@ -48,8 +48,8 @@ protected override async Task Run()
var connection = _connectionFactory.Connect(_connection);
- var toRemove = _entityIdentity.Id != null ?
- new[] {await connection.ApiKeys.FindAsync(_entityIdentity.Id)} :
+ var toRemove = _entityIdentity.Id != null ? [await connection.ApiKeys.FindAsync(_entityIdentity.Id)]
+ :
(await connection.ApiKeys.ListAsync())
.Where(ak => _entityIdentity.Title == ak.Title)
.ToArray();
diff --git a/src/SeqCli/Cli/Commands/AppInstance/RemoveCommand.cs b/src/SeqCli/Cli/Commands/AppInstance/RemoveCommand.cs
index 76e90915..376f7354 100644
--- a/src/SeqCli/Cli/Commands/AppInstance/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/AppInstance/RemoveCommand.cs
@@ -34,8 +34,8 @@ protected override async Task Run()
var connection = _connectionFactory.Connect(_connection);
- var toRemove = _entityIdentity.Id != null ?
- new[] {await connection.AppInstances.FindAsync(_entityIdentity.Id)} :
+ var toRemove = _entityIdentity.Id != null ? [await connection.AppInstances.FindAsync(_entityIdentity.Id)]
+ :
(await connection.AppInstances.ListAsync())
.Where(ak => _entityIdentity.Title == ak.Title)
.ToArray();
diff --git a/src/SeqCli/Cli/Commands/Dashboard/RemoveCommand.cs b/src/SeqCli/Cli/Commands/Dashboard/RemoveCommand.cs
index 64e45bbf..70d9a78e 100644
--- a/src/SeqCli/Cli/Commands/Dashboard/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/Dashboard/RemoveCommand.cs
@@ -50,8 +50,8 @@ protected override async Task Run()
var connection = _connectionFactory.Connect(_connection);
- var toRemove = _entityIdentity.Id != null ?
- new[] { await connection.Dashboards.FindAsync(_entityIdentity.Id) } :
+ var toRemove = _entityIdentity.Id != null ? [await connection.Dashboards.FindAsync(_entityIdentity.Id)]
+ :
(await connection.Dashboards.ListAsync(ownerId: _entityOwner.OwnerId, shared: _entityOwner.IncludeShared))
.Where(dashboard => _entityIdentity.Title == dashboard.Title)
.ToArray();
diff --git a/src/SeqCli/Cli/Commands/Feed/RemoveCommand.cs b/src/SeqCli/Cli/Commands/Feed/RemoveCommand.cs
index 4f0ce4b4..c706fe3e 100644
--- a/src/SeqCli/Cli/Commands/Feed/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/Feed/RemoveCommand.cs
@@ -58,8 +58,8 @@ protected override async Task Run()
var connection = _connectionFactory.Connect(_connection);
- var toRemove = _id != null ?
- new[] {await connection.Feeds.FindAsync(_id)} :
+ var toRemove = _id != null ? [await connection.Feeds.FindAsync(_id)]
+ :
(await connection.Feeds.ListAsync())
.Where(f => _name == f.Name)
.ToArray();
diff --git a/src/SeqCli/Cli/Commands/Forwarder/RunCommand.cs b/src/SeqCli/Cli/Commands/Forwarder/RunCommand.cs
index 4c39c38b..e743f174 100644
--- a/src/SeqCli/Cli/Commands/Forwarder/RunCommand.cs
+++ b/src/SeqCli/Cli/Commands/Forwarder/RunCommand.cs
@@ -12,98 +12,98 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using Autofac;
-using Seq.Forwarder.Config;
-using Serilog;
-using Serilog.Events;
-using Serilog.Formatting.Compact;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
-using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
+using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
-using Seq.Forwarder.Util;
-using Seq.Forwarder.Web.Host;
-using SeqCli.Cli;
using SeqCli.Cli.Features;
+using SeqCli.Config;
+using SeqCli.Config.Forwarder;
+using SeqCli.Forwarder;
+using SeqCli.Forwarder.Util;
+using SeqCli.Forwarder.Web.Host;
+using Serilog;
using Serilog.Core;
+using Serilog.Events;
+using Serilog.Formatting.Compact;
// ReSharper disable UnusedType.Global
-namespace Seq.Forwarder.Cli.Commands
+namespace SeqCli.Cli.Commands.Forwarder;
+
+[Command("forwarder", "run", "Run the server interactively")]
+class RunCommand : Command
{
- [Command("forwarder", "run", "Run the server interactively")]
- class RunCommand : Command
- {
- readonly StoragePathFeature _storagePath;
- readonly ListenUriFeature _listenUri;
+ readonly StoragePathFeature _storagePath;
+ readonly ListenUriFeature _listenUri;
- bool _noLogo;
+ bool _noLogo;
- public RunCommand()
- {
- Options.Add("nologo", _ => _noLogo = true);
- _storagePath = Enable();
- _listenUri = Enable();
- }
+ public RunCommand()
+ {
+ Options.Add("nologo", _ => _noLogo = true);
+ _storagePath = Enable();
+ _listenUri = Enable();
+ }
- protected override async Task Run(string[] unrecognized)
+ protected override async Task Run(string[] unrecognized)
+ {
+ if (Environment.UserInteractive)
{
- if (Environment.UserInteractive)
+ if (!_noLogo)
{
- if (!_noLogo)
- {
- WriteBanner();
- Console.WriteLine();
- }
-
- Console.WriteLine("Running as server; press Ctrl+C to exit.");
+ WriteBanner();
Console.WriteLine();
}
- SeqForwarderConfig config;
+ Console.WriteLine("Running as server; press Ctrl+C to exit.");
+ Console.WriteLine();
+ }
- try
- {
- config = SeqForwarderConfig.ReadOrInit(_storagePath.ConfigFilePath);
- }
- catch (Exception ex)
- {
- await using var logger = CreateLogger(
- LogEventLevel.Information,
- SeqForwarderDiagnosticConfig.GetDefaultInternalLogPath());
+ SeqCliConfig config;
- logger.Fatal(ex, "Failed to load configuration from {ConfigFilePath}", _storagePath.ConfigFilePath);
- return 1;
- }
+ try
+ {
+ config = SeqCliConfig.Read(); // _storagePath.ConfigFilePath);
+ }
+ catch (Exception ex)
+ {
+ await using var logger = CreateLogger(
+ LogEventLevel.Information,
+ ForwarderDiagnosticConfig.GetDefaultInternalLogPath());
- Log.Logger = CreateLogger(
- config.Diagnostics.InternalLoggingLevel,
- config.Diagnostics.InternalLogPath,
- config.Diagnostics.InternalLogServerUri,
- config.Diagnostics.InternalLogServerApiKey);
+ logger.Fatal(ex, "Failed to load configuration from {ConfigFilePath}", _storagePath.ConfigFilePath);
+ return 1;
+ }
- var listenUri = _listenUri.ListenUri ?? config.Api.ListenUri;
+ Log.Logger = CreateLogger(
+ config.Forwarder.Diagnostics.InternalLoggingLevel,
+ config.Forwarder.Diagnostics.InternalLogPath,
+ config.Forwarder.Diagnostics.InternalLogServerUri,
+ config.Forwarder.Diagnostics.InternalLogServerApiKey);
- try
- {
- ILifetimeScope? container = null;
- using var host = new HostBuilder()
- .UseSerilog()
- .UseServiceProviderFactory(new AutofacServiceProviderFactory())
- .ConfigureContainer(builder =>
- {
- builder.RegisterBuildCallback(ls => container = ls);
- builder.RegisterModule(new SeqForwarderModule(_storagePath.BufferPath, config));
- })
- .ConfigureWebHostDefaults(web =>
- {
- web.UseStartup();
- web.UseKestrel(options =>
+ var listenUri = _listenUri.ListenUri ?? config.Forwarder.Api.ListenUri;
+
+ try
+ {
+ ILifetimeScope? container = null;
+ using var host = new HostBuilder()
+ .UseSerilog()
+ .UseServiceProviderFactory(new AutofacServiceProviderFactory())
+ .ConfigureContainer(builder =>
+ {
+ builder.RegisterBuildCallback(ls => container = ls);
+ builder.RegisterModule(new ForwarderModule(_storagePath.BufferPath, config));
+ })
+ .ConfigureWebHostDefaults(web =>
+ {
+ web.UseStartup();
+ web.UseKestrel(options =>
{
options.AddServerHeader = false;
options.AllowSynchronousIO = true;
@@ -138,124 +138,123 @@ protected override async Task Run(string[] unrecognized)
options.Listen(ipAddress, apiListenUri.Port);
}
});
- })
- .Build();
+ })
+ .Build();
- if (container == null) throw new Exception("Host did not build container.");
+ if (container == null) throw new Exception("Host did not build container.");
- var service = container.Resolve(
- new TypedParameter(typeof(IHost), host),
- new NamedParameter("listenUri", listenUri));
+ var service = container.Resolve(
+ new TypedParameter(typeof(IHost), host),
+ new NamedParameter("listenUri", listenUri));
- var exit = ExecutionEnvironment.SupportsStandardIO
- ? RunStandardIO(service, Console.Out)
- : RunService(service);
+ var exit = ExecutionEnvironment.SupportsStandardIO
+ ? RunStandardIO(service, Console.Out)
+ : RunService(service);
- return exit;
- }
- catch (Exception ex)
- {
- Log.Fatal(ex, "Unhandled exception");
- return -1;
- }
- finally
- {
- await Log.CloseAndFlushAsync();
- }
+ return exit;
}
-
- static Logger CreateLogger(
- LogEventLevel internalLoggingLevel,
- string internalLogPath,
- string? internalLogServerUri = null,
- string? internalLogServerApiKey = null)
+ catch (Exception ex)
{
- var loggerConfiguration = new LoggerConfiguration()
- .Enrich.FromLogContext()
- .Enrich.WithProperty("MachineName", Environment.MachineName)
- .Enrich.WithProperty("Application", "Seq Forwarder")
- .MinimumLevel.Is(internalLoggingLevel)
- .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
- .WriteTo.File(
- new RenderedCompactJsonFormatter(),
- GetRollingLogFilePathFormat(internalLogPath),
- rollingInterval: RollingInterval.Day,
- fileSizeLimitBytes: 1024 * 1024);
-
- if (Environment.UserInteractive)
- loggerConfiguration.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information);
-
- if (!string.IsNullOrWhiteSpace(internalLogServerUri))
- loggerConfiguration.WriteTo.Seq(
- internalLogServerUri,
- apiKey: internalLogServerApiKey);
-
- return loggerConfiguration.CreateLogger();
+ Log.Fatal(ex, "Unhandled exception");
+ return -1;
}
-
- static string GetRollingLogFilePathFormat(string internalLogPath)
+ finally
{
- if (internalLogPath == null) throw new ArgumentNullException(nameof(internalLogPath));
-
- return Path.Combine(internalLogPath, "seq-forwarder-.log");
+ await Log.CloseAndFlushAsync();
}
+ }
- [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
- static int RunService(ServerService service)
- {
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ static int RunService(ServerService service)
+ {
#if WINDOWS
System.ServiceProcess.ServiceBase.Run([
new ServiceProcess.SeqForwarderWindowsService(service)
]);
return 0;
#else
- throw new NotSupportedException("Windows services are not supported on this platform.");
+ throw new NotSupportedException("Windows services are not supported on this platform.");
#endif
- }
+ }
- static int RunStandardIO(ServerService service, TextWriter cout)
+ static int RunStandardIO(ServerService service, TextWriter cout)
+ {
+ service.Start();
+
+ try
{
- service.Start();
+ Console.TreatControlCAsInput = true;
+ var k = Console.ReadKey(true);
+ while (k.Key != ConsoleKey.C || !k.Modifiers.HasFlag(ConsoleModifiers.Control))
+ k = Console.ReadKey(true);
- try
- {
- Console.TreatControlCAsInput = true;
- var k = Console.ReadKey(true);
- while (k.Key != ConsoleKey.C || !k.Modifiers.HasFlag(ConsoleModifiers.Control))
- k = Console.ReadKey(true);
+ cout.WriteLine("Ctrl+C pressed; stopping...");
+ Console.TreatControlCAsInput = false;
+ }
+ catch (Exception ex)
+ {
+ Log.Debug(ex, "Console not attached, waiting for any input");
+ Console.Read();
+ }
- cout.WriteLine("Ctrl+C pressed; stopping...");
- Console.TreatControlCAsInput = false;
- }
- catch (Exception ex)
- {
- Log.Debug(ex, "Console not attached, waiting for any input");
- Console.Read();
- }
+ service.Stop();
- service.Stop();
+ return 0;
+ }
- return 0;
- }
+ static void WriteBanner()
+ {
+ Write("─", ConsoleColor.DarkGray, 47);
+ Console.WriteLine();
+ Write(" Seq Forwarder", ConsoleColor.White);
+ Write(" ──", ConsoleColor.DarkGray);
+ Write(" © 2024 Datalust Pty Ltd", ConsoleColor.Gray);
+ Console.WriteLine();
+ Write("─", ConsoleColor.DarkGray, 47);
+ Console.WriteLine();
+ }
- static void WriteBanner()
- {
- Write("─", ConsoleColor.DarkGray, 47);
- Console.WriteLine();
- Write(" Seq Forwarder", ConsoleColor.White);
- Write(" ──", ConsoleColor.DarkGray);
- Write(" © 2024 Datalust Pty Ltd", ConsoleColor.Gray);
- Console.WriteLine();
- Write("─", ConsoleColor.DarkGray, 47);
- Console.WriteLine();
- }
+ static void Write(string s, ConsoleColor color, int repeats = 1)
+ {
+ Console.ForegroundColor = color;
+ for (var i = 0; i < repeats; ++i)
+ Console.Write(s);
+ Console.ResetColor();
+ }
+
+ static Logger CreateLogger(
+ LogEventLevel internalLoggingLevel,
+ string internalLogPath,
+ string? internalLogServerUri = null,
+ string? internalLogServerApiKey = null)
+ {
+ var loggerConfiguration = new LoggerConfiguration()
+ .Enrich.FromLogContext()
+ .Enrich.WithProperty("MachineName", Environment.MachineName)
+ .Enrich.WithProperty("Application", "Seq Forwarder")
+ .MinimumLevel.Is(internalLoggingLevel)
+ .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
+ .WriteTo.File(
+ new RenderedCompactJsonFormatter(),
+ GetRollingLogFilePathFormat(internalLogPath),
+ rollingInterval: RollingInterval.Day,
+ fileSizeLimitBytes: 1024 * 1024);
- static void Write(string s, ConsoleColor color, int repeats = 1)
- {
- Console.ForegroundColor = color;
- for (var i = 0; i < repeats; ++i)
- Console.Write(s);
- Console.ResetColor();
- }
+ if (Environment.UserInteractive)
+ loggerConfiguration.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information);
+
+ if (!string.IsNullOrWhiteSpace(internalLogServerUri))
+ loggerConfiguration.WriteTo.Seq(
+ internalLogServerUri,
+ apiKey: internalLogServerApiKey);
+
+ return loggerConfiguration.CreateLogger();
+ }
+
+ static string GetRollingLogFilePathFormat(string internalLogPath)
+ {
+ if (internalLogPath == null) throw new ArgumentNullException(nameof(internalLogPath));
+
+ return Path.Combine(internalLogPath, "seq-forwarder-.log");
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Cli/Commands/Forwarder/TruncateCommand.cs b/src/SeqCli/Cli/Commands/Forwarder/TruncateCommand.cs
index baf0320c..df5130da 100644
--- a/src/SeqCli/Cli/Commands/Forwarder/TruncateCommand.cs
+++ b/src/SeqCli/Cli/Commands/Forwarder/TruncateCommand.cs
@@ -13,39 +13,36 @@
// limitations under the License.
using System;
-using System.IO;
using System.Threading.Tasks;
-using Seq.Forwarder.Multiplexing;
-using SeqCli.Cli;
using SeqCli.Cli.Features;
+using SeqCli.Forwarder.Multiplexing;
using Serilog;
-namespace Seq.Forwarder.Cli.Commands
+namespace SeqCli.Cli.Commands.Forwarder;
+
+[Command("forwarder", "truncate", "Clear the log buffer contents")]
+class TruncateCommand : Command
{
- [Command("forwarder", "truncate", "Clear the log buffer contents")]
- class TruncateCommand : Command
+ readonly StoragePathFeature _storagePath;
+
+ public TruncateCommand()
{
- readonly StoragePathFeature _storagePath;
+ _storagePath = Enable();
+ }
- public TruncateCommand()
+ protected override async Task Run(string[] args)
+ {
+ try
{
- _storagePath = Enable();
+ ActiveLogBufferMap.Truncate(_storagePath.BufferPath);
+ return 0;
}
-
- protected override async Task Run(string[] args)
+ catch (Exception ex)
{
- try
- {
- ActiveLogBufferMap.Truncate(_storagePath.BufferPath);
- return 0;
- }
- catch (Exception ex)
- {
- await using var logger = new LoggerConfiguration().WriteTo.Console().CreateLogger();
+ await using var logger = new LoggerConfiguration().WriteTo.Console().CreateLogger();
- logger.Fatal(ex, "Could not truncate log buffer");
- return 1;
- }
+ logger.Fatal(ex, "Could not truncate log buffer");
+ return 1;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Cli/Commands/RetentionPolicy/ListCommand.cs b/src/SeqCli/Cli/Commands/RetentionPolicy/ListCommand.cs
index 57702a93..710ae634 100644
--- a/src/SeqCli/Cli/Commands/RetentionPolicy/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/RetentionPolicy/ListCommand.cs
@@ -49,8 +49,8 @@ protected override async Task Run()
{
var connection = _connectionFactory.Connect(_connection);
- var list = _id != null ?
- new[] { await connection.RetentionPolicies.FindAsync(_id) } :
+ var list = _id != null ? [await connection.RetentionPolicies.FindAsync(_id)]
+ :
(await connection.RetentionPolicies.ListAsync())
.ToArray();
diff --git a/src/SeqCli/Cli/Commands/Signal/RemoveCommand.cs b/src/SeqCli/Cli/Commands/Signal/RemoveCommand.cs
index cf1b890e..35f3a951 100644
--- a/src/SeqCli/Cli/Commands/Signal/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/Signal/RemoveCommand.cs
@@ -50,8 +50,8 @@ protected override async Task Run()
var connection = _connectionFactory.Connect(_connection);
- var toRemove = _entityIdentity.Id != null ?
- new[] { await connection.Signals.FindAsync(_entityIdentity.Id) } :
+ var toRemove = _entityIdentity.Id != null ? [await connection.Signals.FindAsync(_entityIdentity.Id)]
+ :
(await connection.Signals.ListAsync(ownerId: _entityOwner.OwnerId, shared: _entityOwner.IncludeShared))
.Where(signal => _entityIdentity.Title == signal.Title)
.ToArray();
diff --git a/src/SeqCli/Cli/Commands/User/RemoveCommand.cs b/src/SeqCli/Cli/Commands/User/RemoveCommand.cs
index 51b6127c..782f90d9 100644
--- a/src/SeqCli/Cli/Commands/User/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/User/RemoveCommand.cs
@@ -48,8 +48,8 @@ protected override async Task Run()
var connection = _connectionFactory.Connect(_connection);
- var toRemove = _userIdentity.Id != null ?
- new[] {await connection.Users.FindAsync(_userIdentity.Id)} :
+ var toRemove = _userIdentity.Id != null ? [await connection.Users.FindAsync(_userIdentity.Id)]
+ :
(await connection.Users.ListAsync())
.Where(u => _userIdentity.Name == u.Username)
.ToArray();
diff --git a/src/SeqCli/Cli/Commands/Workspace/RemoveCommand.cs b/src/SeqCli/Cli/Commands/Workspace/RemoveCommand.cs
index a4990edd..470e719c 100644
--- a/src/SeqCli/Cli/Commands/Workspace/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/Workspace/RemoveCommand.cs
@@ -36,8 +36,8 @@ protected override async Task Run()
var connection = _connectionFactory.Connect(_connection);
- var toRemove = _entityIdentity.Id != null ?
- new[] { await connection.Workspaces.FindAsync(_entityIdentity.Id) } :
+ var toRemove = _entityIdentity.Id != null ? [await connection.Workspaces.FindAsync(_entityIdentity.Id)]
+ :
(await connection.Workspaces.ListAsync(ownerId: _entityOwner.OwnerId, shared: _entityOwner.IncludeShared))
.Where(workspace => _entityIdentity.Title == workspace.Title)
.ToArray();
diff --git a/src/SeqCli/Cli/Options.cs b/src/SeqCli/Cli/Options.cs
index 5678ac29..beedaad4 100644
--- a/src/SeqCli/Cli/Options.cs
+++ b/src/SeqCli/Cli/Options.cs
@@ -150,1218 +150,1216 @@
#if NDESK_OPTIONS
namespace NDesk.Options
#else
-namespace SeqCli.Cli
+namespace SeqCli.Cli;
#endif
-{
- delegate U Converter(T t);
- static class StringCoda {
+delegate U Converter(T t);
- public static IEnumerable WrappedLines (string self, params int[] widths)
- {
- IEnumerable w = widths;
- return WrappedLines (self, w);
- }
+static class StringCoda {
- public static IEnumerable WrappedLines (string self, IEnumerable widths)
- {
- if (widths == null)
- throw new ArgumentNullException (nameof(widths));
- return CreateWrappedLinesIterator (self, widths);
- }
+ public static IEnumerable WrappedLines (string self, params int[] widths)
+ {
+ IEnumerable w = widths;
+ return WrappedLines (self, w);
+ }
- private static IEnumerable CreateWrappedLinesIterator (string self, IEnumerable widths)
- {
- if (string.IsNullOrEmpty (self)) {
- yield return string.Empty;
- yield break;
- }
- using (IEnumerator ewidths = widths.GetEnumerator ()) {
- bool? hw = null;
- int width = GetNextWidth (ewidths, int.MaxValue, ref hw);
- int start = 0, end;
- do {
- end = GetLineEnd (start, width, self);
- char c = self [end-1];
- if (char.IsWhiteSpace (c))
- --end;
- bool needContinuation = end != self.Length && !IsEolChar (c);
- string continuation = "";
- if (needContinuation) {
- --end;
- continuation = "-";
- }
- string line = self.Substring (start, end - start) + continuation;
- yield return line;
- start = end;
- if (char.IsWhiteSpace (c))
- ++start;
- width = GetNextWidth (ewidths, width, ref hw);
- } while (start < self.Length);
- }
- }
+ public static IEnumerable WrappedLines (string self, IEnumerable widths)
+ {
+ if (widths == null)
+ throw new ArgumentNullException (nameof(widths));
+ return CreateWrappedLinesIterator (self, widths);
+ }
- private static int GetNextWidth (IEnumerator ewidths, int curWidth, ref bool? eValid)
- {
- if (!eValid.HasValue || (eValid.HasValue && eValid.Value)) {
- curWidth = (eValid = ewidths.MoveNext ()).Value ? ewidths.Current : curWidth;
- // '.' is any character, - is for a continuation
- const string minWidth = ".-";
- if (curWidth < minWidth.Length)
- throw new ArgumentOutOfRangeException ("widths",
- string.Format ("Element must be >= {0}, was {1}.", minWidth.Length, curWidth));
- return curWidth;
- }
- // no more elements, use the last element.
- return curWidth;
+ private static IEnumerable CreateWrappedLinesIterator (string self, IEnumerable widths)
+ {
+ if (string.IsNullOrEmpty (self)) {
+ yield return string.Empty;
+ yield break;
+ }
+ using (IEnumerator ewidths = widths.GetEnumerator ()) {
+ bool? hw = null;
+ int width = GetNextWidth (ewidths, int.MaxValue, ref hw);
+ int start = 0, end;
+ do {
+ end = GetLineEnd (start, width, self);
+ char c = self [end-1];
+ if (char.IsWhiteSpace (c))
+ --end;
+ bool needContinuation = end != self.Length && !IsEolChar (c);
+ string continuation = "";
+ if (needContinuation) {
+ --end;
+ continuation = "-";
+ }
+ string line = self.Substring (start, end - start) + continuation;
+ yield return line;
+ start = end;
+ if (char.IsWhiteSpace (c))
+ ++start;
+ width = GetNextWidth (ewidths, width, ref hw);
+ } while (start < self.Length);
}
+ }
- private static bool IsEolChar (char c)
- {
- return !char.IsLetterOrDigit (c);
+ private static int GetNextWidth (IEnumerator ewidths, int curWidth, ref bool? eValid)
+ {
+ if (!eValid.HasValue || (eValid.HasValue && eValid.Value)) {
+ curWidth = (eValid = ewidths.MoveNext ()).Value ? ewidths.Current : curWidth;
+ // '.' is any character, - is for a continuation
+ const string minWidth = ".-";
+ if (curWidth < minWidth.Length)
+ throw new ArgumentOutOfRangeException ("widths",
+ string.Format ("Element must be >= {0}, was {1}.", minWidth.Length, curWidth));
+ return curWidth;
}
+ // no more elements, use the last element.
+ return curWidth;
+ }
- private static int GetLineEnd (int start, int length, string description)
- {
- int end = System.Math.Min (start + length, description.Length);
- int sep = -1;
- for (int i = start; i < end; ++i) {
- if (description [i] == '\n')
- return i+1;
- if (IsEolChar (description [i]))
- sep = i+1;
- }
- if (sep == -1 || end == description.Length)
- return end;
- return sep;
- }
+ private static bool IsEolChar (char c)
+ {
+ return !char.IsLetterOrDigit (c);
}
- class OptionValueCollection : IList, IList {
+ private static int GetLineEnd (int start, int length, string description)
+ {
+ int end = System.Math.Min (start + length, description.Length);
+ int sep = -1;
+ for (int i = start; i < end; ++i) {
+ if (description [i] == '\n')
+ return i+1;
+ if (IsEolChar (description [i]))
+ sep = i+1;
+ }
+ if (sep == -1 || end == description.Length)
+ return end;
+ return sep;
+ }
+}
- List values = new List ();
- OptionContext c;
+class OptionValueCollection : IList, IList {
- internal OptionValueCollection (OptionContext c)
- {
- this.c = c;
- }
+ List values = [];
+ OptionContext c;
- #region ICollection
- void ICollection.CopyTo (Array array, int index) {(values as ICollection).CopyTo (array, index);}
- bool ICollection.IsSynchronized {get {return (values as ICollection).IsSynchronized;}}
- object ICollection.SyncRoot {get {return (values as ICollection).SyncRoot;}}
- #endregion
-
- #region ICollection
- public void Add (string item) {values.Add (item);}
- public void Clear () {values.Clear ();}
- public bool Contains (string item) {return values.Contains (item);}
- public void CopyTo (string[] array, int arrayIndex) {values.CopyTo (array, arrayIndex);}
- public bool Remove (string item) {return values.Remove (item);}
- public int Count {get {return values.Count;}}
- public bool IsReadOnly {get {return false;}}
- #endregion
-
- #region IEnumerable
- IEnumerator IEnumerable.GetEnumerator () {return values.GetEnumerator ();}
- #endregion
-
- #region IEnumerable
- public IEnumerator GetEnumerator () {return values.GetEnumerator ();}
- #endregion
-
- #region IList
- int IList.Add (object value) {return (values as IList).Add (value);}
- bool IList.Contains (object value) {return (values as IList).Contains (value);}
- int IList.IndexOf (object value) {return (values as IList).IndexOf (value);}
- void IList.Insert (int index, object value) {(values as IList).Insert (index, value);}
- void IList.Remove (object value) {(values as IList).Remove (value);}
- void IList.RemoveAt (int index) {(values as IList).RemoveAt (index);}
- bool IList.IsFixedSize {get {return false;}}
- object IList.this [int index] {get {return this [index];} set {(values as IList)[index] = value;}}
- #endregion
-
- #region IList
- public int IndexOf (string item) {return values.IndexOf (item);}
- public void Insert (int index, string item) {values.Insert (index, item);}
- public void RemoveAt (int index) {values.RemoveAt (index);}
-
- private void AssertValid (int index)
- {
- if (c.Option == null)
- throw new InvalidOperationException ("OptionContext.Option is null.");
- if (index >= c.Option.MaxValueCount)
- throw new ArgumentOutOfRangeException (nameof(index));
- if (c.Option.OptionValueType == OptionValueType.Required &&
- index >= values.Count)
- throw new OptionException (string.Format (
- c.OptionSet.MessageLocalizer ("Missing required value for option '{0}'."), c.OptionName),
- c.OptionName);
- }
+ internal OptionValueCollection (OptionContext c)
+ {
+ this.c = c;
+ }
- public string this [int index] {
- get {
- AssertValid (index);
- return index >= values.Count ? null : values [index];
- }
- set {
- values [index] = value;
- }
- }
- #endregion
+ #region ICollection
+ void ICollection.CopyTo (Array array, int index) {(values as ICollection).CopyTo (array, index);}
+ bool ICollection.IsSynchronized {get {return (values as ICollection).IsSynchronized;}}
+ object ICollection.SyncRoot {get {return (values as ICollection).SyncRoot;}}
+ #endregion
+
+ #region ICollection
+ public void Add (string item) {values.Add (item);}
+ public void Clear () {values.Clear ();}
+ public bool Contains (string item) {return values.Contains (item);}
+ public void CopyTo (string[] array, int arrayIndex) {values.CopyTo (array, arrayIndex);}
+ public bool Remove (string item) {return values.Remove (item);}
+ public int Count {get {return values.Count;}}
+ public bool IsReadOnly {get {return false;}}
+ #endregion
+
+ #region IEnumerable
+ IEnumerator IEnumerable.GetEnumerator () {return values.GetEnumerator ();}
+ #endregion
+
+ #region IEnumerable
+ public IEnumerator GetEnumerator () {return values.GetEnumerator ();}
+ #endregion
+
+ #region IList
+ int IList.Add (object value) {return (values as IList).Add (value);}
+ bool IList.Contains (object value) {return (values as IList).Contains (value);}
+ int IList.IndexOf (object value) {return (values as IList).IndexOf (value);}
+ void IList.Insert (int index, object value) {(values as IList).Insert (index, value);}
+ void IList.Remove (object value) {(values as IList).Remove (value);}
+ void IList.RemoveAt (int index) {(values as IList).RemoveAt (index);}
+ bool IList.IsFixedSize {get {return false;}}
+ object IList.this [int index] {get {return this [index];} set {(values as IList)[index] = value;}}
+ #endregion
+
+ #region IList
+ public int IndexOf (string item) {return values.IndexOf (item);}
+ public void Insert (int index, string item) {values.Insert (index, item);}
+ public void RemoveAt (int index) {values.RemoveAt (index);}
+
+ private void AssertValid (int index)
+ {
+ if (c.Option == null)
+ throw new InvalidOperationException ("OptionContext.Option is null.");
+ if (index >= c.Option.MaxValueCount)
+ throw new ArgumentOutOfRangeException (nameof(index));
+ if (c.Option.OptionValueType == OptionValueType.Required &&
+ index >= values.Count)
+ throw new OptionException (string.Format (
+ c.OptionSet.MessageLocalizer ("Missing required value for option '{0}'."), c.OptionName),
+ c.OptionName);
+ }
- public List ToList ()
- {
- return new List (values);
+ public string this [int index] {
+ get {
+ AssertValid (index);
+ return index >= values.Count ? null : values [index];
}
-
- public string[] ToArray ()
- {
- return values.ToArray ();
+ set {
+ values [index] = value;
}
+ }
+ #endregion
- public override string ToString ()
- {
- return string.Join (", ", values.ToArray ());
- }
+ public List ToList ()
+ {
+ return [..values];
}
- class OptionContext {
- private Option option;
- private string name;
- private int index;
- private OptionSet set;
- private OptionValueCollection c;
+ public string[] ToArray ()
+ {
+ return values.ToArray ();
+ }
- public OptionContext (OptionSet set)
- {
- this.set = set;
- this.c = new OptionValueCollection (this);
- }
+ public override string ToString ()
+ {
+ return string.Join (", ", values.ToArray ());
+ }
+}
- public Option Option {
- get {return option;}
- set {option = value;}
- }
+class OptionContext {
+ private Option option;
+ private string name;
+ private int index;
+ private OptionSet set;
+ private OptionValueCollection c;
- public string OptionName {
- get {return name;}
- set {name = value;}
- }
+ public OptionContext (OptionSet set)
+ {
+ this.set = set;
+ this.c = new OptionValueCollection (this);
+ }
- public int OptionIndex {
- get {return index;}
- set {index = value;}
- }
+ public Option Option {
+ get {return option;}
+ set {option = value;}
+ }
- public OptionSet OptionSet {
- get {return set;}
- }
+ public string OptionName {
+ get {return name;}
+ set {name = value;}
+ }
- public OptionValueCollection OptionValues {
- get {return c;}
- }
+ public int OptionIndex {
+ get {return index;}
+ set {index = value;}
}
- enum OptionValueType {
- None,
- Optional,
- Required,
+ public OptionSet OptionSet {
+ get {return set;}
}
- abstract class Option {
- string prototype, description;
- string[] names;
- OptionValueType type;
- int count;
- string[] separators;
- bool hidden;
+ public OptionValueCollection OptionValues {
+ get {return c;}
+ }
+}
- protected Option (string prototype, string description)
- : this (prototype, description, 1, false)
- {
- }
+enum OptionValueType {
+ None,
+ Optional,
+ Required,
+}
- protected Option (string prototype, string description, int maxValueCount)
- : this (prototype, description, maxValueCount, false)
- {
- }
+abstract class Option {
+ string prototype, description;
+ string[] names;
+ OptionValueType type;
+ int count;
+ string[] separators;
+ bool hidden;
- protected Option (string prototype, string description, int maxValueCount, bool hidden)
- {
- if (prototype == null)
- throw new ArgumentNullException (nameof(prototype));
- if (prototype.Length == 0)
- throw new ArgumentException ("Cannot be the empty string.", nameof(prototype));
- if (maxValueCount < 0)
- throw new ArgumentOutOfRangeException (nameof(maxValueCount));
-
- this.prototype = prototype;
- this.description = description;
- this.count = maxValueCount;
- this.names = (this is OptionSet.Category)
- // append GetHashCode() so that "duplicate" categories have distinct
- // names, e.g. adding multiple "" categories should be valid.
- ? new[]{prototype + this.GetHashCode ()}
- : prototype.Split ('|');
-
- if (this is OptionSet.Category)
- return;
-
- this.type = ParsePrototype ();
- this.hidden = hidden;
-
- if (this.count == 0 && type != OptionValueType.None)
- throw new ArgumentException (
- "Cannot provide maxValueCount of 0 for OptionValueType.Required or " +
- "OptionValueType.Optional.",
- nameof(maxValueCount));
- if (this.type == OptionValueType.None && maxValueCount > 1)
- throw new ArgumentException (
- string.Format ("Cannot provide maxValueCount of {0} for OptionValueType.None.", maxValueCount),
- nameof(maxValueCount));
- if (Array.IndexOf (names, "<>") >= 0 &&
- ((names.Length == 1 && this.type != OptionValueType.None) ||
- (names.Length > 1 && this.MaxValueCount > 1)))
- throw new ArgumentException (
- "The default option handler '<>' cannot require values.",
- nameof(prototype));
- }
+ protected Option (string prototype, string description)
+ : this (prototype, description, 1, false)
+ {
+ }
- public string Prototype {get {return prototype;}}
- public string Description {get {return description;}}
- public OptionValueType OptionValueType {get {return type;}}
- public int MaxValueCount {get {return count;}}
- public bool Hidden {get {return hidden;}}
+ protected Option (string prototype, string description, int maxValueCount)
+ : this (prototype, description, maxValueCount, false)
+ {
+ }
- public string[] GetNames ()
- {
- return (string[]) names.Clone ();
- }
+ protected Option (string prototype, string description, int maxValueCount, bool hidden)
+ {
+ if (prototype == null)
+ throw new ArgumentNullException (nameof(prototype));
+ if (prototype.Length == 0)
+ throw new ArgumentException ("Cannot be the empty string.", nameof(prototype));
+ if (maxValueCount < 0)
+ throw new ArgumentOutOfRangeException (nameof(maxValueCount));
+
+ this.prototype = prototype;
+ this.description = description;
+ this.count = maxValueCount;
+ this.names = (this is OptionSet.Category)
+ // append GetHashCode() so that "duplicate" categories have distinct
+ // names, e.g. adding multiple "" categories should be valid.
+ ? [prototype + this.GetHashCode ()]
+ : prototype.Split ('|');
+
+ if (this is OptionSet.Category)
+ return;
+
+ this.type = ParsePrototype ();
+ this.hidden = hidden;
+
+ if (this.count == 0 && type != OptionValueType.None)
+ throw new ArgumentException (
+ "Cannot provide maxValueCount of 0 for OptionValueType.Required or " +
+ "OptionValueType.Optional.",
+ nameof(maxValueCount));
+ if (this.type == OptionValueType.None && maxValueCount > 1)
+ throw new ArgumentException (
+ string.Format ("Cannot provide maxValueCount of {0} for OptionValueType.None.", maxValueCount),
+ nameof(maxValueCount));
+ if (Array.IndexOf (names, "<>") >= 0 &&
+ ((names.Length == 1 && this.type != OptionValueType.None) ||
+ (names.Length > 1 && this.MaxValueCount > 1)))
+ throw new ArgumentException (
+ "The default option handler '<>' cannot require values.",
+ nameof(prototype));
+ }
- public string[] GetValueSeparators ()
- {
- if (separators == null)
- return new string [0];
- return (string[]) separators.Clone ();
- }
+ public string Prototype {get {return prototype;}}
+ public string Description {get {return description;}}
+ public OptionValueType OptionValueType {get {return type;}}
+ public int MaxValueCount {get {return count;}}
+ public bool Hidden {get {return hidden;}}
- protected static T Parse (string value, OptionContext c)
- {
- var tt = typeof (T).GetTypeInfo();
- bool nullable = tt.IsValueType && tt.IsGenericType &&
- !tt.IsGenericTypeDefinition &&
- tt.GetGenericTypeDefinition () == typeof (Nullable<>);
- Type targetType = nullable ? tt.GetGenericArguments () [0] : typeof (T);
- T t = default (T);
- try {
- if (value != null)
- t = (T) Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture);
- }
- catch (Exception e) {
- throw new OptionException (
- string.Format (
- c.OptionSet.MessageLocalizer ("Could not convert string `{0}' to type {1} for option `{2}'."),
- value, targetType.Name, c.OptionName),
- c.OptionName, e);
- }
- return t;
- }
+ public string[] GetNames ()
+ {
+ return (string[]) names.Clone ();
+ }
- internal string[] Names {get {return names;}}
- internal string[] ValueSeparators {get {return separators;}}
+ public string[] GetValueSeparators ()
+ {
+ if (separators == null)
+ return new string [0];
+ return (string[]) separators.Clone ();
+ }
- static readonly char[] NameTerminator = new char[]{'=', ':'};
+ protected static T Parse (string value, OptionContext c)
+ {
+ var tt = typeof (T).GetTypeInfo();
+ bool nullable = tt.IsValueType && tt.IsGenericType &&
+ !tt.IsGenericTypeDefinition &&
+ tt.GetGenericTypeDefinition () == typeof (Nullable<>);
+ Type targetType = nullable ? tt.GetGenericArguments () [0] : typeof (T);
+ T t = default (T);
+ try {
+ if (value != null)
+ t = (T) Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture);
+ }
+ catch (Exception e) {
+ throw new OptionException (
+ string.Format (
+ c.OptionSet.MessageLocalizer ("Could not convert string `{0}' to type {1} for option `{2}'."),
+ value, targetType.Name, c.OptionName),
+ c.OptionName, e);
+ }
+ return t;
+ }
- private OptionValueType ParsePrototype ()
- {
- char type = '\0';
- List seps = new List ();
- for (int i = 0; i < names.Length; ++i) {
- string name = names [i];
- if (name.Length == 0)
- throw new ArgumentException ("Empty option names are not supported.", "prototype");
-
- int end = name.IndexOfAny (NameTerminator);
- if (end == -1)
- continue;
- names [i] = name.Substring (0, end);
- if (type == '\0' || type == name [end])
- type = name [end];
- else
- throw new ArgumentException (
- string.Format ("Conflicting option types: '{0}' vs. '{1}'.", type, name [end]),
- "prototype");
- AddSeparators (name, end, seps);
- }
+ internal string[] Names {get {return names;}}
+ internal string[] ValueSeparators {get {return separators;}}
- if (type == '\0')
- return OptionValueType.None;
+ static readonly char[] NameTerminator = ['=', ':'];
- if (count <= 1 && seps.Count != 0)
+ private OptionValueType ParsePrototype ()
+ {
+ char type = '\0';
+ List seps = [];
+ for (int i = 0; i < names.Length; ++i) {
+ string name = names [i];
+ if (name.Length == 0)
+ throw new ArgumentException ("Empty option names are not supported.", "prototype");
+
+ int end = name.IndexOfAny (NameTerminator);
+ if (end == -1)
+ continue;
+ names [i] = name.Substring (0, end);
+ if (type == '\0' || type == name [end])
+ type = name [end];
+ else
throw new ArgumentException (
- string.Format ("Cannot provide key/value separators for Options taking {0} value(s).", count),
- "prototype");
- if (count > 1) {
- if (seps.Count == 0)
- this.separators = new string[]{":", "="};
- else if (seps.Count == 1 && seps [0].Length == 0)
- this.separators = null;
- else
- this.separators = seps.ToArray ();
- }
-
- return type == '=' ? OptionValueType.Required : OptionValueType.Optional;
+ string.Format ("Conflicting option types: '{0}' vs. '{1}'.", type, name [end]),
+ "prototype");
+ AddSeparators (name, end, seps);
+ }
+
+ if (type == '\0')
+ return OptionValueType.None;
+
+ if (count <= 1 && seps.Count != 0)
+ throw new ArgumentException (
+ string.Format ("Cannot provide key/value separators for Options taking {0} value(s).", count),
+ "prototype");
+ if (count > 1) {
+ if (seps.Count == 0)
+ this.separators = [":", "="];
+ else if (seps.Count == 1 && seps [0].Length == 0)
+ this.separators = null;
+ else
+ this.separators = seps.ToArray ();
}
- private static void AddSeparators (string name, int end, ICollection seps)
- {
- int start = -1;
- for (int i = end+1; i < name.Length; ++i) {
- switch (name [i]) {
- case '{':
- if (start != -1)
- throw new ArgumentException (
- string.Format ("Ill-formed name/value separator found in \"{0}\".", name),
- "prototype");
- start = i+1;
- break;
- case '}':
- if (start == -1)
- throw new ArgumentException (
- string.Format ("Ill-formed name/value separator found in \"{0}\".", name),
- "prototype");
- seps.Add (name.Substring (start, i-start));
- start = -1;
- break;
- default:
- if (start == -1)
- seps.Add (name [i].ToString ());
- break;
- }
+ return type == '=' ? OptionValueType.Required : OptionValueType.Optional;
+ }
+
+ private static void AddSeparators (string name, int end, ICollection seps)
+ {
+ int start = -1;
+ for (int i = end+1; i < name.Length; ++i) {
+ switch (name [i]) {
+ case '{':
+ if (start != -1)
+ throw new ArgumentException (
+ string.Format ("Ill-formed name/value separator found in \"{0}\".", name),
+ "prototype");
+ start = i+1;
+ break;
+ case '}':
+ if (start == -1)
+ throw new ArgumentException (
+ string.Format ("Ill-formed name/value separator found in \"{0}\".", name),
+ "prototype");
+ seps.Add (name.Substring (start, i-start));
+ start = -1;
+ break;
+ default:
+ if (start == -1)
+ seps.Add (name [i].ToString ());
+ break;
}
- if (start != -1)
- throw new ArgumentException (
- string.Format ("Ill-formed name/value separator found in \"{0}\".", name),
- "prototype");
}
+ if (start != -1)
+ throw new ArgumentException (
+ string.Format ("Ill-formed name/value separator found in \"{0}\".", name),
+ "prototype");
+ }
- public void Invoke (OptionContext c)
- {
- OnParseComplete (c);
- c.OptionName = null;
- c.Option = null;
- c.OptionValues.Clear ();
- }
+ public void Invoke (OptionContext c)
+ {
+ OnParseComplete (c);
+ c.OptionName = null;
+ c.Option = null;
+ c.OptionValues.Clear ();
+ }
- protected abstract void OnParseComplete (OptionContext c);
+ protected abstract void OnParseComplete (OptionContext c);
- public override string ToString ()
- {
- return Prototype;
- }
+ public override string ToString ()
+ {
+ return Prototype;
}
+}
- abstract class ArgumentSource {
+abstract class ArgumentSource {
- protected ArgumentSource ()
- {
- }
+ protected ArgumentSource ()
+ {
+ }
- public abstract string[] GetNames ();
- public abstract string Description { get; }
- public abstract bool GetArguments (string value, out IEnumerable replacement);
+ public abstract string[] GetNames ();
+ public abstract string Description { get; }
+ public abstract bool GetArguments (string value, out IEnumerable replacement);
- public static IEnumerable GetArgumentsFromFile (string file)
- {
- return GetArguments (File.OpenText (file), true);
- }
+ public static IEnumerable GetArgumentsFromFile (string file)
+ {
+ return GetArguments (File.OpenText (file), true);
+ }
- public static IEnumerable GetArguments (TextReader reader)
- {
- return GetArguments (reader, false);
- }
+ public static IEnumerable GetArguments (TextReader reader)
+ {
+ return GetArguments (reader, false);
+ }
- // Cribbed from mcs/driver.cs:LoadArgs(string)
- static IEnumerable GetArguments (TextReader reader, bool close)
- {
- try {
- StringBuilder arg = new StringBuilder ();
+ // Cribbed from mcs/driver.cs:LoadArgs(string)
+ static IEnumerable GetArguments (TextReader reader, bool close)
+ {
+ try {
+ StringBuilder arg = new StringBuilder ();
- string line;
- while ((line = reader.ReadLine ()) != null) {
- int t = line.Length;
+ string line;
+ while ((line = reader.ReadLine ()) != null) {
+ int t = line.Length;
- for (int i = 0; i < t; i++) {
- char c = line [i];
+ for (int i = 0; i < t; i++) {
+ char c = line [i];
- if (c == '"' || c == '\'') {
- char end = c;
+ if (c == '"' || c == '\'') {
+ char end = c;
- for (i++; i < t; i++){
- c = line [i];
-
- if (c == end)
- break;
- arg.Append (c);
- }
- } else if (c == ' ') {
- if (arg.Length > 0) {
- yield return arg.ToString ();
- arg.Length = 0;
- }
- } else
+ for (i++; i < t; i++){
+ c = line [i];
+
+ if (c == end)
+ break;
arg.Append (c);
- }
- if (arg.Length > 0) {
- yield return arg.ToString ();
- arg.Length = 0;
- }
+ }
+ } else if (c == ' ') {
+ if (arg.Length > 0) {
+ yield return arg.ToString ();
+ arg.Length = 0;
+ }
+ } else
+ arg.Append (c);
+ }
+ if (arg.Length > 0) {
+ yield return arg.ToString ();
+ arg.Length = 0;
}
}
- finally {
- if (close)
- reader.Dispose();
- }
+ }
+ finally {
+ if (close)
+ reader.Dispose();
}
}
+}
- class ResponseFileSource : ArgumentSource {
+class ResponseFileSource : ArgumentSource {
- public override string[] GetNames ()
- {
- return new string[]{"@file"};
- }
+ public override string[] GetNames ()
+ {
+ return ["@file"];
+ }
- public override string Description {
- get {return "Read response file for more options.";}
- }
+ public override string Description {
+ get {return "Read response file for more options.";}
+ }
- public override bool GetArguments (string value, out IEnumerable replacement)
- {
- if (string.IsNullOrEmpty (value) || !value.StartsWith ("@")) {
- replacement = null;
- return false;
- }
- replacement = ArgumentSource.GetArgumentsFromFile (value.Substring (1));
- return true;
+ public override bool GetArguments (string value, out IEnumerable replacement)
+ {
+ if (string.IsNullOrEmpty (value) || !value.StartsWith ("@")) {
+ replacement = null;
+ return false;
}
+ replacement = ArgumentSource.GetArgumentsFromFile (value.Substring (1));
+ return true;
}
+}
- class OptionException : Exception {
- private string option;
+class OptionException : Exception {
+ private string option;
- public OptionException ()
- {
- }
+ public OptionException ()
+ {
+ }
- public OptionException (string message, string optionName)
- : base (message)
- {
- this.option = optionName;
- }
+ public OptionException (string message, string optionName)
+ : base (message)
+ {
+ this.option = optionName;
+ }
- public OptionException (string message, string optionName, Exception innerException)
- : base (message, innerException)
- {
- this.option = optionName;
- }
+ public OptionException (string message, string optionName, Exception innerException)
+ : base (message, innerException)
+ {
+ this.option = optionName;
+ }
- public string OptionName {
- get {return this.option;}
- }
+ public string OptionName {
+ get {return this.option;}
}
+}
- delegate void OptionAction (TKey key, TValue value);
+delegate void OptionAction (TKey key, TValue value);
- class OptionSet : KeyedCollection
+class OptionSet : KeyedCollection
+{
+ public OptionSet ()
+ : this (delegate (string f) {return f;})
{
- public OptionSet ()
- : this (delegate (string f) {return f;})
- {
- }
+ }
- public OptionSet (Converter localizer)
- {
- this.localizer = localizer;
- this.roSources = new ReadOnlyCollection(sources);
- }
+ public OptionSet (Converter localizer)
+ {
+ this.localizer = localizer;
+ this.roSources = new ReadOnlyCollection(sources);
+ }
- Converter localizer;
+ Converter localizer;
- public Converter MessageLocalizer {
- get {return localizer;}
- }
+ public Converter MessageLocalizer {
+ get {return localizer;}
+ }
+
+ List sources = [];
+ ReadOnlyCollection roSources;
- List sources = new List ();
- ReadOnlyCollection roSources;
+ public ReadOnlyCollection ArgumentSources {
+ get {return roSources;}
+ }
- public ReadOnlyCollection ArgumentSources {
- get {return roSources;}
+
+ protected override string GetKeyForItem (Option item)
+ {
+ if (item == null)
+ throw new ArgumentNullException ("option");
+ if (item.Names != null && item.Names.Length > 0)
+ return item.Names [0];
+ // This should never happen, as it's invalid for Option to be
+ // constructed w/o any names.
+ throw new InvalidOperationException ("Option has no names!");
+ }
+
+ [Obsolete ("Use KeyedCollection.this[string]")]
+ protected Option GetOptionForName (string option)
+ {
+ if (option == null)
+ throw new ArgumentNullException (nameof(option));
+ try {
+ return base [option];
+ }
+ catch (KeyNotFoundException) {
+ return null;
}
+ }
+ protected override void InsertItem (int index, Option item)
+ {
+ base.InsertItem (index, item);
+ AddImpl (item);
+ }
- protected override string GetKeyForItem (Option item)
- {
- if (item == null)
- throw new ArgumentNullException ("option");
- if (item.Names != null && item.Names.Length > 0)
- return item.Names [0];
- // This should never happen, as it's invalid for Option to be
- // constructed w/o any names.
- throw new InvalidOperationException ("Option has no names!");
+ protected override void RemoveItem (int index)
+ {
+ Option p = Items [index];
+ base.RemoveItem (index);
+ // KeyedCollection.RemoveItem() handles the 0th item
+ for (int i = 1; i < p.Names.Length; ++i) {
+ Dictionary.Remove (p.Names [i]);
}
+ }
- [Obsolete ("Use KeyedCollection.this[string]")]
- protected Option GetOptionForName (string option)
- {
- if (option == null)
- throw new ArgumentNullException (nameof(option));
- try {
- return base [option];
- }
- catch (KeyNotFoundException) {
- return null;
+ protected override void SetItem (int index, Option item)
+ {
+ base.SetItem (index, item);
+ AddImpl (item);
+ }
+
+ private void AddImpl (Option option)
+ {
+ if (option == null)
+ throw new ArgumentNullException (nameof(option));
+ List added = new List (option.Names.Length);
+ try {
+ // KeyedCollection.InsertItem/SetItem handle the 0th name.
+ for (int i = 1; i < option.Names.Length; ++i) {
+ Dictionary.Add (option.Names [i], option);
+ added.Add (option.Names [i]);
}
}
+ catch (Exception) {
+ foreach (string name in added)
+ Dictionary.Remove (name);
+ throw;
+ }
+ }
+
+ public OptionSet Add (string header)
+ {
+ if (header == null)
+ throw new ArgumentNullException (nameof(header));
+ Add (new Category (header));
+ return this;
+ }
- protected override void InsertItem (int index, Option item)
+ internal sealed class Category : Option {
+
+ // Prototype starts with '=' because this is an invalid prototype
+ // (see Option.ParsePrototype(), and thus it'll prevent Category
+ // instances from being accidentally used as normal options.
+ public Category (string description)
+ : base ("=:Category:= " + description, description)
{
- base.InsertItem (index, item);
- AddImpl (item);
}
- protected override void RemoveItem (int index)
+ protected override void OnParseComplete (OptionContext c)
{
- Option p = Items [index];
- base.RemoveItem (index);
- // KeyedCollection.RemoveItem() handles the 0th item
- for (int i = 1; i < p.Names.Length; ++i) {
- Dictionary.Remove (p.Names [i]);
- }
+ throw new NotSupportedException ("Category.OnParseComplete should not be invoked.");
}
+ }
- protected override void SetItem (int index, Option item)
+
+ public new OptionSet Add (Option option)
+ {
+ base.Add (option);
+ return this;
+ }
+
+ sealed class ActionOption : Option {
+ Action action;
+
+ public ActionOption (string prototype, string description, int count, Action action)
+ : this (prototype, description, count, action, false)
{
- base.SetItem (index, item);
- AddImpl (item);
}
- private void AddImpl (Option option)
+ public ActionOption (string prototype, string description, int count, Action action, bool hidden)
+ : base (prototype, description, count, hidden)
{
- if (option == null)
- throw new ArgumentNullException (nameof(option));
- List added = new List (option.Names.Length);
- try {
- // KeyedCollection.InsertItem/SetItem handle the 0th name.
- for (int i = 1; i < option.Names.Length; ++i) {
- Dictionary.Add (option.Names [i], option);
- added.Add (option.Names [i]);
- }
- }
- catch (Exception) {
- foreach (string name in added)
- Dictionary.Remove (name);
- throw;
- }
+ this.action = action ?? throw new ArgumentNullException (nameof(action));
}
- public OptionSet Add (string header)
+ protected override void OnParseComplete (OptionContext c)
{
- if (header == null)
- throw new ArgumentNullException (nameof(header));
- Add (new Category (header));
- return this;
+ action (c.OptionValues);
}
+ }
- internal sealed class Category : Option {
+ public OptionSet Add (string prototype, Action action)
+ {
+ return Add (prototype, null, action);
+ }
- // Prototype starts with '=' because this is an invalid prototype
- // (see Option.ParsePrototype(), and thus it'll prevent Category
- // instances from being accidentally used as normal options.
- public Category (string description)
- : base ("=:Category:= " + description, description)
- {
- }
+ public OptionSet Add (string prototype, string description, Action action)
+ {
+ return Add (prototype, description, action, false);
+ }
- protected override void OnParseComplete (OptionContext c)
+ public OptionSet Add (string prototype, string description, Action action, bool hidden)
+ {
+ if (action == null)
+ throw new ArgumentNullException (nameof(action));
+ Option p = new ActionOption (prototype, description, 1,
+ delegate (OptionValueCollection v)
{
- throw new NotSupportedException ("Category.OnParseComplete should not be invoked.");
- }
- }
-
-
- public new OptionSet Add (Option option)
- {
- base.Add (option);
- return this;
- }
+ var v0 = v[0];
+ if (!string.IsNullOrWhiteSpace(v0))
+ {
+ action(v0);
+ }
+ }, hidden);
+ base.Add (p);
+ return this;
+ }
- sealed class ActionOption : Option {
- Action action;
+ public OptionSet Add (string prototype, OptionAction action)
+ {
+ return Add (prototype, null, action);
+ }
- public ActionOption (string prototype, string description, int count, Action action)
- : this (prototype, description, count, action, false)
- {
- }
+ public OptionSet Add (string prototype, string description, OptionAction action)
+ {
+ return Add (prototype, description, action, false);
+ }
- public ActionOption (string prototype, string description, int count, Action action, bool hidden)
- : base (prototype, description, count, hidden)
- {
- this.action = action ?? throw new ArgumentNullException (nameof(action));
- }
+ public OptionSet Add (string prototype, string description, OptionAction action, bool hidden) {
+ if (action == null)
+ throw new ArgumentNullException (nameof(action));
+ Option p = new ActionOption (prototype, description, 2,
+ delegate (OptionValueCollection v) {action (v [0], v [1]);}, hidden);
+ base.Add (p);
+ return this;
+ }
- protected override void OnParseComplete (OptionContext c)
- {
- action (c.OptionValues);
- }
- }
+ sealed class ActionOption : Option {
+ Action action;
- public OptionSet Add (string prototype, Action action)
+ public ActionOption (string prototype, string description, Action action)
+ : base (prototype, description, 1)
{
- return Add (prototype, null, action);
+ this.action = action ?? throw new ArgumentNullException (nameof(action));
}
- public OptionSet Add (string prototype, string description, Action action)
+ protected override void OnParseComplete (OptionContext c)
{
- return Add (prototype, description, action, false);
+ action (Parse (c.OptionValues [0], c));
}
+ }
- public OptionSet Add (string prototype, string description, Action action, bool hidden)
- {
- if (action == null)
- throw new ArgumentNullException (nameof(action));
- Option p = new ActionOption (prototype, description, 1,
- delegate (OptionValueCollection v)
- {
- var v0 = v[0];
- if (!string.IsNullOrWhiteSpace(v0))
- {
- action(v0);
- }
- }, hidden);
- base.Add (p);
- return this;
- }
+ sealed class ActionOption : Option {
+ OptionAction action;
- public OptionSet Add (string prototype, OptionAction action)
+ public ActionOption (string prototype, string description, OptionAction action)
+ : base (prototype, description, 2)
{
- return Add (prototype, null, action);
+ this.action = action ?? throw new ArgumentNullException (nameof(action));
}
- public OptionSet Add (string prototype, string description, OptionAction action)
+ protected override void OnParseComplete (OptionContext c)
{
- return Add (prototype, description, action, false);
+ action (
+ Parse (c.OptionValues [0], c),
+ Parse (c.OptionValues [1], c));
}
+ }
- public OptionSet Add (string prototype, string description, OptionAction action, bool hidden) {
- if (action == null)
- throw new ArgumentNullException (nameof(action));
- Option p = new ActionOption (prototype, description, 2,
- delegate (OptionValueCollection v) {action (v [0], v [1]);}, hidden);
- base.Add (p);
- return this;
- }
+ public OptionSet Add (string prototype, Action action)
+ {
+ return Add (prototype, null, action);
+ }
- sealed class ActionOption : Option {
- Action action;
+ public OptionSet Add (string prototype, string description, Action action)
+ {
+ return Add (new ActionOption (prototype, description, action));
+ }
- public ActionOption (string prototype, string description, Action action)
- : base (prototype, description, 1)
- {
- this.action = action ?? throw new ArgumentNullException (nameof(action));
- }
+ public OptionSet Add (string prototype, OptionAction action)
+ {
+ return Add (prototype, null, action);
+ }
- protected override void OnParseComplete (OptionContext c)
- {
- action (Parse (c.OptionValues [0], c));
- }
- }
+ public OptionSet Add (string prototype, string description, OptionAction action)
+ {
+ return Add (new ActionOption (prototype, description, action));
+ }
- sealed class ActionOption : Option {
- OptionAction action;
+ public OptionSet Add (ArgumentSource source)
+ {
+ if (source == null)
+ throw new ArgumentNullException (nameof(source));
+ sources.Add (source);
+ return this;
+ }
- public ActionOption (string prototype, string description, OptionAction action)
- : base (prototype, description, 2)
- {
- this.action = action ?? throw new ArgumentNullException (nameof(action));
- }
+ protected virtual OptionContext CreateOptionContext ()
+ {
+ return new OptionContext (this);
+ }
- protected override void OnParseComplete (OptionContext c)
- {
- action (
- Parse (c.OptionValues [0], c),
- Parse (c.OptionValues [1], c));
+ public List Parse (IEnumerable arguments)
+ {
+ if (arguments == null)
+ throw new ArgumentNullException (nameof(arguments));
+ OptionContext c = CreateOptionContext ();
+ c.OptionIndex = -1;
+ bool process = true;
+ List unprocessed = [];
+ Option def = Contains ("<>") ? this ["<>"] : null;
+ ArgumentEnumerator ae = new ArgumentEnumerator (arguments);
+ foreach (string argument in ae) {
+ ++c.OptionIndex;
+ if (argument == "--") {
+ process = false;
+ continue;
}
+ if (!process) {
+ Unprocessed (unprocessed, def, c, argument);
+ continue;
+ }
+ if (AddSource (ae, argument))
+ continue;
+ if (!Parse (argument, c))
+ Unprocessed (unprocessed, def, c, argument);
}
+ if (c.Option != null)
+ c.Option.Invoke (c);
+ return unprocessed;
+ }
- public OptionSet Add (string prototype, Action action)
- {
- return Add (prototype, null, action);
- }
+ class ArgumentEnumerator : IEnumerable {
+ List> sources = [];
- public OptionSet Add (string prototype, string description, Action action)
+ public ArgumentEnumerator (IEnumerable arguments)
{
- return Add (new ActionOption (prototype, description, action));
+ sources.Add (arguments.GetEnumerator ());
}
- public OptionSet Add (string prototype, OptionAction action)
+ public void Add (IEnumerable arguments)
{
- return Add (prototype, null, action);
+ sources.Add (arguments.GetEnumerator ());
}
- public OptionSet Add (string prototype, string description, OptionAction action)
+ public IEnumerator GetEnumerator ()
{
- return Add (new ActionOption (prototype, description, action));
+ do {
+ IEnumerator c = sources [sources.Count-1];
+ if (c.MoveNext ())
+ yield return c.Current;
+ else {
+ c.Dispose ();
+ sources.RemoveAt (sources.Count-1);
+ }
+ } while (sources.Count > 0);
}
- public OptionSet Add (ArgumentSource source)
+ IEnumerator IEnumerable.GetEnumerator ()
{
- if (source == null)
- throw new ArgumentNullException (nameof(source));
- sources.Add (source);
- return this;
+ return GetEnumerator ();
}
+ }
- protected virtual OptionContext CreateOptionContext ()
- {
- return new OptionContext (this);
+ bool AddSource (ArgumentEnumerator ae, string argument)
+ {
+ foreach (ArgumentSource source in sources) {
+ IEnumerable replacement;
+ if (!source.GetArguments (argument, out replacement))
+ continue;
+ ae.Add (replacement);
+ return true;
}
+ return false;
+ }
- public List Parse (IEnumerable arguments)
- {
- if (arguments == null)
- throw new ArgumentNullException (nameof(arguments));
- OptionContext c = CreateOptionContext ();
- c.OptionIndex = -1;
- bool process = true;
- List unprocessed = new List ();
- Option def = Contains ("<>") ? this ["<>"] : null;
- ArgumentEnumerator ae = new ArgumentEnumerator (arguments);
- foreach (string argument in ae) {
- ++c.OptionIndex;
- if (argument == "--") {
- process = false;
- continue;
- }
- if (!process) {
- Unprocessed (unprocessed, def, c, argument);
- continue;
- }
- if (AddSource (ae, argument))
- continue;
- if (!Parse (argument, c))
- Unprocessed (unprocessed, def, c, argument);
- }
- if (c.Option != null)
- c.Option.Invoke (c);
- return unprocessed;
+ private static bool Unprocessed (ICollection extra, Option def, OptionContext c, string argument)
+ {
+ if (def == null) {
+ extra.Add (argument);
+ return false;
}
+ c.OptionValues.Add (argument);
+ c.Option = def;
+ c.Option.Invoke (c);
+ return false;
+ }
- class ArgumentEnumerator : IEnumerable {
- List> sources = new List> ();
-
- public ArgumentEnumerator (IEnumerable arguments)
- {
- sources.Add (arguments.GetEnumerator ());
- }
-
- public void Add (IEnumerable arguments)
- {
- sources.Add (arguments.GetEnumerator ());
- }
-
- public IEnumerator GetEnumerator ()
- {
- do {
- IEnumerator c = sources [sources.Count-1];
- if (c.MoveNext ())
- yield return c.Current;
- else {
- c.Dispose ();
- sources.RemoveAt (sources.Count-1);
- }
- } while (sources.Count > 0);
- }
+ private readonly Regex ValueOption = new(
+ @"^(?--|-|/)(?[^:=]+)((?[:=])(?.*))?$");
- IEnumerator IEnumerable.GetEnumerator ()
- {
- return GetEnumerator ();
- }
- }
+ protected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value)
+ {
+ if (argument == null)
+ throw new ArgumentNullException (nameof(argument));
- bool AddSource (ArgumentEnumerator ae, string argument)
- {
- foreach (ArgumentSource source in sources) {
- IEnumerable replacement;
- if (!source.GetArguments (argument, out replacement))
- continue;
- ae.Add (replacement);
- return true;
- }
+ flag = name = sep = value = null;
+ Match m = ValueOption.Match (argument);
+ if (!m.Success) {
return false;
}
-
- private static bool Unprocessed (ICollection extra, Option def, OptionContext c, string argument)
- {
- if (def == null) {
- extra.Add (argument);
- return false;
- }
- c.OptionValues.Add (argument);
- c.Option = def;
- c.Option.Invoke (c);
- return false;
+ flag = m.Groups ["flag"].Value;
+ name = m.Groups ["name"].Value;
+ if (m.Groups ["sep"].Success && m.Groups ["value"].Success) {
+ sep = m.Groups ["sep"].Value;
+ value = m.Groups ["value"].Value;
}
+ return true;
+ }
- private readonly Regex ValueOption = new Regex (
- @"^(?--|-|/)(?[^:=]+)((?[:=])(?.*))?$");
+ protected virtual bool Parse (string argument, OptionContext c)
+ {
+ if (c.Option != null) {
+ ParseValue (argument, c);
+ return true;
+ }
- protected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value)
- {
- if (argument == null)
- throw new ArgumentNullException (nameof(argument));
+ string f, n, s, v;
+ if (!GetOptionParts (argument, out f, out n, out s, out v))
+ return false;
- flag = name = sep = value = null;
- Match m = ValueOption.Match (argument);
- if (!m.Success) {
- return false;
- }
- flag = m.Groups ["flag"].Value;
- name = m.Groups ["name"].Value;
- if (m.Groups ["sep"].Success && m.Groups ["value"].Success) {
- sep = m.Groups ["sep"].Value;
- value = m.Groups ["value"].Value;
+ Option p;
+ if (Contains (n)) {
+ p = this [n];
+ c.OptionName = f + n;
+ c.Option = p;
+ switch (p.OptionValueType) {
+ case OptionValueType.None:
+ c.OptionValues.Add (n);
+ c.Option.Invoke (c);
+ break;
+ case OptionValueType.Optional:
+ case OptionValueType.Required:
+ ParseValue (v, c);
+ break;
}
return true;
}
+ // no match; is it a bool option?
+ if (ParseBool (argument, n, c))
+ return true;
+ // is it a bundled option?
+ if (ParseBundledValue (f, string.Concat (n + s + v), c))
+ return true;
- protected virtual bool Parse (string argument, OptionContext c)
- {
- if (c.Option != null) {
- ParseValue (argument, c);
- return true;
- }
-
- string f, n, s, v;
- if (!GetOptionParts (argument, out f, out n, out s, out v))
- return false;
+ return false;
+ }
- Option p;
- if (Contains (n)) {
- p = this [n];
- c.OptionName = f + n;
- c.Option = p;
- switch (p.OptionValueType) {
- case OptionValueType.None:
- c.OptionValues.Add (n);
- c.Option.Invoke (c);
- break;
- case OptionValueType.Optional:
- case OptionValueType.Required:
- ParseValue (v, c);
- break;
- }
- return true;
+ private void ParseValue (string option, OptionContext c)
+ {
+ if (option != null)
+ foreach (string o in c.Option.ValueSeparators != null
+ ? option.Split (c.Option.ValueSeparators, c.Option.MaxValueCount - c.OptionValues.Count, StringSplitOptions.None)
+ : [option]) {
+ c.OptionValues.Add (o);
}
- // no match; is it a bool option?
- if (ParseBool (argument, n, c))
- return true;
- // is it a bundled option?
- if (ParseBundledValue (f, string.Concat (n + s + v), c))
- return true;
-
- return false;
+ if (c.OptionValues.Count == c.Option.MaxValueCount ||
+ c.Option.OptionValueType == OptionValueType.Optional)
+ c.Option.Invoke (c);
+ else if (c.OptionValues.Count > c.Option.MaxValueCount) {
+ throw new OptionException (localizer (string.Format (
+ "Error: Found {0} option values when expecting {1}.",
+ c.OptionValues.Count, c.Option.MaxValueCount)),
+ c.OptionName);
}
+ }
- private void ParseValue (string option, OptionContext c)
- {
- if (option != null)
- foreach (string o in c.Option.ValueSeparators != null
- ? option.Split (c.Option.ValueSeparators, c.Option.MaxValueCount - c.OptionValues.Count, StringSplitOptions.None)
- : new string[]{option}) {
- c.OptionValues.Add (o);
- }
- if (c.OptionValues.Count == c.Option.MaxValueCount ||
- c.Option.OptionValueType == OptionValueType.Optional)
- c.Option.Invoke (c);
- else if (c.OptionValues.Count > c.Option.MaxValueCount) {
- throw new OptionException (localizer (string.Format (
- "Error: Found {0} option values when expecting {1}.",
- c.OptionValues.Count, c.Option.MaxValueCount)),
- c.OptionName);
- }
+ private bool ParseBool (string option, string n, OptionContext c)
+ {
+ Option p;
+ string rn;
+ if (n.Length >= 1 && (n [n.Length-1] == '+' || n [n.Length-1] == '-') &&
+ Contains ((rn = n.Substring (0, n.Length-1)))) {
+ p = this [rn];
+ string v = n [n.Length-1] == '+' ? option : null;
+ c.OptionName = option;
+ c.Option = p;
+ c.OptionValues.Add (v);
+ p.Invoke (c);
+ return true;
}
+ return false;
+ }
- private bool ParseBool (string option, string n, OptionContext c)
- {
+ private bool ParseBundledValue (string f, string n, OptionContext c)
+ {
+ if (f != "-")
+ return false;
+ for (int i = 0; i < n.Length; ++i) {
Option p;
- string rn;
- if (n.Length >= 1 && (n [n.Length-1] == '+' || n [n.Length-1] == '-') &&
- Contains ((rn = n.Substring (0, n.Length-1)))) {
- p = this [rn];
- string v = n [n.Length-1] == '+' ? option : null;
- c.OptionName = option;
- c.Option = p;
- c.OptionValues.Add (v);
- p.Invoke (c);
- return true;
+ string opt = f + n [i].ToString ();
+ string rn = n [i].ToString ();
+ if (!Contains (rn)) {
+ if (i == 0)
+ return false;
+ throw new OptionException (string.Format (localizer (
+ "Cannot bundle unregistered option '{0}'."), opt), opt);
}
- return false;
- }
-
- private bool ParseBundledValue (string f, string n, OptionContext c)
- {
- if (f != "-")
- return false;
- for (int i = 0; i < n.Length; ++i) {
- Option p;
- string opt = f + n [i].ToString ();
- string rn = n [i].ToString ();
- if (!Contains (rn)) {
- if (i == 0)
- return false;
- throw new OptionException (string.Format (localizer (
- "Cannot bundle unregistered option '{0}'."), opt), opt);
- }
- p = this [rn];
- switch (p.OptionValueType) {
- case OptionValueType.None:
- Invoke (c, opt, n, p);
- break;
- case OptionValueType.Optional:
- case OptionValueType.Required: {
- string v = n.Substring (i+1);
- c.Option = p;
- c.OptionName = opt;
- ParseValue (v.Length != 0 ? v : null, c);
- return true;
- }
- default:
- throw new InvalidOperationException ("Unknown OptionValueType: " + p.OptionValueType);
+ p = this [rn];
+ switch (p.OptionValueType) {
+ case OptionValueType.None:
+ Invoke (c, opt, n, p);
+ break;
+ case OptionValueType.Optional:
+ case OptionValueType.Required: {
+ string v = n.Substring (i+1);
+ c.Option = p;
+ c.OptionName = opt;
+ ParseValue (v.Length != 0 ? v : null, c);
+ return true;
}
+ default:
+ throw new InvalidOperationException ("Unknown OptionValueType: " + p.OptionValueType);
}
- return true;
- }
-
- private static void Invoke (OptionContext c, string name, string value, Option option)
- {
- c.OptionName = name;
- c.Option = option;
- c.OptionValues.Add (value);
- option.Invoke (c);
}
+ return true;
+ }
- private const int OptionWidth = 29;
- private const int Description_FirstWidth = 80 - OptionWidth;
- private const int Description_RemWidth = 80 - OptionWidth - 2;
+ private static void Invoke (OptionContext c, string name, string value, Option option)
+ {
+ c.OptionName = name;
+ c.Option = option;
+ c.OptionValues.Add (value);
+ option.Invoke (c);
+ }
- public void WriteOptionDescriptions (TextWriter o)
- {
- foreach (Option p in this) {
- int written = 0;
+ private const int OptionWidth = 29;
+ private const int Description_FirstWidth = 80 - OptionWidth;
+ private const int Description_RemWidth = 80 - OptionWidth - 2;
- if (p.Hidden)
- continue;
+ public void WriteOptionDescriptions (TextWriter o)
+ {
+ foreach (Option p in this) {
+ int written = 0;
- Category c = p as Category;
- if (c != null) {
- WriteDescription (o, p.Description, "", 80, 80);
- continue;
- }
+ if (p.Hidden)
+ continue;
- if (!WriteOptionPrototype (o, p, ref written))
- continue;
+ Category c = p as Category;
+ if (c != null) {
+ WriteDescription (o, p.Description, "", 80, 80);
+ continue;
+ }
- if (written < OptionWidth)
- o.Write (new string (' ', OptionWidth - written));
- else {
- o.WriteLine ();
- o.Write (new string (' ', OptionWidth));
- }
+ if (!WriteOptionPrototype (o, p, ref written))
+ continue;
- WriteDescription (o, p.Description, new string (' ', OptionWidth+2),
- Description_FirstWidth -1, Description_RemWidth - 2);
+ if (written < OptionWidth)
+ o.Write (new string (' ', OptionWidth - written));
+ else {
+ o.WriteLine ();
+ o.Write (new string (' ', OptionWidth));
}
- foreach (ArgumentSource s in sources) {
- string[] names = s.GetNames ();
- if (names == null || names.Length == 0)
- continue;
+ WriteDescription (o, p.Description, new string (' ', OptionWidth+2),
+ Description_FirstWidth -1, Description_RemWidth - 2);
+ }
- int written = 0;
+ foreach (ArgumentSource s in sources) {
+ string[] names = s.GetNames ();
+ if (names == null || names.Length == 0)
+ continue;
- Write (o, ref written, " ");
- Write (o, ref written, names [0]);
- for (int i = 1; i < names.Length; ++i) {
- Write (o, ref written, ", ");
- Write (o, ref written, names [i]);
- }
+ int written = 0;
- if (written < OptionWidth)
- o.Write (new string (' ', OptionWidth - written));
- else {
- o.WriteLine ();
- o.Write (new string (' ', OptionWidth));
- }
-
- WriteDescription (o, s.Description, new string (' ', OptionWidth+2),
- Description_FirstWidth, Description_RemWidth);
+ Write (o, ref written, " ");
+ Write (o, ref written, names [0]);
+ for (int i = 1; i < names.Length; ++i) {
+ Write (o, ref written, ", ");
+ Write (o, ref written, names [i]);
}
- }
- void WriteDescription (TextWriter o, string value, string prefix, int firstWidth, int remWidth)
- {
- bool indent = false;
- foreach (string line in GetLines (localizer (GetDescription (value)), firstWidth, remWidth)) {
- if (indent)
- o.Write (prefix);
- o.WriteLine (line);
- indent = true;
+ if (written < OptionWidth)
+ o.Write (new string (' ', OptionWidth - written));
+ else {
+ o.WriteLine ();
+ o.Write (new string (' ', OptionWidth));
}
+
+ WriteDescription (o, s.Description, new string (' ', OptionWidth+2),
+ Description_FirstWidth, Description_RemWidth);
}
+ }
- public bool WriteOptionPrototype (TextWriter o, Option p, ref int written, bool markdown = false)
- {
- string[] names = p.Names;
-
- int i = GetNextOptionIndex (names, 0);
- if (i == names.Length)
- return false;
-
- if (names [i].Length == 1) {
- if (markdown)
- Write(o, ref written, "`-");
- else
- Write(o, ref written, " -");
- Write(o, ref written, names [0]);
- }
- else {
- if (markdown)
- Write(o, ref written, " `--");
- else
- Write (o, ref written, " --");
- Write (o, ref written, names[0]);
- }
-
- for ( i = GetNextOptionIndex (names, i+1);
- i < names.Length; i = GetNextOptionIndex (names, i+1)) {
- if (markdown)
- Write(o, ref written, "`, `");
- else
- Write(o, ref written, ", ");
- Write (o, ref written, names [i].Length == 1 ? "-" : "--");
- Write (o, ref written, names [i]);
- }
+ void WriteDescription (TextWriter o, string value, string prefix, int firstWidth, int remWidth)
+ {
+ bool indent = false;
+ foreach (string line in GetLines (localizer (GetDescription (value)), firstWidth, remWidth)) {
+ if (indent)
+ o.Write (prefix);
+ o.WriteLine (line);
+ indent = true;
+ }
+ }
- if (p.OptionValueType == OptionValueType.Optional ||
- p.OptionValueType == OptionValueType.Required) {
- if (p.OptionValueType == OptionValueType.Optional) {
- Write (o, ref written, localizer ("["));
- }
- Write (o, ref written, localizer ("=" + GetArgumentName (0, p.MaxValueCount, p.Description)));
- string sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0
- ? p.ValueSeparators [0]
- : " ";
- for (int c = 1; c < p.MaxValueCount; ++c) {
- Write (o, ref written, localizer (sep + GetArgumentName (c, p.MaxValueCount, p.Description)));
- }
- if (p.OptionValueType == OptionValueType.Optional) {
- Write (o, ref written, localizer ("]"));
- }
- }
+ public bool WriteOptionPrototype (TextWriter o, Option p, ref int written, bool markdown = false)
+ {
+ string[] names = p.Names;
- if (markdown)
- Write(o, ref written, "`");
+ int i = GetNextOptionIndex (names, 0);
+ if (i == names.Length)
+ return false;
- return true;
+ if (names [i].Length == 1) {
+ if (markdown)
+ Write(o, ref written, "`-");
+ else
+ Write(o, ref written, " -");
+ Write(o, ref written, names [0]);
+ }
+ else {
+ if (markdown)
+ Write(o, ref written, " `--");
+ else
+ Write (o, ref written, " --");
+ Write (o, ref written, names[0]);
+ }
+
+ for ( i = GetNextOptionIndex (names, i+1);
+ i < names.Length; i = GetNextOptionIndex (names, i+1)) {
+ if (markdown)
+ Write(o, ref written, "`, `");
+ else
+ Write(o, ref written, ", ");
+ Write (o, ref written, names [i].Length == 1 ? "-" : "--");
+ Write (o, ref written, names [i]);
}
- static int GetNextOptionIndex (string[] names, int i)
- {
- while (i < names.Length && names [i] == "<>") {
- ++i;
+ if (p.OptionValueType == OptionValueType.Optional ||
+ p.OptionValueType == OptionValueType.Required) {
+ if (p.OptionValueType == OptionValueType.Optional) {
+ Write (o, ref written, localizer ("["));
+ }
+ Write (o, ref written, localizer ("=" + GetArgumentName (0, p.MaxValueCount, p.Description)));
+ string sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0
+ ? p.ValueSeparators [0]
+ : " ";
+ for (int c = 1; c < p.MaxValueCount; ++c) {
+ Write (o, ref written, localizer (sep + GetArgumentName (c, p.MaxValueCount, p.Description)));
+ }
+ if (p.OptionValueType == OptionValueType.Optional) {
+ Write (o, ref written, localizer ("]"));
}
- return i;
}
- static void Write (TextWriter o, ref int n, string s)
- {
- n += s.Length;
- o.Write (s);
+ if (markdown)
+ Write(o, ref written, "`");
+
+ return true;
+ }
+
+ static int GetNextOptionIndex (string[] names, int i)
+ {
+ while (i < names.Length && names [i] == "<>") {
+ ++i;
}
+ return i;
+ }
- private static string GetArgumentName (int index, int maxIndex, string description)
- {
- if (description == null)
- return maxIndex == 1 ? "VALUE" : index == 0 ? "NAME" : "VALUE";
- string[] nameStart;
- if (maxIndex == 1)
- nameStart = new string[]{"{0:", "{"};
- else
- nameStart = new string[]{"{" + index + ":"};
- for (int i = 0; i < nameStart.Length; ++i) {
- int start, j = 0;
- do {
- start = description.IndexOf (nameStart [i], j);
- } while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);
- if (start == -1)
- continue;
- int end = description.IndexOf ("}", start);
- if (end == -1)
- continue;
- return description.Substring (start + nameStart [i].Length, end - start - nameStart [i].Length);
- }
+ static void Write (TextWriter o, ref int n, string s)
+ {
+ n += s.Length;
+ o.Write (s);
+ }
+
+ private static string GetArgumentName (int index, int maxIndex, string description)
+ {
+ if (description == null)
return maxIndex == 1 ? "VALUE" : index == 0 ? "NAME" : "VALUE";
- }
+ string[] nameStart;
+ if (maxIndex == 1)
+ nameStart = ["{0:", "{"];
+ else
+ nameStart = ["{" + index + ":"];
+ for (int i = 0; i < nameStart.Length; ++i) {
+ int start, j = 0;
+ do {
+ start = description.IndexOf (nameStart [i], j);
+ } while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);
+ if (start == -1)
+ continue;
+ int end = description.IndexOf ("}", start);
+ if (end == -1)
+ continue;
+ return description.Substring (start + nameStart [i].Length, end - start - nameStart [i].Length);
+ }
+ return maxIndex == 1 ? "VALUE" : index == 0 ? "NAME" : "VALUE";
+ }
- private static string GetDescription (string description)
- {
- if (description == null)
- return string.Empty;
- StringBuilder sb = new StringBuilder (description.Length);
- int start = -1;
- for (int i = 0; i < description.Length; ++i) {
- switch (description [i]) {
- case '{':
- if (i == start) {
- sb.Append ('{');
- start = -1;
- }
- else if (start < 0)
- start = i + 1;
- break;
- case '}':
- if (start < 0) {
- if ((i+1) == description.Length || description [i+1] != '}')
- throw new InvalidOperationException ("Invalid option description: " + description);
- ++i;
- sb.Append ("}");
- }
- else {
- sb.Append (description.Substring (start, i - start));
- start = -1;
- }
- break;
- case ':':
- if (start < 0)
- goto default;
+ private static string GetDescription (string description)
+ {
+ if (description == null)
+ return string.Empty;
+ StringBuilder sb = new StringBuilder (description.Length);
+ int start = -1;
+ for (int i = 0; i < description.Length; ++i) {
+ switch (description [i]) {
+ case '{':
+ if (i == start) {
+ sb.Append ('{');
+ start = -1;
+ }
+ else if (start < 0)
start = i + 1;
- break;
- default:
- if (start < 0)
- sb.Append (description [i]);
- break;
- }
+ break;
+ case '}':
+ if (start < 0) {
+ if ((i+1) == description.Length || description [i+1] != '}')
+ throw new InvalidOperationException ("Invalid option description: " + description);
+ ++i;
+ sb.Append ("}");
+ }
+ else {
+ sb.Append (description.Substring (start, i - start));
+ start = -1;
+ }
+ break;
+ case ':':
+ if (start < 0)
+ goto default;
+ start = i + 1;
+ break;
+ default:
+ if (start < 0)
+ sb.Append (description [i]);
+ break;
}
- return sb.ToString ();
- }
-
- private static IEnumerable GetLines (string description, int firstWidth, int remWidth)
- {
- return StringCoda.WrappedLines (description, firstWidth, remWidth);
}
+ return sb.ToString ();
}
-}
+ private static IEnumerable GetLines (string description, int firstWidth, int remWidth)
+ {
+ return StringCoda.WrappedLines (description, firstWidth, remWidth);
+ }
+}
\ No newline at end of file
diff --git a/src/SeqCli/Config/ConnectionConfig.cs b/src/SeqCli/Config/ConnectionConfig.cs
index 57b6fd50..821b6ad6 100644
--- a/src/SeqCli/Config/ConnectionConfig.cs
+++ b/src/SeqCli/Config/ConnectionConfig.cs
@@ -14,11 +14,12 @@
using System;
using Newtonsoft.Json;
+using SeqCli.Forwarder.Cryptography;
using SeqCli.Util;
namespace SeqCli.Config;
-class ConnectionConfig
+public class ConnectionConfig
{
const string ProtectedDataPrefix = "pd.";
@@ -57,4 +58,13 @@ public string? ApiKey
EncodedApiKey = value;
}
}
+
+ public string? GetApiKey(IStringDataProtector dataProtector)
+ {
+ throw new NotImplementedException();
+ }
+
+ public uint? PooledConnectionLifetimeMilliseconds { get; set; } = null;
+ public ulong EventBodyLimitBytes { get; set; } = 256 * 1024;
+ public ulong PayloadLimitBytes { get; set; } = 10 * 1024 * 1024;
}
\ No newline at end of file
diff --git a/src/SeqCli/Config/Forwarder/ForwarderApiConfig.cs b/src/SeqCli/Config/Forwarder/ForwarderApiConfig.cs
index 321e8017..c0c27c19 100644
--- a/src/SeqCli/Config/Forwarder/ForwarderApiConfig.cs
+++ b/src/SeqCli/Config/Forwarder/ForwarderApiConfig.cs
@@ -1,6 +1,8 @@
-namespace SeqCli.Config;
+namespace SeqCli.Config.Forwarder;
+
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
class ForwarderApiConfig
{
- public string ListenUri { get; set; } = "http://localhost:15341";
+ public string ListenUri { get; set; } = "http://127.0.0.1:15341";
}
\ No newline at end of file
diff --git a/src/SeqCli/Config/Forwarder/ForwarderConfig.cs b/src/SeqCli/Config/Forwarder/ForwarderConfig.cs
index 621072cc..cbb2e16f 100644
--- a/src/SeqCli/Config/Forwarder/ForwarderConfig.cs
+++ b/src/SeqCli/Config/Forwarder/ForwarderConfig.cs
@@ -1,11 +1,9 @@
-namespace SeqCli.Config;
+namespace SeqCli.Config.Forwarder;
+
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
class ForwarderConfig
{
- public uint? PooledConnectionLifetimeMilliseconds { get; set; } = null;
- public ulong EventBodyLimitBytes { get; set; } = 256 * 1024;
- public ulong PayloadLimitBytes { get; set; } = 10 * 1024 * 1024;
-
public ForwarderStorageConfig Storage { get; set; } = new();
public ForwarderDiagnosticConfig Diagnostics { get; set; } = new();
public ForwarderApiConfig Api { get; set; } = new();
diff --git a/src/SeqCli/Config/Forwarder/ForwarderDiagnosticConfig.cs b/src/SeqCli/Config/Forwarder/ForwarderDiagnosticConfig.cs
index 8366a6e4..3a63d685 100644
--- a/src/SeqCli/Config/Forwarder/ForwarderDiagnosticConfig.cs
+++ b/src/SeqCli/Config/Forwarder/ForwarderDiagnosticConfig.cs
@@ -1,8 +1,10 @@
using System;
using System.IO;
using Serilog.Events;
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
-namespace SeqCli.Config;
+namespace SeqCli.Config.Forwarder;
public class ForwarderDiagnosticConfig
{
diff --git a/src/SeqCli/Config/Forwarder/ForwarderStorageConfig.cs b/src/SeqCli/Config/Forwarder/ForwarderStorageConfig.cs
index f2143eaa..5bc58044 100644
--- a/src/SeqCli/Config/Forwarder/ForwarderStorageConfig.cs
+++ b/src/SeqCli/Config/Forwarder/ForwarderStorageConfig.cs
@@ -1,6 +1,8 @@
-namespace SeqCli.Config;
+namespace SeqCli.Config.Forwarder;
+
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
public class ForwarderStorageConfig
{
- public int BufferSizeBytes { get; set; } = 67_108_864;
+ public ulong BufferSizeBytes { get; set; } = 67_108_864;
}
\ No newline at end of file
diff --git a/src/SeqCli/Config/OutputConfig.cs b/src/SeqCli/Config/OutputConfig.cs
index 8727c2b3..b52a73b6 100644
--- a/src/SeqCli/Config/OutputConfig.cs
+++ b/src/SeqCli/Config/OutputConfig.cs
@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+
namespace SeqCli.Config;
public class OutputConfig
diff --git a/src/SeqCli/Config/SeqCliConfig.cs b/src/SeqCli/Config/SeqCliConfig.cs
index 8ff11a08..88ac1b08 100644
--- a/src/SeqCli/Config/SeqCliConfig.cs
+++ b/src/SeqCli/Config/SeqCliConfig.cs
@@ -18,6 +18,9 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
+using SeqCli.Config.Forwarder;
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
namespace SeqCli.Config;
@@ -26,7 +29,7 @@ class SeqCliConfig
static readonly string DefaultConfigFilename =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "SeqCli.json");
- static JsonSerializerSettings SerializerSettings { get; } = new JsonSerializerSettings
+ static JsonSerializerSettings SerializerSettings { get; } = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters =
@@ -51,11 +54,10 @@ public static void Write(SeqCliConfig data)
File.WriteAllText(DefaultConfigFilename, content);
}
- public ConnectionConfig Connection { get; set; } = new ConnectionConfig();
+ public ConnectionConfig Connection { get; set; } = new();
public OutputConfig Output { get; set; } = new();
public ForwarderConfig Forwarder { get; set; } = new();
public SeqCliEncryptionProviderConfig EncryptionProviderProvider { get; set; } = new SeqCliEncryptionProviderConfig();
- public Dictionary Profiles { get; } =
- new Dictionary(StringComparer.OrdinalIgnoreCase);
+ public Dictionary Profiles { get; } = new(StringComparer.OrdinalIgnoreCase);
}
\ No newline at end of file
diff --git a/src/SeqCli/Csv/CsvTokenizer.cs b/src/SeqCli/Csv/CsvTokenizer.cs
index aca5796a..2f3529a4 100644
--- a/src/SeqCli/Csv/CsvTokenizer.cs
+++ b/src/SeqCli/Csv/CsvTokenizer.cs
@@ -42,7 +42,7 @@ protected override IEnumerable> Tokenize(TextSpan span)
if (next.Value != '"')
{
- yield return Result.Empty(next.Location, new[] {"double-quote"});
+ yield return Result.Empty(next.Location, ["double-quote"]);
yield break;
}
@@ -79,13 +79,13 @@ protected override IEnumerable> Tokenize(TextSpan span)
}
else
{
- yield return Result.Empty(next.Location, new[] {"comma", "newline"});
+ yield return Result.Empty(next.Location, ["comma", "newline"]);
yield break;
}
}
else
{
- yield return Result.Empty(next.Location, new[] {"double-quote"});
+ yield return Result.Empty(next.Location, ["double-quote"]);
yield break;
}
diff --git a/src/SeqCli/Forwarder/Config/SeqForwarderApiConfig.cs b/src/SeqCli/Forwarder/Config/SeqForwarderApiConfig.cs
deleted file mode 100644
index d2e0aaaa..00000000
--- a/src/SeqCli/Forwarder/Config/SeqForwarderApiConfig.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016-2017 Datalust Pty Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-namespace Seq.Forwarder.Config
-{
- class SeqForwarderApiConfig
- {
- public string ListenUri { get; set; } = "http://localhost:15341";
- }
-}
diff --git a/src/SeqCli/Forwarder/Config/SeqForwarderConfig.cs b/src/SeqCli/Forwarder/Config/SeqForwarderConfig.cs
deleted file mode 100644
index d39abb59..00000000
--- a/src/SeqCli/Forwarder/Config/SeqForwarderConfig.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2016-2017 Datalust Pty Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using Microsoft.Extensions.Configuration;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Converters;
-using Newtonsoft.Json.Serialization;
-
-// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
-
-namespace Seq.Forwarder.Config
-{
- class SeqForwarderConfig
- {
- static JsonSerializerSettings SerializerSettings { get; } = new JsonSerializerSettings
- {
- ContractResolver = new CamelCasePropertyNamesContractResolver(),
- Converters =
- {
- new StringEnumConverter()
- }
- };
-
- public static SeqForwarderConfig ReadOrInit(string filename, bool includeEnvironmentVariables = true)
- {
- if (filename == null) throw new ArgumentNullException(nameof(filename));
-
- if (!File.Exists(filename))
- {
- var config = new SeqForwarderConfig();
- Write(filename, config);
- return config;
- }
-
- var content = File.ReadAllText(filename);
- var combinedConfig = JsonConvert.DeserializeObject(content, SerializerSettings)
- ?? throw new ArgumentException("Configuration content is null.");
-
- if (includeEnvironmentVariables)
- {
- // Any Environment Variables overwrite those in the Config File
- var envVarConfig = new ConfigurationBuilder().AddEnvironmentVariables("FORWARDER_").Build();
- foreach (var sectionProperty in typeof(SeqForwarderConfig).GetTypeInfo().DeclaredProperties
- .Where(p => p.GetMethod != null && p.GetMethod.IsPublic && !p.GetMethod.IsStatic))
- {
- foreach (var subGroupProperty in sectionProperty.PropertyType.GetTypeInfo().DeclaredProperties
- .Where(p => p.GetMethod != null && p.GetMethod.IsPublic && p.SetMethod != null && p.SetMethod.IsPublic && !p.GetMethod.IsStatic))
- {
- var envVarName = sectionProperty.Name.ToUpper() + "_" + subGroupProperty.Name.ToUpper();
- var envVarVal = envVarConfig.GetValue(subGroupProperty.PropertyType, envVarName);
- if (envVarVal != null)
- {
- subGroupProperty.SetValue(sectionProperty.GetValue(combinedConfig), envVarVal);
- }
- }
- }
- }
-
- return combinedConfig;
- }
-
- public static void Write(string filename, SeqForwarderConfig data)
- {
- if (filename == null) throw new ArgumentNullException(nameof(filename));
- if (data == null) throw new ArgumentNullException(nameof(data));
-
- var dir = Path.GetDirectoryName(filename);
- if (!Directory.Exists(dir))
- Directory.CreateDirectory(dir!);
-
- var content = JsonConvert.SerializeObject(data, Formatting.Indented, SerializerSettings);
- File.WriteAllText(filename, content);
- }
-
- public SeqForwarderDiagnosticConfig Diagnostics { get; set; } = new SeqForwarderDiagnosticConfig();
- public SeqForwarderOutputConfig Output { get; set; } = new SeqForwarderOutputConfig();
- public SeqForwarderStorageConfig Storage { get; set; } = new SeqForwarderStorageConfig();
- public SeqForwarderApiConfig Api { get; set; } = new SeqForwarderApiConfig();
- }
-}
diff --git a/src/SeqCli/Forwarder/Config/SeqForwarderDiagnosticConfig.cs b/src/SeqCli/Forwarder/Config/SeqForwarderDiagnosticConfig.cs
deleted file mode 100644
index d1bca9f3..00000000
--- a/src/SeqCli/Forwarder/Config/SeqForwarderDiagnosticConfig.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016-2017 Datalust Pty Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.IO;
-using Serilog.Events;
-
-namespace Seq.Forwarder.Config
-{
- public class SeqForwarderDiagnosticConfig
- {
- public string InternalLogPath { get; set; } = GetDefaultInternalLogPath();
- public LogEventLevel InternalLoggingLevel { get; set; } = LogEventLevel.Information;
- public string? InternalLogServerUri { get; set; }
- public string? InternalLogServerApiKey { get; set; }
- public bool IngestionLogShowDetail { get; set; }
-
- public static string GetDefaultInternalLogPath()
- {
- return Path.Combine(
-#if WINDOWS
- // Common, here, because the service may run as Local Service, which has no obvious home
- // directory.
- Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
-#else
- // Specific to and writable by the current user.
- Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
-#endif
- @"Seq",
- "Logs");
- }
- }
-}
diff --git a/src/SeqCli/Forwarder/Config/SeqForwarderOutputConfig.cs b/src/SeqCli/Forwarder/Config/SeqForwarderOutputConfig.cs
deleted file mode 100644
index a48bdf76..00000000
--- a/src/SeqCli/Forwarder/Config/SeqForwarderOutputConfig.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright Datalust Pty Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using Newtonsoft.Json;
-using Seq.Forwarder.Cryptography;
-
-// ReSharper disable UnusedMember.Global, AutoPropertyCanBeMadeGetOnly.Global
-
-namespace Seq.Forwarder.Config
-{
- public class SeqForwarderOutputConfig
- {
- public string ServerUrl { get; set; } = "http://localhost:5341";
- public ulong EventBodyLimitBytes { get; set; } = 256 * 1024;
- public ulong RawPayloadLimitBytes { get; set; } = 10 * 1024 * 1024;
- public uint? PooledConnectionLifetimeMilliseconds { get; set; } = null;
-
- const string ProtectedDataPrefix = "pd.";
-
- public string? ApiKey { get; set; }
-
- public string? GetApiKey(IStringDataProtector dataProtector)
- {
- if (string.IsNullOrWhiteSpace(ApiKey))
- return null;
-
- if (!ApiKey.StartsWith(ProtectedDataPrefix))
- return ApiKey;
-
- return dataProtector.Unprotect(ApiKey.Substring(ProtectedDataPrefix.Length));
- }
-
- public void SetApiKey(string? apiKey, IStringDataProtector dataProtector)
- {
- if (string.IsNullOrWhiteSpace(apiKey))
- {
- ApiKey = null;
- return;
- }
-
- ApiKey = $"{ProtectedDataPrefix}{dataProtector.Protect(apiKey)}";
- }
- }
-}
diff --git a/src/SeqCli/Forwarder/Config/SeqForwarderStorageConfig.cs b/src/SeqCli/Forwarder/Config/SeqForwarderStorageConfig.cs
deleted file mode 100644
index 2f713b7d..00000000
--- a/src/SeqCli/Forwarder/Config/SeqForwarderStorageConfig.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016-2017 Datalust Pty Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-namespace Seq.Forwarder.Config
-{
- public class SeqForwarderStorageConfig
- {
- public ulong BufferSizeBytes { get; set; } = 64 * 1024 * 1024;
- }
-}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Cryptography/IStringDataProtector.cs b/src/SeqCli/Forwarder/Cryptography/IStringDataProtector.cs
index 24ef61b0..cdc930c1 100644
--- a/src/SeqCli/Forwarder/Cryptography/IStringDataProtector.cs
+++ b/src/SeqCli/Forwarder/Cryptography/IStringDataProtector.cs
@@ -1,8 +1,7 @@
-namespace Seq.Forwarder.Cryptography
+namespace SeqCli.Forwarder.Cryptography;
+
+public interface IStringDataProtector
{
- public interface IStringDataProtector
- {
- string Protect(string value);
- string Unprotect(string @protected);
- }
-}
+ string Protect(string value);
+ string Unprotect(string @protected);
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Cryptography/StringDataProtector.cs b/src/SeqCli/Forwarder/Cryptography/StringDataProtector.cs
index 64ef755c..e35ef0b7 100644
--- a/src/SeqCli/Forwarder/Cryptography/StringDataProtector.cs
+++ b/src/SeqCli/Forwarder/Cryptography/StringDataProtector.cs
@@ -1,14 +1,13 @@
-namespace Seq.Forwarder.Cryptography
+namespace SeqCli.Forwarder.Cryptography;
+
+static class StringDataProtector
{
- static class StringDataProtector
+ public static IStringDataProtector CreatePlatformDefault()
{
- public static IStringDataProtector CreatePlatformDefault()
- {
#if WINDOWS
return new DpapiMachineScopeDataProtect();
#else
- return new UnprotectedStringData();
+ return new UnprotectedStringData();
#endif
- }
}
}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Cryptography/UnprotectedStringData.cs b/src/SeqCli/Forwarder/Cryptography/UnprotectedStringData.cs
index b5213375..6148081e 100644
--- a/src/SeqCli/Forwarder/Cryptography/UnprotectedStringData.cs
+++ b/src/SeqCli/Forwarder/Cryptography/UnprotectedStringData.cs
@@ -2,20 +2,19 @@
using Serilog;
-namespace Seq.Forwarder.Cryptography
+namespace SeqCli.Forwarder.Cryptography;
+
+public class UnprotectedStringData : IStringDataProtector
{
- public class UnprotectedStringData : IStringDataProtector
+ public string Protect(string value)
{
- public string Protect(string value)
- {
- Log.Warning("Data protection is not available on this platform; sensitive values will be stored in plain text");
- return value;
- }
+ Log.Warning("Data protection is not available on this platform; sensitive values will be stored in plain text");
+ return value;
+ }
- public string Unprotect(string @protected)
- {
- return @protected;
- }
+ public string Unprotect(string @protected)
+ {
+ return @protected;
}
}
diff --git a/src/SeqCli/Forwarder/Diagnostics/InMemorySink.cs b/src/SeqCli/Forwarder/Diagnostics/InMemorySink.cs
index 00797ec0..b5eea21f 100644
--- a/src/SeqCli/Forwarder/Diagnostics/InMemorySink.cs
+++ b/src/SeqCli/Forwarder/Diagnostics/InMemorySink.cs
@@ -18,32 +18,31 @@
using Serilog.Core;
using Serilog.Events;
-namespace Seq.Forwarder.Diagnostics
+namespace SeqCli.Forwarder.Diagnostics;
+
+public class InMemorySink : ILogEventSink
{
- public class InMemorySink : ILogEventSink
- {
- readonly int _queueLength;
- readonly ConcurrentQueue _queue = new ConcurrentQueue();
+ readonly int _queueLength;
+ readonly ConcurrentQueue _queue = new();
- public InMemorySink(int queueLength)
- {
- _queueLength = queueLength;
- }
+ public InMemorySink(int queueLength)
+ {
+ _queueLength = queueLength;
+ }
- public IEnumerable Read()
- {
- return _queue.ToArray();
- }
+ public IEnumerable Read()
+ {
+ return _queue.ToArray();
+ }
- public void Emit(LogEvent logEvent)
- {
- if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
- _queue.Enqueue(logEvent);
+ public void Emit(LogEvent logEvent)
+ {
+ if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
+ _queue.Enqueue(logEvent);
- while (_queue.Count > _queueLength)
- {
- _queue.TryDequeue(out _);
- }
+ while (_queue.Count > _queueLength)
+ {
+ _queue.TryDequeue(out _);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Diagnostics/IngestionLog.cs b/src/SeqCli/Forwarder/Diagnostics/IngestionLog.cs
index 52e5af13..5e54a5bf 100644
--- a/src/SeqCli/Forwarder/Diagnostics/IngestionLog.cs
+++ b/src/SeqCli/Forwarder/Diagnostics/IngestionLog.cs
@@ -18,48 +18,47 @@
using Serilog;
using Serilog.Events;
-namespace Seq.Forwarder.Diagnostics
+namespace SeqCli.Forwarder.Diagnostics;
+
+static class IngestionLog
{
- static class IngestionLog
- {
- const int Capacity = 100;
+ const int Capacity = 100;
- static readonly InMemorySink Sink = new InMemorySink(Capacity);
+ static readonly InMemorySink Sink = new(Capacity);
- public static ILogger Log { get; }
+ public static ILogger Log { get; }
- static IngestionLog()
- {
- Log = new LoggerConfiguration()
- .MinimumLevel.Verbose()
- .WriteTo.Sink(Sink)
- .WriteTo.Logger(Serilog.Log.Logger)
- .CreateLogger();
- }
+ static IngestionLog()
+ {
+ Log = new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .WriteTo.Sink(Sink)
+ .WriteTo.Logger(Serilog.Log.Logger)
+ .CreateLogger();
+ }
- public static IEnumerable Read()
- {
- return Sink.Read();
- }
+ public static IEnumerable Read()
+ {
+ return Sink.Read();
+ }
- public static ILogger ForClient(IPAddress clientHostIP)
- {
- return Log.ForContext("ClientHostIP", clientHostIP);
- }
+ public static ILogger ForClient(IPAddress clientHostIP)
+ {
+ return Log.ForContext("ClientHostIP", clientHostIP);
+ }
- public static ILogger ForPayload(IPAddress clientHostIP, string payload)
- {
- var prefix = CapturePrefix(payload);
- return ForClient(clientHostIP)
- .ForContext("StartToLog", prefix.Length)
- .ForContext("DocumentStart", prefix);
- }
+ public static ILogger ForPayload(IPAddress clientHostIP, string payload)
+ {
+ var prefix = CapturePrefix(payload);
+ return ForClient(clientHostIP)
+ .ForContext("StartToLog", prefix.Length)
+ .ForContext("DocumentStart", prefix);
+ }
- static string CapturePrefix(string line)
- {
- if (line == null) throw new ArgumentNullException(nameof(line));
- var startToLog = Math.Min(line.Length, 1024);
- return line.Substring(0, startToLog);
- }
+ static string CapturePrefix(string line)
+ {
+ if (line == null) throw new ArgumentNullException(nameof(line));
+ var startToLog = Math.Min(line.Length, 1024);
+ return line.Substring(0, startToLog);
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/ForwarderModule.cs b/src/SeqCli/Forwarder/ForwarderModule.cs
new file mode 100644
index 00000000..2a5005ab
--- /dev/null
+++ b/src/SeqCli/Forwarder/ForwarderModule.cs
@@ -0,0 +1,84 @@
+// Copyright Datalust Pty Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Net.Http;
+using System.Threading;
+using Autofac;
+using SeqCli.Config;
+using SeqCli.Forwarder.Cryptography;
+using SeqCli.Forwarder.Multiplexing;
+using SeqCli.Forwarder.Web.Host;
+
+namespace SeqCli.Forwarder;
+
+class ForwarderModule : Module
+{
+ readonly string _bufferPath;
+ readonly SeqCliConfig _config;
+
+ public ForwarderModule(string bufferPath, SeqCliConfig config)
+ {
+ _bufferPath = bufferPath ?? throw new ArgumentNullException(nameof(bufferPath));
+ _config = config ?? throw new ArgumentNullException(nameof(config));
+ }
+
+ protected override void Load(ContainerBuilder builder)
+ {
+ builder.RegisterType().SingleInstance();
+ builder.RegisterType()
+ .WithParameter("bufferPath", _bufferPath)
+ .SingleInstance();
+
+ builder.RegisterType().As();
+ builder.RegisterType().SingleInstance();
+
+ builder.Register(c =>
+ {
+ var outputConfig = c.Resolve();
+ var baseUri = outputConfig.ServerUrl;
+ if (string.IsNullOrWhiteSpace(baseUri))
+ throw new ArgumentException("The destination Seq server URL must be configured in SeqForwarder.json.");
+
+ if (!baseUri.EndsWith("/"))
+ baseUri += "/";
+
+ // additional configuration options that require the use of SocketsHttpHandler should be added to
+ // this expression, using an "or" operator.
+
+ var hasSocketHandlerOption =
+ outputConfig.PooledConnectionLifetimeMilliseconds.HasValue;
+
+ if (hasSocketHandlerOption)
+ {
+ var httpMessageHandler = new SocketsHttpHandler
+ {
+ PooledConnectionLifetime = outputConfig.PooledConnectionLifetimeMilliseconds.HasValue ? TimeSpan.FromMilliseconds(outputConfig.PooledConnectionLifetimeMilliseconds.Value) : Timeout.InfiniteTimeSpan,
+ };
+
+ return new HttpClient(httpMessageHandler) { BaseAddress = new Uri(baseUri) };
+ }
+
+ return new HttpClient { BaseAddress = new Uri(baseUri) };
+
+ }).SingleInstance();
+
+ builder.RegisterInstance(StringDataProtector.CreatePlatformDefault());
+
+ builder.RegisterInstance(_config);
+ builder.RegisterInstance(_config.Forwarder.Api);
+ builder.RegisterInstance(_config.Forwarder.Diagnostics);
+ builder.RegisterInstance(_config.Forwarder.Storage);
+ }
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Multiplexing/ActiveLogBuffer.cs b/src/SeqCli/Forwarder/Multiplexing/ActiveLogBuffer.cs
index 637f4c09..52fd743b 100644
--- a/src/SeqCli/Forwarder/Multiplexing/ActiveLogBuffer.cs
+++ b/src/SeqCli/Forwarder/Multiplexing/ActiveLogBuffer.cs
@@ -13,26 +13,25 @@
// limitations under the License.
using System;
-using Seq.Forwarder.Shipper;
-using Seq.Forwarder.Storage;
+using SeqCli.Forwarder.Shipper;
+using SeqCli.Forwarder.Storage;
-namespace Seq.Forwarder.Multiplexing
+namespace SeqCli.Forwarder.Multiplexing;
+
+sealed class ActiveLogBuffer : IDisposable
{
- sealed class ActiveLogBuffer : IDisposable
- {
- public LogShipper Shipper { get; }
- public LogBuffer Buffer { get; }
+ public LogShipper Shipper { get; }
+ public LogBuffer Buffer { get; }
- public ActiveLogBuffer(LogBuffer logBuffer, LogShipper logShipper)
- {
- Buffer = logBuffer ?? throw new ArgumentNullException(nameof(logBuffer));
- Shipper = logShipper ?? throw new ArgumentNullException(nameof(logShipper));
- }
+ public ActiveLogBuffer(LogBuffer logBuffer, LogShipper logShipper)
+ {
+ Buffer = logBuffer ?? throw new ArgumentNullException(nameof(logBuffer));
+ Shipper = logShipper ?? throw new ArgumentNullException(nameof(logShipper));
+ }
- public void Dispose()
- {
- Shipper.Dispose();
- Buffer.Dispose();
- }
+ public void Dispose()
+ {
+ Shipper.Dispose();
+ Buffer.Dispose();
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Multiplexing/ActiveLogBufferMap.cs b/src/SeqCli/Forwarder/Multiplexing/ActiveLogBufferMap.cs
index 13779570..bcd09c65 100644
--- a/src/SeqCli/Forwarder/Multiplexing/ActiveLogBufferMap.cs
+++ b/src/SeqCli/Forwarder/Multiplexing/ActiveLogBufferMap.cs
@@ -16,220 +16,207 @@
using System.Collections.Generic;
using System.IO;
using System.Net;
-using Seq.Forwarder.Config;
-using Seq.Forwarder.Cryptography;
-using Seq.Forwarder.Storage;
-using Seq.Forwarder.Web;
+using SeqCli.Config;
+using SeqCli.Config.Forwarder;
+using SeqCli.Forwarder.Cryptography;
+using SeqCli.Forwarder.Storage;
+using SeqCli.Forwarder.Web;
using Serilog;
-namespace Seq.Forwarder.Multiplexing
+namespace SeqCli.Forwarder.Multiplexing;
+
+public class ActiveLogBufferMap : IDisposable
{
- public class ActiveLogBufferMap : IDisposable
+ const string DataFileName = "data.mdb", LockFileName = "lock.mdb", ApiKeyFileName = ".apikey";
+
+ readonly ulong _bufferSizeBytes;
+ readonly ConnectionConfig _connectionConfig;
+ readonly ILogShipperFactory _shipperFactory;
+ readonly IStringDataProtector _dataProtector;
+ readonly string _bufferPath;
+ readonly ILogger _log = Log.ForContext();
+
+ readonly object _sync = new();
+ bool _loaded;
+ ActiveLogBuffer? _noApiKeyLogBuffer;
+ readonly Dictionary _buffersByApiKey = new();
+
+ public ActiveLogBufferMap(
+ string bufferPath,
+ ForwarderStorageConfig storageConfig,
+ ConnectionConfig outputConfig,
+ ILogShipperFactory logShipperFactory,
+ IStringDataProtector dataProtector)
{
- const string DataFileName = "data.mdb", LockFileName = "lock.mdb", ApiKeyFileName = ".apikey";
-
- readonly ulong _bufferSizeBytes;
- readonly SeqForwarderOutputConfig _outputConfig;
- readonly ILogShipperFactory _shipperFactory;
- readonly IStringDataProtector _dataProtector;
- readonly string _bufferPath;
- readonly ILogger _log = Log.ForContext();
-
- readonly object _sync = new object();
- bool _loaded;
- ActiveLogBuffer? _noApiKeyLogBuffer;
- readonly Dictionary _buffersByApiKey = new Dictionary();
-
- public ActiveLogBufferMap(
- string bufferPath,
- SeqForwarderStorageConfig storageConfig,
- SeqForwarderOutputConfig outputConfig,
- ILogShipperFactory logShipperFactory,
- IStringDataProtector dataProtector)
- {
- _bufferSizeBytes = storageConfig.BufferSizeBytes;
- _outputConfig = outputConfig ?? throw new ArgumentNullException(nameof(outputConfig));
- _shipperFactory = logShipperFactory ?? throw new ArgumentNullException(nameof(logShipperFactory));
- _dataProtector = dataProtector ?? throw new ArgumentNullException(nameof(dataProtector));
- _bufferPath = bufferPath ?? throw new ArgumentNullException(nameof(bufferPath));
- }
+ _bufferSizeBytes = storageConfig.BufferSizeBytes;
+ _connectionConfig = outputConfig ?? throw new ArgumentNullException(nameof(outputConfig));
+ _shipperFactory = logShipperFactory ?? throw new ArgumentNullException(nameof(logShipperFactory));
+ _dataProtector = dataProtector ?? throw new ArgumentNullException(nameof(dataProtector));
+ _bufferPath = bufferPath ?? throw new ArgumentNullException(nameof(bufferPath));
+ }
- // The odd three-stage initialization improves our chances of correctly tearing down the `LightningEnvironment`s within
- // `LogBuffer`s in the event of a failure during start-up. See: https://github.com/CoreyKaylor/Lightning.NET/blob/master/src/LightningDB/LightningEnvironment.cs#L252
- public void Load()
- {
- // At startup, we look for buffers and either delete them if they're empty, or load them
- // up if they're not. This garbage collection at start-up is a simplification,
- // we might try cleaning up in the background if the gains are worthwhile, although more synchronization
- // would be required.
+ // The odd three-stage initialization improves our chances of correctly tearing down the `LightningEnvironment`s within
+ // `LogBuffer`s in the event of a failure during start-up. See: https://github.com/CoreyKaylor/Lightning.NET/blob/master/src/LightningDB/LightningEnvironment.cs#L252
+ public void Load()
+ {
+ // At startup, we look for buffers and either delete them if they're empty, or load them
+ // up if they're not. This garbage collection at start-up is a simplification,
+ // we might try cleaning up in the background if the gains are worthwhile, although more synchronization
+ // would be required.
- lock (_sync)
- {
- if (_loaded) throw new InvalidOperationException("The log buffer map is already loaded.");
+ lock (_sync)
+ {
+ if (_loaded) throw new InvalidOperationException("The log buffer map is already loaded.");
- Directory.CreateDirectory(_bufferPath);
+ Directory.CreateDirectory(_bufferPath);
- var defaultDataFilePath = Path.Combine(_bufferPath, DataFileName);
- if (File.Exists(defaultDataFilePath))
+ var defaultDataFilePath = Path.Combine(_bufferPath, DataFileName);
+ if (File.Exists(defaultDataFilePath))
+ {
+ _log.Information("Loading the default log buffer in {Path}", _bufferPath);
+ var buffer = new LogBuffer(_bufferPath, _bufferSizeBytes);
+ if (buffer.Peek(0).Length == 0)
{
- _log.Information("Loading the default log buffer in {Path}", _bufferPath);
- var buffer = new LogBuffer(_bufferPath, _bufferSizeBytes);
- if (buffer.Peek(0).Length == 0)
- {
- _log.Information("The default buffer is empty and will be removed until more data is received");
- buffer.Dispose();
- File.Delete(defaultDataFilePath);
- var lockFilePath = Path.Combine(_bufferPath, LockFileName);
- if (File.Exists(lockFilePath))
- File.Delete(lockFilePath);
- }
- else
- {
- _noApiKeyLogBuffer = new ActiveLogBuffer(buffer, _shipperFactory.Create(buffer, _outputConfig.GetApiKey(_dataProtector)));
- }
+ _log.Information("The default buffer is empty and will be removed until more data is received");
+ buffer.Dispose();
+ File.Delete(defaultDataFilePath);
+ var lockFilePath = Path.Combine(_bufferPath, LockFileName);
+ if (File.Exists(lockFilePath))
+ File.Delete(lockFilePath);
}
-
- foreach (var subfolder in Directory.GetDirectories(_bufferPath))
+ else
{
- var encodedApiKeyFilePath = Path.Combine(subfolder, ApiKeyFileName);
- if (!File.Exists(encodedApiKeyFilePath))
- {
- _log.Information("Folder {Path} does not appear to be a log buffer; skipping", subfolder);
- continue;
- }
-
- _log.Information("Loading an API-key specific buffer in {Path}", subfolder);
- var apiKey = _dataProtector.Unprotect(File.ReadAllText(encodedApiKeyFilePath));
-
- var buffer = new LogBuffer(subfolder, _bufferSizeBytes);
- if (buffer.Peek(0).Length == 0)
- {
- _log.Information("API key-specific buffer in {Path} is empty and will be removed until more data is received", subfolder);
- buffer.Dispose();
- Directory.Delete(subfolder, true);
- }
- else
- {
- var activeBuffer = new ActiveLogBuffer(buffer, _shipperFactory.Create(buffer, apiKey));
- _buffersByApiKey.Add(apiKey, activeBuffer);
- }
+ _noApiKeyLogBuffer = new ActiveLogBuffer(buffer, _shipperFactory.Create(buffer, _connectionConfig.GetApiKey(_dataProtector)));
}
-
- _loaded = true;
}
- }
- public void Start()
- {
- lock (_sync)
+ foreach (var subfolder in Directory.GetDirectories(_bufferPath))
{
- if (!_loaded) throw new InvalidOperationException("The log buffer map is not loaded.");
-
- foreach (var buffer in OpenBuffers)
+ var encodedApiKeyFilePath = Path.Combine(subfolder, ApiKeyFileName);
+ if (!File.Exists(encodedApiKeyFilePath))
{
- buffer.Shipper.Start();
+ _log.Information("Folder {Path} does not appear to be a log buffer; skipping", subfolder);
+ continue;
}
- }
- }
- public void Stop()
- {
- lock (_sync)
- {
- // Hard to ensure _loaded is set in all cases, better here to be forgiving and
- // permit a clean shut-down.
+ _log.Information("Loading an API-key specific buffer in {Path}", subfolder);
+ var apiKey = _dataProtector.Unprotect(File.ReadAllText(encodedApiKeyFilePath));
- foreach (var buffer in OpenBuffers)
+ var buffer = new LogBuffer(subfolder, _bufferSizeBytes);
+ if (buffer.Peek(0).Length == 0)
{
- buffer.Shipper.Stop();
+ _log.Information("API key-specific buffer in {Path} is empty and will be removed until more data is received", subfolder);
+ buffer.Dispose();
+ Directory.Delete(subfolder, true);
+ }
+ else
+ {
+ var activeBuffer = new ActiveLogBuffer(buffer, _shipperFactory.Create(buffer, apiKey));
+ _buffersByApiKey.Add(apiKey, activeBuffer);
}
}
+
+ _loaded = true;
}
+ }
- public LogBuffer GetLogBuffer(string? apiKey)
+ public void Start()
+ {
+ lock (_sync)
{
- lock (_sync)
- {
- if (!_loaded) throw new RequestProcessingException("The forwarder service is starting up.", HttpStatusCode.ServiceUnavailable);
-
- if (apiKey == null)
- {
- if (_noApiKeyLogBuffer == null)
- {
- _log.Information("Creating a new default log buffer in {Path}", _bufferPath);
- var buffer = new LogBuffer(_bufferPath, _bufferSizeBytes);
- _noApiKeyLogBuffer = new ActiveLogBuffer(buffer, _shipperFactory.Create(buffer, _outputConfig.GetApiKey(_dataProtector)));
- _noApiKeyLogBuffer.Shipper.Start();
- }
- return _noApiKeyLogBuffer.Buffer;
- }
+ if (!_loaded) throw new InvalidOperationException("The log buffer map is not loaded.");
- if (_buffersByApiKey.TryGetValue(apiKey, out var existing))
- return existing.Buffer;
-
- var subfolder = Path.Combine(_bufferPath, Guid.NewGuid().ToString("n"));
- _log.Information("Creating a new API key-specific log buffer in {Path}", subfolder);
- Directory.CreateDirectory(subfolder);
- File.WriteAllText(Path.Combine(subfolder, ".apikey"), _dataProtector.Protect(apiKey));
- var newBuffer = new LogBuffer(subfolder, _bufferSizeBytes);
- var newActiveBuffer = new ActiveLogBuffer(newBuffer, _shipperFactory.Create(newBuffer, apiKey));
- _buffersByApiKey.Add(apiKey, newActiveBuffer);
- newActiveBuffer.Shipper.Start();
- return newBuffer;
+ foreach (var buffer in OpenBuffers)
+ {
+ buffer.Shipper.Start();
}
}
+ }
- public void Dispose()
+ public void Stop()
+ {
+ lock (_sync)
{
- lock (_sync)
+ // Hard to ensure _loaded is set in all cases, better here to be forgiving and
+ // permit a clean shut-down.
+
+ foreach (var buffer in OpenBuffers)
{
- foreach (var buffer in OpenBuffers)
- {
- buffer.Dispose();
- }
+ buffer.Shipper.Stop();
}
}
+ }
- public void Enumerate(Action action)
+ public LogBuffer GetLogBuffer(string? apiKey)
+ {
+ lock (_sync)
{
- if (action == null) throw new ArgumentNullException(nameof(action));
+ if (!_loaded) throw new RequestProcessingException("The forwarder service is starting up.", HttpStatusCode.ServiceUnavailable);
- lock (_sync)
+ if (apiKey == null)
{
- foreach (var buffer in OpenBuffers)
+ if (_noApiKeyLogBuffer == null)
{
- buffer.Buffer.Enumerate(action);
+ _log.Information("Creating a new default log buffer in {Path}", _bufferPath);
+ var buffer = new LogBuffer(_bufferPath, _bufferSizeBytes);
+ _noApiKeyLogBuffer = new ActiveLogBuffer(buffer, _shipperFactory.Create(buffer, _connectionConfig.GetApiKey(_dataProtector)));
+ _noApiKeyLogBuffer.Shipper.Start();
}
+ return _noApiKeyLogBuffer.Buffer;
}
+
+ if (_buffersByApiKey.TryGetValue(apiKey, out var existing))
+ return existing.Buffer;
+
+ var subfolder = Path.Combine(_bufferPath, Guid.NewGuid().ToString("n"));
+ _log.Information("Creating a new API key-specific log buffer in {Path}", subfolder);
+ Directory.CreateDirectory(subfolder);
+ File.WriteAllText(Path.Combine(subfolder, ".apikey"), _dataProtector.Protect(apiKey));
+ var newBuffer = new LogBuffer(subfolder, _bufferSizeBytes);
+ var newActiveBuffer = new ActiveLogBuffer(newBuffer, _shipperFactory.Create(newBuffer, apiKey));
+ _buffersByApiKey.Add(apiKey, newActiveBuffer);
+ newActiveBuffer.Shipper.Start();
+ return newBuffer;
}
+ }
- public static void Truncate(string bufferPath)
+ public void Dispose()
+ {
+ lock (_sync)
{
- DeleteIfExists(Path.Combine(bufferPath, DataFileName));
- DeleteIfExists(Path.Combine(bufferPath, LockFileName));
- foreach (var subdirectory in Directory.GetDirectories(bufferPath))
+ foreach (var buffer in OpenBuffers)
{
- if (File.Exists(Path.Combine(subdirectory, ApiKeyFileName)))
- Directory.Delete(subdirectory, true);
+ buffer.Dispose();
}
}
+ }
- static void DeleteIfExists(string filePath)
+ public static void Truncate(string bufferPath)
+ {
+ DeleteIfExists(Path.Combine(bufferPath, DataFileName));
+ DeleteIfExists(Path.Combine(bufferPath, LockFileName));
+ foreach (var subdirectory in Directory.GetDirectories(bufferPath))
{
- if (File.Exists(filePath))
- File.Delete(filePath);
+ if (File.Exists(Path.Combine(subdirectory, ApiKeyFileName)))
+ Directory.Delete(subdirectory, true);
}
+ }
- IEnumerable OpenBuffers
+ static void DeleteIfExists(string filePath)
+ {
+ if (File.Exists(filePath))
+ File.Delete(filePath);
+ }
+
+ IEnumerable OpenBuffers
+ {
+ get
{
- get
- {
- if (_noApiKeyLogBuffer != null)
- yield return _noApiKeyLogBuffer;
+ if (_noApiKeyLogBuffer != null)
+ yield return _noApiKeyLogBuffer;
- foreach (var buffer in _buffersByApiKey.Values)
- yield return buffer;
- }
+ foreach (var buffer in _buffersByApiKey.Values)
+ yield return buffer;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Multiplexing/HttpLogShipperFactory.cs b/src/SeqCli/Forwarder/Multiplexing/HttpLogShipperFactory.cs
index 4de973ad..7c95215d 100644
--- a/src/SeqCli/Forwarder/Multiplexing/HttpLogShipperFactory.cs
+++ b/src/SeqCli/Forwarder/Multiplexing/HttpLogShipperFactory.cs
@@ -14,28 +14,27 @@
using System;
using System.Net.Http;
-using Seq.Forwarder.Config;
-using Seq.Forwarder.Shipper;
-using Seq.Forwarder.Storage;
+using SeqCli.Config;
+using SeqCli.Forwarder.Shipper;
+using SeqCli.Forwarder.Storage;
-namespace Seq.Forwarder.Multiplexing
+namespace SeqCli.Forwarder.Multiplexing;
+
+class HttpLogShipperFactory : ILogShipperFactory
{
- class HttpLogShipperFactory : ILogShipperFactory
- {
- readonly HttpClient _outputHttpClient;
- readonly ServerResponseProxy _serverResponseProxy;
- readonly SeqForwarderOutputConfig _outputConfig;
+ readonly HttpClient _outputHttpClient;
+ readonly ServerResponseProxy _serverResponseProxy;
+ readonly ConnectionConfig _outputConfig;
- public HttpLogShipperFactory(ServerResponseProxy serverResponseProxy, SeqForwarderOutputConfig outputConfig, HttpClient outputHttpClient)
- {
- _outputHttpClient = outputHttpClient;
- _serverResponseProxy = serverResponseProxy ?? throw new ArgumentNullException(nameof(serverResponseProxy));
- _outputConfig = outputConfig ?? throw new ArgumentNullException(nameof(outputConfig));
- }
+ public HttpLogShipperFactory(ServerResponseProxy serverResponseProxy, ConnectionConfig outputConfig, HttpClient outputHttpClient)
+ {
+ _outputHttpClient = outputHttpClient;
+ _serverResponseProxy = serverResponseProxy ?? throw new ArgumentNullException(nameof(serverResponseProxy));
+ _outputConfig = outputConfig ?? throw new ArgumentNullException(nameof(outputConfig));
+ }
- public LogShipper Create(LogBuffer logBuffer, string? apiKey)
- {
- return new HttpLogShipper(logBuffer, apiKey, _outputConfig, _serverResponseProxy, _outputHttpClient);
- }
+ public LogShipper Create(LogBuffer logBuffer, string? apiKey)
+ {
+ return new HttpLogShipper(logBuffer, apiKey, _outputConfig, _serverResponseProxy, _outputHttpClient);
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Multiplexing/ILogShipperFactory.cs b/src/SeqCli/Forwarder/Multiplexing/ILogShipperFactory.cs
index 554324de..773f455f 100644
--- a/src/SeqCli/Forwarder/Multiplexing/ILogShipperFactory.cs
+++ b/src/SeqCli/Forwarder/Multiplexing/ILogShipperFactory.cs
@@ -12,13 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using Seq.Forwarder.Shipper;
-using Seq.Forwarder.Storage;
+using SeqCli.Forwarder.Shipper;
+using SeqCli.Forwarder.Storage;
-namespace Seq.Forwarder.Multiplexing
+namespace SeqCli.Forwarder.Multiplexing;
+
+public interface ILogShipperFactory
{
- public interface ILogShipperFactory
- {
- LogShipper Create(LogBuffer logBuffer, string? apiKey);
- }
-}
+ LogShipper Create(LogBuffer logBuffer, string? apiKey);
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Multiplexing/InertLogShipperFactory.cs b/src/SeqCli/Forwarder/Multiplexing/InertLogShipperFactory.cs
index f0dd9e44..b6fff878 100644
--- a/src/SeqCli/Forwarder/Multiplexing/InertLogShipperFactory.cs
+++ b/src/SeqCli/Forwarder/Multiplexing/InertLogShipperFactory.cs
@@ -12,16 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using Seq.Forwarder.Shipper;
-using Seq.Forwarder.Storage;
+using SeqCli.Forwarder.Shipper;
+using SeqCli.Forwarder.Storage;
-namespace Seq.Forwarder.Multiplexing
+namespace SeqCli.Forwarder.Multiplexing;
+
+class InertLogShipperFactory : ILogShipperFactory
{
- class InertLogShipperFactory : ILogShipperFactory
+ public LogShipper Create(LogBuffer logBuffer, string? apiKey)
{
- public LogShipper Create(LogBuffer logBuffer, string? apiKey)
- {
- return new InertLogShipper();
- }
+ return new InertLogShipper();
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Multiplexing/ServerResponseProxy.cs b/src/SeqCli/Forwarder/Multiplexing/ServerResponseProxy.cs
index 86ccc768..b52dc988 100644
--- a/src/SeqCli/Forwarder/Multiplexing/ServerResponseProxy.cs
+++ b/src/SeqCli/Forwarder/Multiplexing/ServerResponseProxy.cs
@@ -14,39 +14,38 @@
using System.Collections.Generic;
-namespace Seq.Forwarder.Multiplexing
+namespace SeqCli.Forwarder.Multiplexing;
+
+public class ServerResponseProxy
{
- public class ServerResponseProxy
- {
- const string EmptyResponse = "{}";
+ const string EmptyResponse = "{}";
- readonly object _syncRoot = new object();
- readonly Dictionary _lastResponseByApiKey = new Dictionary();
- string _lastNoApiKeyResponse = EmptyResponse;
+ readonly object _syncRoot = new();
+ readonly Dictionary _lastResponseByApiKey = new();
+ string _lastNoApiKeyResponse = EmptyResponse;
- public void SuccessResponseReturned(string? apiKey, string response)
+ public void SuccessResponseReturned(string? apiKey, string response)
+ {
+ lock (_syncRoot)
{
- lock (_syncRoot)
- {
- if (apiKey == null)
- _lastNoApiKeyResponse = response;
- else
- _lastResponseByApiKey[apiKey] = response;
- }
+ if (apiKey == null)
+ _lastNoApiKeyResponse = response;
+ else
+ _lastResponseByApiKey[apiKey] = response;
}
+ }
- public string GetResponseText(string? apiKey)
+ public string GetResponseText(string? apiKey)
+ {
+ lock (_syncRoot)
{
- lock (_syncRoot)
- {
- if (apiKey == null)
- return _lastNoApiKeyResponse;
+ if (apiKey == null)
+ return _lastNoApiKeyResponse;
- if (_lastResponseByApiKey.TryGetValue(apiKey, out var response))
- return response;
+ if (_lastResponseByApiKey.TryGetValue(apiKey, out var response))
+ return response;
- return EmptyResponse;
- }
+ return EmptyResponse;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Properties/AssemblyInfo.cs b/src/SeqCli/Forwarder/Properties/AssemblyInfo.cs
deleted file mode 100644
index da681b10..00000000
--- a/src/SeqCli/Forwarder/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("Seq.Forwarder.Tests")]
diff --git a/src/SeqCli/Forwarder/Schema/EventSchema.cs b/src/SeqCli/Forwarder/Schema/EventSchema.cs
index aa6c6f6c..c13f0325 100644
--- a/src/SeqCli/Forwarder/Schema/EventSchema.cs
+++ b/src/SeqCli/Forwarder/Schema/EventSchema.cs
@@ -4,184 +4,180 @@
using System.Globalization;
using System.Linq;
using Newtonsoft.Json.Linq;
+using SeqCli.Forwarder.Util;
using Serilog.Parsing;
-using Seq.Forwarder.Util;
-namespace Seq.Forwarder.Schema
+namespace SeqCli.Forwarder.Schema;
+
+static class EventSchema
{
- static class EventSchema
- {
- static readonly MessageTemplateParser MessageTemplateParser = new MessageTemplateParser();
+ static readonly MessageTemplateParser MessageTemplateParser = new();
- static readonly HashSet ClefReifiedProperties = new HashSet
- {
- "@t", "@m", "@mt", "@l", "@x", "@i", "@r"
- };
+ static readonly HashSet ClefReifiedProperties = ["@t", "@m", "@mt", "@l", "@x", "@i", "@r"];
- public static bool FromClefFormat(in int lineNumber, JObject compactFormat, [MaybeNullWhen(false)] out JObject rawFormat, [MaybeNullWhen(true)] out string error)
+ public static bool FromClefFormat(in int lineNumber, JObject compactFormat, [MaybeNullWhen(false)] out JObject rawFormat, [MaybeNullWhen(true)] out string error)
+ {
+ var result = new JObject();
+
+ var rawTimestamp = compactFormat["@t"];
+ if (rawTimestamp == null)
{
- var result = new JObject();
+ error = $"The event on line {lineNumber} does not carry an `@t` timestamp property.";
+ rawFormat = default;
+ return false;
+ }
- var rawTimestamp = compactFormat["@t"];
- if (rawTimestamp == null)
- {
- error = $"The event on line {lineNumber} does not carry an `@t` timestamp property.";
- rawFormat = default;
- return false;
- }
+ if (rawTimestamp.Type != JTokenType.String)
+ {
+ error = $"The event on line {lineNumber} has an invalid `@t` timestamp property; the value must be a JSON string.";
+ rawFormat = default;
+ return false;
+ }
+
+ if (!DateTimeOffset.TryParse(rawTimestamp.Value(), out _))
+ {
+ error = $"The timestamp value `{rawTimestamp}` on line {lineNumber} could not be parsed.";
+ rawFormat = default;
+ return false;
+ }
+
+ result.Add("Timestamp", rawTimestamp);
+
+ var properties = new JObject();
+ foreach (var property in compactFormat.Properties())
+ {
+ if (property.Name.StartsWith("@@"))
+ properties.Add(property.Name.Substring(1), property.Value);
+ else if (!ClefReifiedProperties.Contains(property.Name))
+ properties.Add(property.Name, property.Value);
+ }
- if (rawTimestamp.Type != JTokenType.String)
+ var x = compactFormat["@x"];
+ if (x != null)
+ {
+ if (x.Type != JTokenType.String)
{
- error = $"The event on line {lineNumber} has an invalid `@t` timestamp property; the value must be a JSON string.";
+ error = $"The event on line {lineNumber} has a non-string `@x` exception property.";
rawFormat = default;
return false;
}
- if (!DateTimeOffset.TryParse(rawTimestamp.Value(), out _))
+ result.Add("Exception", x);
+ }
+
+ var l = compactFormat["@l"];
+ if (l != null)
+ {
+ if (l.Type != JTokenType.String)
{
- error = $"The timestamp value `{rawTimestamp}` on line {lineNumber} could not be parsed.";
+ error = $"The event on line {lineNumber} has a non-string `@l` level property.";
rawFormat = default;
return false;
}
- result.Add("Timestamp", rawTimestamp);
+ result.Add("Level", l);
+ }
- var properties = new JObject();
- foreach (var property in compactFormat.Properties())
+ string? message = null;
+ var m = compactFormat["@m"];
+ if (m != null)
+ {
+ if (m.Type != JTokenType.String)
{
- if (property.Name.StartsWith("@@"))
- properties.Add(property.Name.Substring(1), property.Value);
- else if (!ClefReifiedProperties.Contains(property.Name))
- properties.Add(property.Name, property.Value);
+ error = $"The event on line {lineNumber} has a non-string `@m` message property.";
+ rawFormat = default;
+ return false;
}
- var x = compactFormat["@x"];
- if (x != null)
- {
- if (x.Type != JTokenType.String)
- {
- error = $"The event on line {lineNumber} has a non-string `@x` exception property.";
- rawFormat = default;
- return false;
- }
-
- result.Add("Exception", x);
- }
+ message = m.Value();
+ }
- var l = compactFormat["@l"];
- if (l != null)
+ string? messageTemplate = null;
+ var mt = compactFormat["@mt"];
+ if (mt != null)
+ {
+ if (mt.Type != JTokenType.String)
{
- if (l.Type != JTokenType.String)
- {
- error = $"The event on line {lineNumber} has a non-string `@l` level property.";
- rawFormat = default;
- return false;
- }
-
- result.Add("Level", l);
+ error = $"The event on line {lineNumber} has a non-string `@mt` message template property.";
+ rawFormat = default;
+ return false;
}
- string? message = null;
- var m = compactFormat["@m"];
- if (m != null)
- {
- if (m.Type != JTokenType.String)
- {
- error = $"The event on line {lineNumber} has a non-string `@m` message property.";
- rawFormat = default;
- return false;
- }
+ messageTemplate = mt.Value();
+ }
- message = m.Value();
- }
+ if (message != null)
+ {
+ result.Add("RenderedMessage", message);
+ }
+ else if (messageTemplate != null && compactFormat["@r"] is JArray renderingsArray)
+ {
+ var template = MessageTemplateParser.Parse(messageTemplate);
+ var withFormat = template.Tokens.OfType().Where(pt => pt.Format != null);
- string? messageTemplate = null;
- var mt = compactFormat["@mt"];
- if (mt != null)
+ // ReSharper disable once PossibleMultipleEnumeration
+ if (withFormat.Count() == renderingsArray.Count)
{
- if (mt.Type != JTokenType.String)
- {
- error = $"The event on line {lineNumber} has a non-string `@mt` message template property.";
- rawFormat = default;
- return false;
- }
+ // ReSharper disable once PossibleMultipleEnumeration
+ var renderingsByProperty = withFormat
+ .Zip(renderingsArray, (p, j) => new { p.PropertyName, Format = p.Format!, Rendering = j.Value() })
+ .GroupBy(p => p.PropertyName)
+ .ToDictionary(g => g.Key, g => g.ToDictionaryDistinct(p => p.Format, p => p.Rendering));
- messageTemplate = mt.Value();
- }
+ var renderings = new JObject();
+ result.Add("Renderings", renderings);
- if (message != null)
- {
- result.Add("RenderedMessage", message);
- }
- else if (messageTemplate != null && compactFormat["@r"] is JArray renderingsArray)
- {
- var template = MessageTemplateParser.Parse(messageTemplate);
- var withFormat = template.Tokens.OfType().Where(pt => pt.Format != null);
-
- // ReSharper disable once PossibleMultipleEnumeration
- if (withFormat.Count() == renderingsArray.Count)
+ foreach (var (property, propertyRenderings) in renderingsByProperty)
{
- // ReSharper disable once PossibleMultipleEnumeration
- var renderingsByProperty = withFormat
- .Zip(renderingsArray, (p, j) => new { p.PropertyName, Format = p.Format!, Rendering = j.Value() })
- .GroupBy(p => p.PropertyName)
- .ToDictionary(g => g.Key, g => g.ToDictionaryDistinct(p => p.Format, p => p.Rendering));
-
- var renderings = new JObject();
- result.Add("Renderings", renderings);
+ var byFormat = new JArray();
+ renderings.Add(property, byFormat);
- foreach (var (property, propertyRenderings) in renderingsByProperty)
+ foreach (var (format, rendering) in propertyRenderings)
{
- var byFormat = new JArray();
- renderings.Add(property, byFormat);
-
- foreach (var (format, rendering) in propertyRenderings)
- {
- var element = new JObject {{"Format", format}, {"Rendering", rendering}};
- byFormat.Add(element);
- }
+ var element = new JObject {{"Format", format}, {"Rendering", rendering}};
+ byFormat.Add(element);
}
}
}
+ }
- messageTemplate ??= message ?? "No template provided";
- result.Add("MessageTemplate", messageTemplate);
+ messageTemplate ??= message ?? "No template provided";
+ result.Add("MessageTemplate", messageTemplate);
- var eventTypeToken = compactFormat["@i"];
- if (eventTypeToken != null)
+ var eventTypeToken = compactFormat["@i"];
+ if (eventTypeToken != null)
+ {
+ if (eventTypeToken.Type == JTokenType.Integer)
{
- if (eventTypeToken.Type == JTokenType.Integer)
- {
- result.Add("EventType", uint.Parse(eventTypeToken.Value()!));
- }
- else if (eventTypeToken.Type == JTokenType.String)
- {
- if (uint.TryParse(eventTypeToken.Value(), NumberStyles.HexNumber,
+ result.Add("EventType", uint.Parse(eventTypeToken.Value()!));
+ }
+ else if (eventTypeToken.Type == JTokenType.String)
+ {
+ if (uint.TryParse(eventTypeToken.Value