diff --git a/src/InEngine.Commands.Test/InEngine.Commands.Test.csproj b/src/InEngine.Commands.Test/InEngine.Commands.Test.csproj
new file mode 100644
index 0000000..e48d527
--- /dev/null
+++ b/src/InEngine.Commands.Test/InEngine.Commands.Test.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/InEngine.Commands.Test/Sample/MinimalTest.cs b/src/InEngine.Commands.Test/Sample/MinimalTest.cs
new file mode 100644
index 0000000..2f5f712
--- /dev/null
+++ b/src/InEngine.Commands.Test/Sample/MinimalTest.cs
@@ -0,0 +1,22 @@
+using InEngine.Commands.Sample;
+using InEngine.Core.IO;
+using InEngineTesting;
+using Moq;
+
+namespace InEngine.Commands.Test.Sample;
+
+public class MinimalTest : TestBase
+{
+ [Test]
+ public async Task ShouldSucceed()
+ {
+ const string expected = "This is an example of a minimal command.";
+ var mockWrite = new Mock();
+ Subject.Write = mockWrite.Object;
+
+ await Subject.RunAsync();
+
+ mockWrite.Verify(x => x.Line(expected), Times.Once());
+ Assert.Pass();
+ }
+}
\ No newline at end of file
diff --git a/src/InEngine.Commands.Test/Sample/SayHelloTest.cs b/src/InEngine.Commands.Test/Sample/SayHelloTest.cs
new file mode 100644
index 0000000..faa9fd7
--- /dev/null
+++ b/src/InEngine.Commands.Test/Sample/SayHelloTest.cs
@@ -0,0 +1,22 @@
+using InEngine.Commands.Sample;
+using InEngine.Core.IO;
+using InEngineTesting;
+using Moq;
+
+namespace InEngine.Commands.Test.Sample;
+
+public class SayHelloTest : TestBase
+{
+ [Test]
+ public async Task ShouldSayHelloTest()
+ {
+ const string expected = "hello";
+ var mockWrite = new Mock();
+ Subject.Write = mockWrite.Object;
+
+ await Subject.RunAsync();
+
+ mockWrite.Verify(x => x.Line(expected), Times.Once());
+ Assert.Pass();
+ }
+}
\ No newline at end of file
diff --git a/src/InEngine.Commands.Test/Usings.cs b/src/InEngine.Commands.Test/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/src/InEngine.Commands.Test/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file
diff --git a/src/InEngine.Commands/CommandsPlugin.cs b/src/InEngine.Commands/CommandsPlugin.cs
index 9714d09..c69a472 100644
--- a/src/InEngine.Commands/CommandsPlugin.cs
+++ b/src/InEngine.Commands/CommandsPlugin.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using CommandLine;
using InEngine.Core;
using InEngine.Core.Commands;
using InEngine.Core.Scheduling;
@@ -8,12 +7,6 @@ namespace InEngine.Commands;
public class CommandsPlugin : AbstractPlugin
{
- [VerbOption("fail", HelpText = "Always fail. Useful for end-to-end testing.")]
- public AlwaysFail AlwaysFail { get; set; }
-
- [VerbOption("succeed", HelpText = "A null operation command. Literally does nothing.")]
- public AlwaysSucceed Null { get; set; }
-
public override void Schedule(ISchedule schedule)
{
schedule.Command(new Echo { VerbatimText = "Core Echo command." })
diff --git a/src/InEngine.Commands/InEngine.Commands.csproj b/src/InEngine.Commands/InEngine.Commands.csproj
index e2e5e00..52f67ca 100644
--- a/src/InEngine.Commands/InEngine.Commands.csproj
+++ b/src/InEngine.Commands/InEngine.Commands.csproj
@@ -4,7 +4,7 @@
5.0.0
- 4.0.0
+ 5.0.0
5.0.0
Ethan Hann
Plugin-based queuing and scheduling command server.
diff --git a/src/InEngine.Commands/Sample/ShowProgress.cs b/src/InEngine.Commands/Sample/ShowProgress.cs
index e9bd69b..01c331f 100644
--- a/src/InEngine.Commands/Sample/ShowProgress.cs
+++ b/src/InEngine.Commands/Sample/ShowProgress.cs
@@ -3,16 +3,11 @@
namespace InEngine.Commands.Sample;
-/*
- * The AbstractCommand class adds functionality, including a logger and a
- * progress bar.
- */
+///
+/// The AbstractCommand class adds functionality, including a logger and a progress bar.
+///
public class ShowProgress : AbstractCommand
{
- /*
- * Note that the override keyword is necessary in the Run method
- * signature as the base class method is virtual.
- */
public override async Task RunAsync()
{
// Define the ticks (aka steps) for the command...
diff --git a/src/InEngine.Core.Test/Commands/AlwaysFailTest.cs b/src/InEngine.Core.Test/Commands/AlwaysFailTest.cs
new file mode 100644
index 0000000..a5a92db
--- /dev/null
+++ b/src/InEngine.Core.Test/Commands/AlwaysFailTest.cs
@@ -0,0 +1,20 @@
+using InEngine.Core.Commands;
+using InEngine.Core.Exceptions;
+using InEngineTesting;
+
+namespace InEngine.Core.Test.Commands;
+
+public class AlwaysFailTest : TestBase
+{
+ [Test]
+ public void ShouldFailWithException()
+ {
+ Assert.ThrowsAsync(async () => await Subject.RunAsync());
+ }
+
+ [Test]
+ public void ShouldFailWithExceptionWhenRunWithLifeCycleMethods()
+ {
+ Assert.ThrowsAsync(async () => await Subject.RunWithLifeCycleAsync());
+ }
+}
\ No newline at end of file
diff --git a/src/InEngine.Core.Test/Commands/AlwaysSucceedTest.cs b/src/InEngine.Core.Test/Commands/AlwaysSucceedTest.cs
new file mode 100644
index 0000000..2bd7b3c
--- /dev/null
+++ b/src/InEngine.Core.Test/Commands/AlwaysSucceedTest.cs
@@ -0,0 +1,23 @@
+using System.Threading.Tasks;
+using InEngine.Core.Commands;
+using InEngine.Core.IO;
+using InEngineTesting;
+using Moq;
+
+namespace InEngine.Core.Test.Commands;
+
+public class AlwaysSucceedTest : TestBase
+{
+ [Test]
+ public async Task ShouldSucceed()
+ {
+ const string expected = "This command always succeeds.";
+ var mockWrite = new Mock();
+ Subject.Write = mockWrite.Object;
+
+ await Subject.RunAsync();
+
+ mockWrite.Verify(x => x.Info(expected), Times.Once());
+ Assert.Pass();
+ }
+}
\ No newline at end of file
diff --git a/src/InEngine.Core.Test/Commands/ChainTest.cs b/src/InEngine.Core.Test/Commands/ChainTest.cs
index 12eb97f..8318b85 100644
--- a/src/InEngine.Core.Test/Commands/ChainTest.cs
+++ b/src/InEngine.Core.Test/Commands/ChainTest.cs
@@ -1,9 +1,9 @@
using System.Collections.Generic;
-using InEngine.Commands;
using InEngine.Core.Commands;
using InEngine.Core.Exceptions;
+using System.Threading.Tasks;
+using InEngineTesting;
using Moq;
-using NUnit.Framework;
namespace InEngine.Core.Test.Commands;
@@ -16,7 +16,7 @@ public void Setup()
}
[Test]
- public void ShouldRunChainOfCommands()
+ public async Task ShouldRunChainOfCommands()
{
var mockCommand1 = new Mock();
var mockCommand2 = new Mock();
@@ -27,7 +27,7 @@ public void ShouldRunChainOfCommands()
};
Subject.Commands = commands;
- Subject.RunAsync();
+ await Subject.RunAsync();
mockCommand1.Verify(x => x.RunAsync(), Times.Once());
mockCommand2.Verify(x => x.RunAsync(), Times.Once());
@@ -47,26 +47,26 @@ public void ShouldRunChainOfCommandsAndFail()
};
Subject.Commands = commands;
- Assert.That(Subject.RunAsync, Throws.TypeOf());
+ Assert.ThrowsAsync(async () => await Subject.RunAsync());
mockCommand1.Verify(x => x.RunAsync(), Times.Once());
mockCommand2.Verify(x => x.RunAsync(), Times.Never());
}
[Test]
- public void ShouldRunChainOfDifferentCommands()
+ public async Task ShouldRunChainOfDifferentCommands()
{
Subject.Commands = new List
{
new AlwaysSucceed(),
- new Echo() { VerbatimText = "Hello, world!" },
+ new Echo { VerbatimText = "Hello, world!" },
};
- Subject.RunAsync();
+ await Subject.RunAsync();
}
[Test]
- public void ShouldRunChainOfDifferentCommandsAsAbstractCommand()
+ public async Task ShouldRunChainOfDifferentCommandsAsAbstractCommand()
{
Subject.Commands = new AbstractCommand[]
{
@@ -74,6 +74,6 @@ public void ShouldRunChainOfDifferentCommandsAsAbstractCommand()
new Echo(verbatimText: "Hello, world!"),
};
- Subject.RunAsync();
+ await Subject.RunAsync();
}
}
\ No newline at end of file
diff --git a/src/InEngine.Core.Test/InEngine.Core.Test.csproj b/src/InEngine.Core.Test/InEngine.Core.Test.csproj
index d3323bc..1d2136b 100644
--- a/src/InEngine.Core.Test/InEngine.Core.Test.csproj
+++ b/src/InEngine.Core.Test/InEngine.Core.Test.csproj
@@ -6,7 +6,7 @@
- 4.0.0
+ 5.0.0
5.0.0
Ethan Hann
Plugin-based queuing and scheduling command server.
@@ -15,14 +15,15 @@
-
-
-
+
+
+
+
diff --git a/src/InEngine.Core.Test/Queuing/Commands/ConsumeTest.cs b/src/InEngine.Core.Test/Queuing/Commands/ConsumeTest.cs
index 981da6c..d87c557 100644
--- a/src/InEngine.Core.Test/Queuing/Commands/ConsumeTest.cs
+++ b/src/InEngine.Core.Test/Queuing/Commands/ConsumeTest.cs
@@ -1,11 +1,12 @@
using InEngine.Commands;
using InEngine.Core.Queuing.Commands;
using Moq;
-using NUnit.Framework;
using Quartz;
namespace InEngine.Core.Test.Queuing.Commands;
+using InEngineTesting;
+
[TestFixture]
public class ConsumeTest : TestBase
{
diff --git a/src/InEngine.Core.Test/Queuing/Commands/PublishTest.cs b/src/InEngine.Core.Test/Queuing/Commands/PublishTest.cs
index 7a98e84..fe5228e 100644
--- a/src/InEngine.Core.Test/Queuing/Commands/PublishTest.cs
+++ b/src/InEngine.Core.Test/Queuing/Commands/PublishTest.cs
@@ -3,8 +3,8 @@
using InEngine.Commands;
using InEngine.Core.Commands;
using InEngine.Core.Exceptions;
+using InEngineTesting;
using InEngine.Core.Queuing.Commands;
-using NUnit.Framework;
namespace InEngine.Core.Test.Queuing.Commands;
diff --git a/src/InEngine.Core.Test/Queuing/Enqueue.cs b/src/InEngine.Core.Test/Queuing/Enqueue.cs
index 0a94f06..0b93205 100644
--- a/src/InEngine.Core.Test/Queuing/Enqueue.cs
+++ b/src/InEngine.Core.Test/Queuing/Enqueue.cs
@@ -4,7 +4,6 @@
using InEngine.Core.Commands;
using InEngine.Core.Queuing;
using Moq;
-using NUnit.Framework;
using Serialize.Linq.Extensions;
namespace InEngine.Core.Test.Queuing;
diff --git a/src/InEngine.Core.Test/Queuing/QueueAdapterTest.cs b/src/InEngine.Core.Test/Queuing/QueueAdapterTest.cs
index b295500..423d07e 100644
--- a/src/InEngine.Core.Test/Queuing/QueueAdapterTest.cs
+++ b/src/InEngine.Core.Test/Queuing/QueueAdapterTest.cs
@@ -3,8 +3,8 @@
using InEngine.Commands;
using InEngine.Core.Commands;
using InEngine.Core.Queuing;
+using InEngineTesting;
using Moq;
-using NUnit.Framework;
using Serialize.Linq.Extensions;
namespace InEngine.Core.Test.Queuing;
diff --git a/src/InEngine.Core.Test/Scheduling/ScheduleTest.cs b/src/InEngine.Core.Test/Scheduling/ScheduleTest.cs
index a950e0f..91f2919 100644
--- a/src/InEngine.Core.Test/Scheduling/ScheduleTest.cs
+++ b/src/InEngine.Core.Test/Scheduling/ScheduleTest.cs
@@ -1,7 +1,7 @@
using System;
-using InEngine.Commands;
+using InEngine.Core.Commands;
using InEngine.Core.Scheduling;
-using NUnit.Framework;
+using InEngineTesting;
namespace InEngine.Core.Test.Scheduling;
diff --git a/src/InEngine.Core.Test/Usings.cs b/src/InEngine.Core.Test/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/src/InEngine.Core.Test/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file
diff --git a/src/InEngine.Core/AbstractCommand.cs b/src/InEngine.Core/AbstractCommand.cs
index 7a93485..1ee59bb 100644
--- a/src/InEngine.Core/AbstractCommand.cs
+++ b/src/InEngine.Core/AbstractCommand.cs
@@ -9,6 +9,7 @@
namespace InEngine.Core;
+using System.Threading;
using Microsoft.Extensions.Logging;
public abstract class AbstractCommand : IJob, IConsoleWrite, IHasCommandLifeCycle, IHasMailSettings
@@ -16,7 +17,7 @@ public abstract class AbstractCommand : IJob, IConsoleWrite, IHasCommandLifeCycl
protected readonly ILogger Log;
public CommandLifeCycle CommandLifeCycle { get; set; } = new CommandLifeCycle();
- public Write Write { get; set; } = new Write();
+ public IConsoleWrite Write { get; set; } = new Write();
public ProgressBar ProgressBar { get; internal set; }
public string Name { get; set; }
public string SchedulerGroup { get; set; }
@@ -43,9 +44,13 @@ public virtual void Run()
{
}
- public virtual async Task RunAsync() => await Task.Run(Run).ConfigureAwait(false);
-
- public virtual async Task RunWithLifeCycle()
+ public virtual async Task RunAsync()
+ {
+ Run();
+ await Task.CompletedTask;
+ }
+
+ public virtual async Task RunWithLifeCycleAsync()
{
try
{
@@ -54,9 +59,16 @@ public virtual async Task RunWithLifeCycle()
await RunAsync();
else
{
- var task = Task.Run(RunAsync);
- if (!task.Wait(TimeSpan.FromSeconds(SecondsBeforeTimeout)))
- throw new Exception($"Scheduled command timed out after {SecondsBeforeTimeout} second(s).");
+ var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(SecondsBeforeTimeout));
+ try
+ {
+ await RunAsync().WaitAsync(timeoutSignal.Token).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+ throw new CommandFailedException(
+ $"Scheduled command timed out after {SecondsBeforeTimeout} second(s).");
+ }
}
CommandLifeCycle.FirePostActions(this);
@@ -97,23 +109,43 @@ public virtual async Task Execute(IJobExecutionContext context)
});
}
- await RunWithLifeCycle();
+ await RunWithLifeCycleAsync();
}
#endregion
- #region Console output
+ #region Console Output
public IConsoleWrite Info(object val) => Write.Info(val);
public IConsoleWrite Warning(object val) => Write.Warning(val);
public IConsoleWrite Error(object val) => Write.Error(val);
public IConsoleWrite Line(object val) => Write.Line(val);
- public IConsoleWrite ColoredLine(object val, ConsoleColor consoleColor) => Write.ColoredLine(val, consoleColor);
+ public IConsoleWrite LineWithColor(object val, ConsoleColor consoleColor) => Write.LineWithColor(val, consoleColor);
public IConsoleWrite InfoText(object val) => Write.InfoText(val);
public IConsoleWrite WarningText(object val) => Write.WarningText(val);
public IConsoleWrite ErrorText(object val) => Write.ErrorText(val);
public IConsoleWrite Text(object val) => Write.Text(val);
- public IConsoleWrite ColoredText(object val, ConsoleColor consoleColor) => Write.ColoredText(val, consoleColor);
+
+ public IConsoleWrite TextWithColor(object val, ConsoleColor consoleColor, bool writeLine) =>
+ Write.TextWithColor(val, consoleColor, writeLine);
+
+ public async Task NewlineAsync(int count = 1) => await Write.NewlineAsync(count);
+ public async Task InfoAsync(object val) => await Write.InfoAsync(val);
+ public async Task WarningAsync(object val) => await Write.WarningAsync(val);
+ public async Task ErrorAsync(object val) => await Write.ErrorAsync(val);
+ public async Task LineAsync(object val) => await Write.LineAsync(val);
+
+ public async Task LineWithColorAsync(object val, ConsoleColor consoleColor) =>
+ await Write.LineWithColorAsync(val, consoleColor);
+
+ public async Task InfoTextAsync(object val) => await Write.InfoTextAsync(val);
+ public async Task WarningTextAsync(object val) => await Write.WarningTextAsync(val);
+ public async Task ErrorTextAsync(object val) => await Write.ErrorTextAsync(val);
+ public async Task TextAsync(object val) => await Write.TextAsync(val);
+
+ public async Task TextWithColorAsync(object val, ConsoleColor consoleColor, bool writeLine = false) =>
+ await Write.TextWithColorAsync(val, consoleColor, writeLine);
+
public IConsoleWrite Newline(int count = 1) => Write.Newline(count);
public string FlushBuffer() => Write.FlushBuffer();
public void ToFile(string path, string text, bool shouldAppend = false) => Write.ToFile(path, text, shouldAppend);
diff --git a/src/InEngine.Commands/AlwaysFail.cs b/src/InEngine.Core/Commands/AlwaysFail.cs
similarity index 59%
rename from src/InEngine.Commands/AlwaysFail.cs
rename to src/InEngine.Core/Commands/AlwaysFail.cs
index b052d7f..00ac345 100644
--- a/src/InEngine.Commands/AlwaysFail.cs
+++ b/src/InEngine.Core/Commands/AlwaysFail.cs
@@ -1,15 +1,18 @@
using System;
-using InEngine.Core;
+using System.Threading.Tasks;
using InEngine.Core.Exceptions;
-namespace InEngine.Commands;
+namespace InEngine.Core.Commands;
///
-/// Dummy command for testing and sample code.
+/// Dummy command for testing.
///
public class AlwaysFail : AbstractCommand
{
- public override void Run() => throw new CommandFailedException("This command always fails.");
+ public override async Task RunAsync()
+ {
+ throw new CommandFailedException("This command always fails.");
+ }
public override void Failed(Exception exception)
{
diff --git a/src/InEngine.Commands/AlwaysSucceed.cs b/src/InEngine.Core/Commands/AlwaysSucceed.cs
similarity index 59%
rename from src/InEngine.Commands/AlwaysSucceed.cs
rename to src/InEngine.Core/Commands/AlwaysSucceed.cs
index a288983..0d9971f 100644
--- a/src/InEngine.Commands/AlwaysSucceed.cs
+++ b/src/InEngine.Core/Commands/AlwaysSucceed.cs
@@ -1,9 +1,7 @@
-using InEngine.Core;
-
-namespace InEngine.Commands;
+namespace InEngine.Core.Commands;
///
-/// Dummy command for testing and sample code.
+/// Dummy command for testing.
///
public class AlwaysSucceed : AbstractCommand
{
diff --git a/src/InEngine.Core/Commands/CommandsPlugin.cs b/src/InEngine.Core/Commands/CommandsPlugin.cs
index 21d77e4..764ee7e 100644
--- a/src/InEngine.Core/Commands/CommandsPlugin.cs
+++ b/src/InEngine.Core/Commands/CommandsPlugin.cs
@@ -9,4 +9,13 @@ public class CommandPlugin : AbstractPlugin
[VerbOption("exec", HelpText = "Execute an external program.")]
public Exec Exec { get; set; }
+
+ [VerbOption("sleep", HelpText = "Sleep (in seconds)")]
+ public Sleep Sleep { get; set; }
+
+ [VerbOption("fail", HelpText = "Always fail. Useful for end-to-end testing.")]
+ public AlwaysFail AlwaysFail { get; set; }
+
+ [VerbOption("succeed", HelpText = "A null operation command. Literally does nothing.")]
+ public AlwaysSucceed AlwaysSucceed { get; set; }
}
\ No newline at end of file
diff --git a/src/InEngine.Core/Commands/Echo.cs b/src/InEngine.Core/Commands/Echo.cs
index 8f644ed..e80c73d 100644
--- a/src/InEngine.Core/Commands/Echo.cs
+++ b/src/InEngine.Core/Commands/Echo.cs
@@ -1,4 +1,6 @@
-using CommandLine;
+using System;
+using System.Threading.Tasks;
+using CommandLine;
namespace InEngine.Core.Commands;
@@ -16,5 +18,5 @@ public Echo()
[Option("text", HelpText = "The text to echo.")]
public string VerbatimText { get; init; }
- public override void Run() => Line(VerbatimText);
+ public override async Task RunAsync() => await LineAsync(VerbatimText);
}
\ No newline at end of file
diff --git a/src/InEngine.Core/Commands/Sleep.cs b/src/InEngine.Core/Commands/Sleep.cs
index 49334ba..8845e0e 100644
--- a/src/InEngine.Core/Commands/Sleep.cs
+++ b/src/InEngine.Core/Commands/Sleep.cs
@@ -3,14 +3,17 @@
namespace InEngine.Core.Commands;
+using CommandLine;
+
public class Sleep : AbstractCommand
{
- public int MillisecondsTimeout { get; set; }
+ [Option("duration", HelpText = "The number of seconds to sleep.")]
+ public int DurationInSeconds { get; set; } = 3;
- public override void Run()
+ public override async Task RunAsync()
{
- Warning("Going to sleep...");
- Thread.Sleep(MillisecondsTimeout);
- Info("Done sleeping!");
+ await WarningAsync("Going to sleep...");
+ Thread.Sleep(DurationInSeconds * 1000);
+ await InfoAsync("Done sleeping!");
}
}
\ No newline at end of file
diff --git a/src/InEngine.Core/IO/IConsoleWrite.cs b/src/InEngine.Core/IO/IConsoleWrite.cs
new file mode 100644
index 0000000..80f2369
--- /dev/null
+++ b/src/InEngine.Core/IO/IConsoleWrite.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace InEngine.Core.IO;
+
+using System.Threading.Tasks;
+
+public interface IConsoleWrite
+{
+ #region Sync Methods
+
+ IConsoleWrite Newline(int count = 1);
+ IConsoleWrite Info(object val);
+ IConsoleWrite Warning(object val);
+ IConsoleWrite Error(object val);
+ IConsoleWrite Line(object val);
+ IConsoleWrite LineWithColor(object val, ConsoleColor consoleColor);
+
+ IConsoleWrite InfoText(object val);
+ IConsoleWrite WarningText(object val);
+ IConsoleWrite ErrorText(object val);
+ IConsoleWrite Text(object val);
+ IConsoleWrite TextWithColor(object val, ConsoleColor consoleColor, bool writeLine = false);
+
+ #endregion
+
+ #region Async Methods
+
+ Task NewlineAsync(int count = 1);
+ Task InfoAsync(object val);
+ Task WarningAsync(object val);
+ Task ErrorAsync(object val);
+ Task LineAsync(object val);
+ Task LineWithColorAsync(object val, ConsoleColor consoleColor);
+
+ Task InfoTextAsync(object val);
+ Task WarningTextAsync(object val);
+ Task ErrorTextAsync(object val);
+ Task TextAsync(object val);
+ Task TextWithColorAsync(object val, ConsoleColor consoleColor, bool writeLine = false);
+
+ #endregion
+
+ string FlushBuffer();
+ void ToFile(string path, string text, bool shouldAppend = false);
+}
\ No newline at end of file
diff --git a/src/InEngine.Core/IO/IWrite.cs b/src/InEngine.Core/IO/IWrite.cs
deleted file mode 100644
index 8155666..0000000
--- a/src/InEngine.Core/IO/IWrite.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-
-namespace InEngine.Core.IO;
-
-public interface IConsoleWrite
-{
- IConsoleWrite Newline(int count = 1);
- IConsoleWrite Info(object val);
- IConsoleWrite Warning(object val);
- IConsoleWrite Error(object val);
- IConsoleWrite Line(object val);
- IConsoleWrite ColoredLine(object val, ConsoleColor consoleColor);
-
- IConsoleWrite InfoText(object val);
- IConsoleWrite WarningText(object val);
- IConsoleWrite ErrorText(object val);
- IConsoleWrite Text(object val);
- IConsoleWrite ColoredText(object val, ConsoleColor consoleColor);
-
- string FlushBuffer();
- void ToFile(string path, string text, bool shouldAppend = false);
-}
\ No newline at end of file
diff --git a/src/InEngine.Core/IO/Write.cs b/src/InEngine.Core/IO/Write.cs
index 5ddaea4..8622c9e 100644
--- a/src/InEngine.Core/IO/Write.cs
+++ b/src/InEngine.Core/IO/Write.cs
@@ -2,29 +2,29 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
+using System.Threading.Tasks;
namespace InEngine.Core.IO;
public class Write : IConsoleWrite
{
- static readonly Mutex consoleOutputLock = new Mutex();
- static readonly Mutex fileOutputLock = new Mutex();
+ private static readonly Mutex ConsoleOutputLock = new();
+ public static readonly Mutex FileOutputLock = new();
public ConsoleColor InfoColor { get; set; } = ConsoleColor.Green;
public ConsoleColor WarningColor { get; set; } = ConsoleColor.Yellow;
public ConsoleColor ErrorColor { get; set; } = ConsoleColor.Red;
public ConsoleColor LineColor { get; set; } = ConsoleColor.White;
- public List Buffer { get; set; } = new List();
+ public List Buffer { get; set; } = new();
public bool IsBufferEnabled { get; set; }
public Write() : this(true)
{
}
- public Write(bool isBufferEnabled)
- {
- IsBufferEnabled = isBufferEnabled;
- }
+ public Write(bool isBufferEnabled) => IsBufferEnabled = isBufferEnabled;
+
+ #region Sync Methods
public IConsoleWrite Newline(int count = 1)
{
@@ -33,77 +33,90 @@ public IConsoleWrite Newline(int count = 1)
return this;
}
- public IConsoleWrite Info(object val)
- {
- return ColoredLine(val, InfoColor);
- }
+ public IConsoleWrite Info(object val) => LineWithColor(val, InfoColor);
+ public IConsoleWrite Error(object val) => LineWithColor(val, ErrorColor);
+ public IConsoleWrite Warning(object val) => LineWithColor(val, WarningColor);
+ public IConsoleWrite Line(object val) => LineWithColor(val, LineColor);
- public IConsoleWrite Error(object val)
+ public IConsoleWrite LineWithColor(object val, ConsoleColor consoleColor)
{
- return ColoredLine(val, ErrorColor);
+ TextWithColor(val, consoleColor, true);
+ return this;
}
- public IConsoleWrite Warning(object val)
- {
- return ColoredLine(val, WarningColor);
- }
+ public IConsoleWrite InfoText(object val) => TextWithColor(val, InfoColor);
+ public IConsoleWrite ErrorText(object val) => TextWithColor(val, ErrorColor);
+ public IConsoleWrite WarningText(object val) => TextWithColor(val, WarningColor);
+ public IConsoleWrite Text(object val) => TextWithColor(val, LineColor);
- public IConsoleWrite Line(object val)
+ public IConsoleWrite TextWithColor(object val, ConsoleColor consoleColor, bool writeLine = false)
{
- return ColoredLine(val, LineColor);
- }
+ var text = BeginWriting(val, consoleColor);
- public IConsoleWrite ColoredLine(object val, ConsoleColor consoleColor)
- {
- WriteColoredLineOrText(val, consoleColor, true);
+ if (writeLine)
+ Console.WriteLine(val);
+ else
+ Console.Write(val);
+
+ EndWriting(text, writeLine);
return this;
}
- public IConsoleWrite InfoText(object val)
- {
- return ColoredText(val, InfoColor);
- }
+ #endregion
- public IConsoleWrite ErrorText(object val)
- {
- return ColoredText(val, ErrorColor);
- }
+ #region Async Methods
- public IConsoleWrite WarningText(object val)
+ public async Task NewlineAsync(int count = 1)
{
- return ColoredText(val, WarningColor);
+ for (var i = 0; i < count; i++)
+ await Console.Out.WriteLineAsync();
}
- public IConsoleWrite Text(object val)
+ public async Task InfoAsync(object val) => await LineWithColorAsync(val, InfoColor);
+ public async Task ErrorAsync(object val) => await LineWithColorAsync(val, ErrorColor);
+ public async Task WarningAsync(object val) => await LineWithColorAsync(val, WarningColor);
+ public async Task LineAsync(object val) => await LineWithColorAsync(val, LineColor);
+
+ public async Task LineWithColorAsync(object val, ConsoleColor consoleColor) =>
+ await TextWithColorAsync(val, consoleColor, true);
+
+ public async Task InfoTextAsync(object val) => await TextWithColorAsync(val, InfoColor);
+ public async Task ErrorTextAsync(object val) => await TextWithColorAsync(val, ErrorColor);
+ public async Task WarningTextAsync(object val) => await TextWithColorAsync(val, WarningColor);
+ public async Task TextAsync(object val) => await TextWithColorAsync(val, LineColor);
+
+ public async Task TextWithColorAsync(object val, ConsoleColor consoleColor, bool writeLine = false)
{
- return ColoredText(val, LineColor);
+ var text = BeginWriting(val, consoleColor);
+
+ if (writeLine)
+ await Console.Out.WriteLineAsync(text);
+ else
+ await Console.Out.WriteAsync(text);
+
+ EndWriting(text, writeLine);
}
- public IConsoleWrite ColoredText(object val, ConsoleColor consoleColor)
+ #endregion
+
+ protected string BeginWriting(object val, ConsoleColor consoleColor)
{
- WriteColoredLineOrText(val, consoleColor, false);
- return this;
+ ConsoleOutputLock.WaitOne();
+ Console.ForegroundColor = consoleColor;
+ return val?.ToString() ?? string.Empty;
}
- void WriteColoredLineOrText(object val, ConsoleColor consoleColor, bool writeLine)
+ protected void EndWriting(string text, bool writeLine)
{
- if (val == null)
- val = String.Empty;
- consoleOutputLock.WaitOne();
- Console.ForegroundColor = consoleColor;
- if (writeLine)
- Console.WriteLine(val);
- else
- Console.Write(val);
Console.ResetColor();
if (IsBufferEnabled)
{
- Buffer.Add(val.ToString());
+ Buffer.Add(text);
if (writeLine)
Buffer.Add(Environment.NewLine);
}
- consoleOutputLock.ReleaseMutex();
+ ConsoleOutputLock.ReleaseMutex();
}
public string FlushBuffer()
@@ -115,12 +128,12 @@ public string FlushBuffer()
public void ToFile(string path, string text, bool shouldAppend = false)
{
- fileOutputLock.WaitOne();
+ FileOutputLock.WaitOne();
if (shouldAppend)
File.AppendAllText(path, text);
else
File.WriteAllText(path, text);
- fileOutputLock.ReleaseMutex();
+ FileOutputLock.ReleaseMutex();
}
}
\ No newline at end of file
diff --git a/src/InEngine.Core/InEngine.Core.csproj b/src/InEngine.Core/InEngine.Core.csproj
index 8d5bc71..afdd327 100644
--- a/src/InEngine.Core/InEngine.Core.csproj
+++ b/src/InEngine.Core/InEngine.Core.csproj
@@ -3,7 +3,7 @@
net6.0
- 4.0.1
+ 5.0.0
5.0.0
Ethan Hann
Plugin-based queuing and scheduling command server.
@@ -27,7 +27,7 @@
-
+
diff --git a/src/InEngine.Core/Queuing/Clients/FileClient.cs b/src/InEngine.Core/Queuing/Clients/FileClient.cs
index 1d9032d..06f7696 100644
--- a/src/InEngine.Core/Queuing/Clients/FileClient.cs
+++ b/src/InEngine.Core/Queuing/Clients/FileClient.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
using InEngine.Core.Exceptions;
using InEngine.Core.IO;
using InEngine.Core.Queuing.Message;
@@ -55,7 +56,7 @@ private void PublishToQueue(CommandEnvelope commandEnvelope, string queuePath)
);
}
- public void Consume(CancellationToken cancellationToken)
+ public async Task Consume(CancellationToken cancellationToken)
{
try
{
@@ -63,8 +64,7 @@ public void Consume(CancellationToken cancellationToken)
{
try
{
- if (Consume() == null)
- Thread.Sleep(5000);
+ await Consume();
}
catch (Exception exception)
{
@@ -84,7 +84,7 @@ public void Consume(CancellationToken cancellationToken)
}
}
- public ICommandEnvelope Consume()
+ public async Task Consume()
{
FileInfo fileInfo;
var inProgressFilePath = string.Empty;
@@ -107,7 +107,7 @@ public ICommandEnvelope Consume()
ConsumeLock.ReleaseMutex();
- var commandEnvelope = File.ReadAllText(inProgressFilePath).DeserializeFromJson();
+ var commandEnvelope = (await File.ReadAllTextAsync(inProgressFilePath)).DeserializeFromJson();
var command = commandEnvelope.GetCommandInstanceAndIncrementRetry(() =>
{
File.Move(inProgressFilePath, Path.Combine(FailedQueuePath, fileInfo.Name));
@@ -116,7 +116,7 @@ public ICommandEnvelope Consume()
try
{
command.WriteSummaryToConsole();
- command.RunWithLifeCycle().RunSynchronously();
+ await command.RunWithLifeCycleAsync();
}
catch (Exception exception)
{
diff --git a/src/InEngine.Core/Queuing/Clients/RabbitMQClient.cs b/src/InEngine.Core/Queuing/Clients/RabbitMQClient.cs
index fd36aec..cb8c58c 100644
--- a/src/InEngine.Core/Queuing/Clients/RabbitMQClient.cs
+++ b/src/InEngine.Core/Queuing/Clients/RabbitMQClient.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
using System.Threading;
+using System.Threading.Tasks;
using InEngine.Core.Exceptions;
using InEngine.Core.IO;
using InEngine.Core.Queuing.Message;
@@ -94,13 +95,18 @@ public void Recover()
{
}
- public void Consume(CancellationToken cancellationToken)
+ public async Task Consume(CancellationToken cancellationToken)
{
InitChannel();
var consumer = new EventingBasicConsumer(Channel);
- consumer.Received += (model, result) =>
+ consumer.Received += async (model, result) =>
{
var eventingConsumer = (EventingBasicConsumer)model;
+ if (eventingConsumer == null)
+ {
+ Log.LogWarning("EventingBasicConsumer is null while attempting to consume messages");
+ return;
+ }
var serializedMessage = Encoding.UTF8.GetString(result.Body);
var commandEnvelope = serializedMessage.DeserializeFromJson();
@@ -115,7 +121,7 @@ public void Consume(CancellationToken cancellationToken)
try
{
command.WriteSummaryToConsole();
- command.RunWithLifeCycle().RunSynchronously();
+ await command.RunWithLifeCycleAsync();
}
catch (Exception exception)
{
@@ -133,9 +139,11 @@ public void Consume(CancellationToken cancellationToken)
eventingConsumer.Model.BasicAck(result.DeliveryTag, false);
};
Channel.BasicConsume(queue: PendingQueueName, autoAck: false, consumer: consumer);
+
+ await Task.Yield();
}
- public ICommandEnvelope Consume()
+ public async Task Consume()
{
InitChannel();
var result = Channel.BasicGet(PendingQueueName, false);
@@ -155,7 +163,7 @@ public ICommandEnvelope Consume()
try
{
command.WriteSummaryToConsole();
- command.RunWithLifeCycle().RunSynchronously();
+ await command.RunWithLifeCycleAsync();
}
catch (Exception exception)
{
diff --git a/src/InEngine.Core/Queuing/Clients/RedisClient.cs b/src/InEngine.Core/Queuing/Clients/RedisClient.cs
index f65069c..c40b55e 100644
--- a/src/InEngine.Core/Queuing/Clients/RedisClient.cs
+++ b/src/InEngine.Core/Queuing/Clients/RedisClient.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
+using System.Threading.Channels;
using System.Threading.Tasks;
using InEngine.Core.Exceptions;
using InEngine.Core.IO;
@@ -29,7 +30,7 @@ public class RedisClient : IQueueClient
public string FailedQueueName => QueueBaseName + $":{QueueName}:{QueueNames.Failed}";
- public static Lazy lazyConnection = new Lazy(() =>
+ public static readonly Lazy LazyConnection = new(() =>
{
var redisConfig = ConfigurationOptions.Parse($"{ClientSettings.Host}:{ClientSettings.Port}");
redisConfig.Password = string.IsNullOrWhiteSpace(ClientSettings.Password) ? null : ClientSettings.Password;
@@ -37,9 +38,8 @@ public class RedisClient : IQueueClient
return ConnectionMultiplexer.Connect(redisConfig);
});
- public static ConnectionMultiplexer Connection => lazyConnection.Value;
+ public static ConnectionMultiplexer Connection => LazyConnection.Value;
- public ConnectionMultiplexer _connectionMultiplexer;
private bool isDisposed;
public IDatabase Redis => Connection.GetDatabase(ClientSettings.Database);
@@ -82,17 +82,16 @@ public void Recover()
PublishToChannel();
}
- public void Consume(CancellationToken cancellationToken)
+ public async Task Consume(CancellationToken cancellationToken)
{
try
{
InitChannel();
- Connection.GetSubscriber().Subscribe(RedisChannel,
- delegate
- {
- Task.Factory.StartNew(Consume, cancellationToken, TaskCreationOptions.LongRunning,
- TaskScheduler.Default);
- });
+ var channelMessageQueue = await Connection.GetSubscriber().SubscribeAsync(RedisChannel);
+ channelMessageQueue.OnMessage(async _ =>
+ {
+ await Consume();
+ });
}
catch (OperationCanceledException exception)
{
@@ -104,12 +103,11 @@ public void Consume(CancellationToken cancellationToken)
}
}
- public ICommandEnvelope Consume()
+ public async Task Consume()
{
var rawRedisMessageValue = Redis.ListRightPopLeftPush(PendingQueueName, InProgressQueueName);
var serializedMessage = rawRedisMessageValue.ToString();
- if (serializedMessage == null)
- return null;
+
var commandEnvelope = serializedMessage.DeserializeFromJson();
if (commandEnvelope == null)
throw new CommandFailedException("Could not deserialize the command.");
@@ -122,7 +120,7 @@ public ICommandEnvelope Consume()
try
{
command.WriteSummaryToConsole();
- command.RunWithLifeCycle().RunSynchronously();
+ await command.RunWithLifeCycleAsync();
}
catch (Exception exception)
{
@@ -189,11 +187,10 @@ public void Dispose()
private void Dispose(bool disposing)
{
- if (isDisposed)
+ if (isDisposed)
return;
- if (!disposing)
+ if (!disposing)
return;
- _connectionMultiplexer?.Dispose();
isDisposed = true;
}
}
\ No newline at end of file
diff --git a/src/InEngine.Core/Queuing/Clients/SyncClient.cs b/src/InEngine.Core/Queuing/Clients/SyncClient.cs
index c0758f6..340d076 100644
--- a/src/InEngine.Core/Queuing/Clients/SyncClient.cs
+++ b/src/InEngine.Core/Queuing/Clients/SyncClient.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
+using System.Threading.Tasks;
using InEngine.Core.IO;
using InEngine.Core.Queuing.Message;
@@ -43,12 +44,12 @@ public void Recover()
{
}
- public void Consume(CancellationToken cancellationToken)
+ public async Task Consume(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
- public ICommandEnvelope Consume()
+ public async Task Consume()
{
throw new NotImplementedException();
}
diff --git a/src/InEngine.Core/Queuing/Dequeue.cs b/src/InEngine.Core/Queuing/Dequeue.cs
index 8e4939b..a72bbd9 100644
--- a/src/InEngine.Core/Queuing/Dequeue.cs
+++ b/src/InEngine.Core/Queuing/Dequeue.cs
@@ -25,29 +25,26 @@ public Dequeue()
public async Task StartAsync()
{
- var allTasks = new List();
Log.LogDebug("Start dequeue tasks for primary queue...");
- allTasks.AddRange(MakeTasks(true, QueueSettings.PrimaryQueueConsumers));
+ await AddConsumers(false, QueueSettings.PrimaryQueueConsumers);
Log.LogDebug("Start dequeue tasks for secondary queue...");
- allTasks.AddRange(MakeTasks(false, QueueSettings.SecondaryQueueConsumers));
- await Task.WhenAll(allTasks);
+ await AddConsumers(true, QueueSettings.SecondaryQueueConsumers);
// Recover from restart, if necessary.
QueueAdapter.Make(false, QueueSettings, MailSettings).Recover();
QueueAdapter.Make(true, QueueSettings, MailSettings).Recover();
}
- IList MakeTasks(bool useSecondaryQueue = false, int numberOfTasks = 0)
+ private async Task AddConsumers(bool useSecondaryQueue = false, int numberOfTasks = 0)
{
- return Enumerable.Range(0, numberOfTasks).Select((i) => {
+ for (var i = 0; i < numberOfTasks; i++)
+ {
Log.LogDebug("Registering Dequeuer {I}", i);
- return Task.Factory.StartNew(() => {
- var queue = QueueAdapter.Make(useSecondaryQueue, QueueSettings, MailSettings);
- queue.Id = i;
- queueAdapters.Add(queue);
- queue.Consume(CancellationTokenSource.Token);
- }, TaskCreationOptions.LongRunning);
- }).ToList();
+ var queue = QueueAdapter.Make(useSecondaryQueue, QueueSettings, MailSettings);
+ queue.Id = i;
+ queueAdapters.Add(queue);
+ await queue.Consume(CancellationTokenSource.Token);
+ }
}
public void Dispose()
diff --git a/src/InEngine.Core/Queuing/IQueueClient.cs b/src/InEngine.Core/Queuing/IQueueClient.cs
index 99cd813..68b5035 100644
--- a/src/InEngine.Core/Queuing/IQueueClient.cs
+++ b/src/InEngine.Core/Queuing/IQueueClient.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Threading;
+using System.Threading.Tasks;
using InEngine.Core.Queuing.Message;
using InEngine.Core.IO;
using Microsoft.Extensions.Logging;
@@ -16,8 +17,8 @@ public interface IQueueClient : IHasMailSettings, IDisposable
string QueueName { get; set; }
bool UseCompression { get; set; }
void Publish(AbstractCommand command);
- void Consume(CancellationToken cancellationToken);
- ICommandEnvelope Consume();
+ Task Consume(CancellationToken cancellationToken);
+ Task Consume();
void Recover();
Dictionary GetQueueLengths();
bool ClearPendingQueue();
diff --git a/src/InEngine.Core/Queuing/Message/CommandEnvelope.cs b/src/InEngine.Core/Queuing/Message/CommandEnvelope.cs
index 52e0309..70b26e9 100644
--- a/src/InEngine.Core/Queuing/Message/CommandEnvelope.cs
+++ b/src/InEngine.Core/Queuing/Message/CommandEnvelope.cs
@@ -24,7 +24,7 @@ public AbstractCommand GetCommandInstanceAndIncrementRetry(Action actionOnFail =
}
catch (Exception exception)
{
- actionOnFail.Invoke();
+ actionOnFail?.Invoke();
throw new CommandNotExtractableFromEnvelopeException(CommandClassName, exception);
}
}
diff --git a/src/InEngine.Core/Queuing/QueueAdapter.cs b/src/InEngine.Core/Queuing/QueueAdapter.cs
index 2fb0bc8..15d8b27 100644
--- a/src/InEngine.Core/Queuing/QueueAdapter.cs
+++ b/src/InEngine.Core/Queuing/QueueAdapter.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
+using System.Threading.Tasks;
using InEngine.Core.IO;
using InEngine.Core.Queuing.Clients;
using InEngine.Core.Queuing.Message;
@@ -89,8 +90,8 @@ public static QueueAdapter Make(bool useSecondaryQueue, QueueSettings queueSetti
}
public void Publish(AbstractCommand command) => QueueClient.Publish(command);
- public void Consume(CancellationToken cancellationToken) => QueueClient.Consume(cancellationToken);
- public ICommandEnvelope Consume() => QueueClient.Consume();
+ public async Task Consume(CancellationToken cancellationToken) => await QueueClient.Consume(cancellationToken);
+ public async Task Consume() => await QueueClient.Consume();
public void Recover() => QueueClient.Recover();
public bool ClearPendingQueue() => QueueClient.ClearPendingQueue();
public bool ClearInProgressQueue() => QueueClient.ClearInProgressQueue();
diff --git a/src/InEngine.Core/ServerHost.cs b/src/InEngine.Core/ServerHost.cs
index 15e87df..bddc7e6 100644
--- a/src/InEngine.Core/ServerHost.cs
+++ b/src/InEngine.Core/ServerHost.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading.Tasks;
using InEngine.Core.IO;
using InEngine.Core.Queuing;
using InEngine.Core.Scheduling;
@@ -13,7 +14,7 @@ public class ServerHost : IDisposable, IHasMailSettings, IHasQueueSettings
public QueueSettings QueueSettings { get; set; }
private bool isDisposed;
- public void Start()
+ public async Task StartAsync()
{
SuperScheduler = new SuperScheduler();
SuperScheduler.Initialize(MailSettings);
@@ -24,11 +25,9 @@ public void Start()
};
SuperScheduler.Start();
- StartDequeueAsync();
+ await Dequeue.StartAsync();
}
- public async void StartDequeueAsync() => await Dequeue.StartAsync();
-
public void Dispose()
{
Dispose(true);
diff --git a/src/InEngine.Net.sln b/src/InEngine.Net.sln
index 0872e7a..7be887f 100644
--- a/src/InEngine.Net.sln
+++ b/src/InEngine.Net.sln
@@ -16,6 +16,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InEngine.Commands", "InEngi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InEngine.Core.Test", "InEngine.Core.Test\InEngine.Core.Test.csproj", "{030204D0-6469-4A46-827E-122B0215F47E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InEngine.Commands.Test", "InEngine.Commands.Test\InEngine.Commands.Test.csproj", "{44C2AE5C-F3EB-4559-B712-534485AB18C1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InEngineTesting", "InEngineTesting\InEngineTesting.csproj", "{08FFCD33-8926-4E04-AC3B-91B6DFB71E61}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -38,6 +42,14 @@ Global
{030204D0-6469-4A46-827E-122B0215F47E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{030204D0-6469-4A46-827E-122B0215F47E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{030204D0-6469-4A46-827E-122B0215F47E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {44C2AE5C-F3EB-4559-B712-534485AB18C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {44C2AE5C-F3EB-4559-B712-534485AB18C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {44C2AE5C-F3EB-4559-B712-534485AB18C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {44C2AE5C-F3EB-4559-B712-534485AB18C1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {08FFCD33-8926-4E04-AC3B-91B6DFB71E61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08FFCD33-8926-4E04-AC3B-91B6DFB71E61}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08FFCD33-8926-4E04-AC3B-91B6DFB71E61}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08FFCD33-8926-4E04-AC3B-91B6DFB71E61}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/InEngine/ArgumentInterpreter.cs b/src/InEngine/ArgumentInterpreter.cs
index edae81f..c7432c1 100644
--- a/src/InEngine/ArgumentInterpreter.cs
+++ b/src/InEngine/ArgumentInterpreter.cs
@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using CommandLine;
using InEngine.Core;
using InEngine.Core.Exceptions;
using InEngine.Core.IO;
using InEngine.Core.Queuing;
-using System.Resources;
using Microsoft.Extensions.Logging;
namespace InEngine;
@@ -19,11 +19,10 @@ public class ArgumentInterpreter
public ArgumentInterpreter()
{
- var resourceManager = new ResourceManager("InEngine.resources", typeof(ArgumentInterpreter).Assembly);
- CliLogo = resourceManager.GetString("cliLogo");
+ CliLogo = resources.cliLogo;
}
- public void Interpret(string[] args)
+ public async Task Interpret(string[] args)
{
var pluginAssemblies = PluginAssembly.Load();
var parser = new Parser(with => {
@@ -44,7 +43,7 @@ public void Interpret(string[] args)
{
Write.Info(CliLogo);
Write.Line("Starting...").Newline();
- Program.RunServer();
+ await Program.RunServerAsync();
ExitWithSuccess();
}
diff --git a/src/InEngine/InEngine.csproj b/src/InEngine/InEngine.csproj
index 5ec28af..36d7ae1 100644
--- a/src/InEngine/InEngine.csproj
+++ b/src/InEngine/InEngine.csproj
@@ -6,7 +6,7 @@
- 4.0.0
+ 5.0.0
5.0.0
Ethan Hann
Plugin-based queuing and scheduling command server.
diff --git a/src/InEngine/Program.cs b/src/InEngine/Program.cs
index 806e8e2..63bd65b 100644
--- a/src/InEngine/Program.cs
+++ b/src/InEngine/Program.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Threading.Tasks;
using InEngine.Core;
namespace InEngine;
@@ -8,17 +9,17 @@ public static class Program
{
public static ServerHost ServerHost { get; set; }
- private static void Main(string[] args)
+ private static async Task Main(string[] args)
{
/*
* Set current working directory as services use the system directory by default.
* Also, allow running the CLI from a different directory than the application root.
*/
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
- new ArgumentInterpreter().Interpret(args);
+ await new ArgumentInterpreter().Interpret(args);
}
- public static void RunServer()
+ public static async Task RunServerAsync()
{
var settings = InEngineSettings.Make();
ServerHost = new ServerHost
@@ -27,8 +28,8 @@ public static void RunServer()
QueueSettings = settings.Queue,
};
- ServerHost.Start();
- Console.WriteLine("Press any key to exit...");
+ await ServerHost.StartAsync();
+ Console.WriteLine(resources.foregroundServerInputPrompt);
Console.ReadLine();
ServerHost.Dispose();
}
diff --git a/src/InEngine/resources.Designer.cs b/src/InEngine/resources.Designer.cs
index 0160ea5..3b1c984 100644
--- a/src/InEngine/resources.Designer.cs
+++ b/src/InEngine/resources.Designer.cs
@@ -50,5 +50,11 @@ internal static string cliLogo {
return ResourceManager.GetString("cliLogo", resourceCulture);
}
}
+
+ internal static string foregroundServerInputPrompt {
+ get {
+ return ResourceManager.GetString("foregroundServerInputPrompt", resourceCulture);
+ }
+ }
}
}
diff --git a/src/InEngine/resources.resx b/src/InEngine/resources.resx
index 10bffaa..8b5d142 100644
--- a/src/InEngine/resources.resx
+++ b/src/InEngine/resources.resx
@@ -26,4 +26,7 @@
|___|_| |_|_____|_| |_|\__, |_|_| |_|\___(_|_| \_|_____| |_|
|___/
+
+ Press any key to exit...
+
\ No newline at end of file
diff --git a/src/InEngineTesting/InEngineTesting.csproj b/src/InEngineTesting/InEngineTesting.csproj
new file mode 100644
index 0000000..07b23f6
--- /dev/null
+++ b/src/InEngineTesting/InEngineTesting.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/src/InEngine.Core.Test/TestBaseT.cs b/src/InEngineTesting/TestBaseT.cs
similarity index 87%
rename from src/InEngine.Core.Test/TestBaseT.cs
rename to src/InEngineTesting/TestBaseT.cs
index 2c85f62..9f88d07 100644
--- a/src/InEngine.Core.Test/TestBaseT.cs
+++ b/src/InEngineTesting/TestBaseT.cs
@@ -1,6 +1,6 @@
using NUnit.Framework;
-namespace InEngine.Core.Test;
+namespace InEngineTesting;
public abstract class TestBase where TSubject : new()
{