Skip to content

Commit 084b56f

Browse files
author
Jani Giannoudis
committed
command: added backend indicator (default: true)
refactored commnad manager for optional http client connection command: enhanced api error handling (scripting exceptions) updated version to 0.9.0-beta.3
1 parent 404fdd4 commit 084b56f

File tree

10 files changed

+142
-77
lines changed

10 files changed

+142
-77
lines changed

Client.Core/Command/CommandBase.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ public abstract class CommandBase : ICommand
1111
/// <inheritdoc />
1212
public virtual string Name => GetType().Name;
1313

14+
/// <inheritdoc />
15+
public virtual bool BackendCommand => true;
16+
1417
/// <inheritdoc />
1518
public abstract ICommandParameters GetParameters(CommandLineParser parser);
1619

@@ -59,12 +62,17 @@ protected void ProcessError(ICommandConsole console, Exception exception)
5962
return;
6063
}
6164

62-
// log
63-
Log.Error(exception, exception.GetBaseException().Message);
64-
65-
// display
66-
var message = exception.GetApiErrorMessage();
67-
console.DisplayErrorLine(message);
65+
// api error
66+
var apiError = exception.GetApiErrorMessage();
67+
if (!string.IsNullOrWhiteSpace(apiError))
68+
{
69+
console.DisplayErrorLine(apiError);
70+
}
71+
else
72+
{
73+
// generic error log
74+
Log.Error(exception, exception.GetBaseException().Message);
75+
}
6876
}
6977

7078
/// <summary>

Client.Core/Command/CommandContext.cs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,17 @@ public class CommandContext
1111
/// Command context.
1212
/// </summary>
1313
/// <param name="commandManager">Command manager.</param>
14-
/// <param name="console">Command console.</param>
15-
/// <param name="displayLevel">Command display level.</param>
16-
public CommandContext(CommandManager commandManager, ICommandConsole console, DisplayLevel displayLevel = DisplayLevel.Full)
17-
{
18-
CommandManager = commandManager ?? throw new ArgumentNullException(nameof(commandManager));
19-
Console = console ?? throw new ArgumentNullException(nameof(console));
20-
DisplayLevel = displayLevel;
21-
}
22-
23-
/// <summary>
24-
/// Command context.
25-
/// </summary>
26-
/// <param name="commandManager">Command manager.</param>
27-
/// <param name="httpClient">Http client.</param>
2814
/// <param name="logger">Command logger.</param>
2915
/// <param name="console">Command console.</param>
16+
/// <param name="httpClient">Http client.</param>
3017
/// <param name="displayLevel">Command display level.</param>
31-
public CommandContext(CommandManager commandManager, PayrollHttpClient httpClient,
32-
ILogger logger, ICommandConsole console, DisplayLevel displayLevel = DisplayLevel.Full)
18+
public CommandContext(CommandManager commandManager, ICommandConsole console, ILogger logger = null,
19+
PayrollHttpClient httpClient = null, DisplayLevel displayLevel = DisplayLevel.Full)
3320
{
3421
CommandManager = commandManager ?? throw new ArgumentNullException(nameof(commandManager));
3522
Console = console ?? throw new ArgumentNullException(nameof(console));
36-
HttpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
37-
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
23+
Logger = logger;
24+
HttpClient = httpClient;
3825
DisplayLevel = displayLevel;
3926
}
4027

Client.Core/Command/CommandLineParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public string Get(int index, string name = null, bool allowToggle = false)
109109
// name
110110
if (name != null)
111111
{
112-
var namedParameter = arg.IndexOf(':') > 0;
112+
var namedParameter = arg.StartsWith($"{name}:", StringComparison.InvariantCultureIgnoreCase);
113113
// ignore other named parameter
114114
if (namedParameter || !allowToggle && IsToggleArgument(arg))
115115
{

Client.Core/Command/CommandManager.cs

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,31 @@ public ICommand GetCommand(string name)
9595
return null;
9696
}
9797

98+
/// <summary>
99+
/// Get command line command
100+
/// </summary>
101+
public ICommand GetCommandLineCommand()
102+
{
103+
var parser = CommandLineParser.NewFromEnvironment();
104+
if (parser.Count == 0)
105+
{
106+
return null;
107+
}
108+
109+
var argCommand = parser.Get(1);
110+
if (string.IsNullOrWhiteSpace(argCommand))
111+
{
112+
return null;
113+
}
114+
115+
return GetCommand(argCommand);
116+
}
117+
98118
/// <summary>
99119
/// Execute command using the environment command line arguments
100120
/// </summary>
101121
/// <returns>Exit code</returns>
102-
public async Task<int> ExecuteAsync(PayrollHttpClient httpClient)
122+
public async Task<int> ExecuteAsync(PayrollHttpClient httpClient = null)
103123
{
104124
var parser = CommandLineParser.NewFromEnvironment();
105125
if (parser.Count == 0)
@@ -125,7 +145,7 @@ public async Task<int> ExecuteAsync(PayrollHttpClient httpClient)
125145
// command file
126146
if (!string.IsNullOrWhiteSpace(argCommand) && IsCommandFile(argCommand))
127147
{
128-
return await ExecuteFileAsync(httpClient, parser);
148+
return await ExecuteFileAsync(parser, httpClient);
129149
}
130150

131151
// single command using the environment command line parser
@@ -140,27 +160,23 @@ public async Task<int> ExecuteAsync(PayrollHttpClient httpClient)
140160
{
141161
return -1;
142162
}
143-
return await ExecuteAsync(httpClient, command, parser);
163+
return await ExecuteAsync(command, parser, httpClient);
144164
}
145165

146166
/// <summary>
147167
/// Execute specific command using the environment command line arguments
148168
/// </summary>
149169
/// <returns>Exit code</returns>
150-
public async Task<int> ExecuteAsync(PayrollHttpClient httpClient, ICommand command) =>
151-
await ExecuteAsync(httpClient, command, CommandLineParser.NewFromEnvironment());
170+
public async Task<int> ExecuteAsync(ICommand command, PayrollHttpClient httpClient = null) =>
171+
await ExecuteAsync(command, CommandLineParser.NewFromEnvironment(), httpClient);
152172

153173
/// <summary>
154174
/// Execute specific command using a custom command line parser
155175
/// </summary>
156176
/// <returns>Exit code</returns>
157-
private async Task<int> ExecuteAsync(PayrollHttpClient httpClient,
158-
ICommand command, CommandLineParser commandLineParser)
177+
private async Task<int> ExecuteAsync(ICommand command, CommandLineParser commandLineParser,
178+
PayrollHttpClient httpClient = null)
159179
{
160-
if (httpClient == null)
161-
{
162-
throw new ArgumentNullException(nameof(httpClient));
163-
}
164180
if (command == null)
165181
{
166182
throw new ArgumentNullException(nameof(command));
@@ -199,9 +215,9 @@ private async Task<int> ExecuteAsync(PayrollHttpClient httpClient,
199215

200216
var context = new CommandContext(
201217
commandManager: this,
202-
httpClient: httpClient,
203-
logger: Logger,
204218
console: Console,
219+
logger: Logger,
220+
httpClient: httpClient,
205221
displayLevel: Console.DisplayLevel);
206222
var result = await command.ExecuteAsync(context, parameters);
207223
Logger?.Trace($"{command} result: {result}");
@@ -238,12 +254,8 @@ public FileItem(string text, CommandLineParser parser, List<FileItem> children)
238254
internal List<FileItem> Children { get; } = [];
239255
}
240256

241-
private async Task<int> ExecuteFileAsync(PayrollHttpClient httpClient, CommandLineParser parser)
257+
private async Task<int> ExecuteFileAsync(CommandLineParser parser, PayrollHttpClient httpClient = null)
242258
{
243-
if (httpClient == null)
244-
{
245-
throw new ArgumentNullException(nameof(httpClient));
246-
}
247259
if (parser == null)
248260
{
249261
throw new ArgumentNullException(nameof(parser));
@@ -261,7 +273,7 @@ private async Task<int> ExecuteFileAsync(PayrollHttpClient httpClient, CommandLi
261273

262274
foreach (var item in items)
263275
{
264-
var exitCode = await ExecuteFileItemAsync(httpClient, item);
276+
var exitCode = await ExecuteFileItemAsync(item, httpClient);
265277
if (exitCode != 0)
266278
{
267279
return exitCode;
@@ -274,12 +286,12 @@ private async Task<int> ExecuteFileAsync(PayrollHttpClient httpClient, CommandLi
274286
return 0;
275287
}
276288

277-
private async Task<int> ExecuteFileItemAsync(PayrollHttpClient httpClient, FileItem item)
289+
private async Task<int> ExecuteFileItemAsync(FileItem item, PayrollHttpClient httpClient = null)
278290
{
279291
// command
280292
if (item.Command != null)
281293
{
282-
return await ExecuteAsync(httpClient, item.Command, item.Parser);
294+
return await ExecuteAsync(item.Command, item.Parser, httpClient);
283295
}
284296

285297
// command file
@@ -303,7 +315,7 @@ private async Task<int> ExecuteFileItemAsync(PayrollHttpClient httpClient, FileI
303315
// process children
304316
foreach (var children in item.Children)
305317
{
306-
var result = await ExecuteFileItemAsync(httpClient, children);
318+
var result = await ExecuteFileItemAsync(children, httpClient);
307319
if (result != 0)
308320
{
309321
return result;

Client.Core/Command/ICommand.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ public interface ICommand
1212
/// </summary>
1313
string Name { get; }
1414

15+
/// <summary>
16+
/// Backend command.
17+
/// </summary>
18+
bool BackendCommand { get; }
19+
1520
/// <summary>
1621
/// Get command parameters.
1722
/// </summary>

Client.Core/ConsoleProgram.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public virtual async Task ExecuteAsync()
112112
await SetupLogAsync();
113113

114114
// http client
115-
if (UseHttpClient && !await SetupHttpClientAsync())
115+
if (UseHttpClient() && !await SetupHttpClientAsync())
116116
{
117117
return;
118118
}
@@ -184,7 +184,6 @@ private static void EnsureExitCode()
184184
protected virtual int MandatoryArgumentCount => 0;
185185

186186
/// <summary>Test for single command line argument help</summary>
187-
/// <returns></returns>
188187
private static bool IsHelpMode()
189188
{
190189
var firstArgument = ConsoleArguments.Get(1, allowToggle: true);
@@ -206,7 +205,7 @@ protected virtual Task HelpAsync()
206205
protected PayrollHttpClient HttpClient { get; private set; }
207206

208207
/// <summary>Use the payroll http client, default is true</summary>
209-
protected virtual bool UseHttpClient => true;
208+
protected virtual bool UseHttpClient() => true;
210209

211210
/// <summary>Show the connection status, default is true</summary>
212211
protected virtual bool ShowConnectionInfo => true;

Client.Core/ExceptionExtensions.cs

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using System;
2+
using System.Net;
3+
using System.Linq;
24
using System.Text;
5+
using System.Net.Http;
36
using System.Text.Json;
47

58
namespace PayrollEngine.Client;
@@ -40,24 +43,22 @@ public static string GetApiErrorMessage(this Exception exception)
4043
return apiException.Message;
4144
}
4245

43-
// maybe a plain exception message
44-
// use first line only, remove the stack trace lines
45-
var message = exception.GetBaseMessage();
46-
message = message.Replace("\\r\\n", "\n");
47-
var lines = message.Split(['\n']);
48-
if (lines.Length > 1)
46+
// script errors
47+
var scriptErrors = GetScriptErrors(exception);
48+
if (scriptErrors != null)
4949
{
50-
message = lines[0];
50+
return string.Join("\n", scriptErrors);
5151
}
5252

53-
// trim quotes and line separators
54-
return message.Trim('\r', '\n', '"');
53+
// plain exception message
54+
// use first line only, remove the stack trace lines
55+
return GetPlainErrorMessage(exception, maxLines: 1);
5556
}
5657

5758
/// <summary>Get the exception message from an API error</summary>
5859
/// <param name="exception">The exception</param>
5960
/// <returns>The payroll API error, null on others errors</returns>
60-
public static ApiError GetApiError(this Exception exception)
61+
private static ApiError GetApiError(this Exception exception)
6162
{
6263
if (exception == null)
6364
{
@@ -91,7 +92,7 @@ public static ApiError GetApiError(this Exception exception)
9192
/// <summary>Get the exception message from an API exception</summary>
9293
/// <param name="exception">The exception</param>
9394
/// <returns>The payroll API error, null on others errors</returns>
94-
public static ApiException GetApiException(Exception exception)
95+
private static ApiException GetApiException(Exception exception)
9596
{
9697
if (exception == null)
9798
{
@@ -122,6 +123,45 @@ public static ApiException GetApiException(Exception exception)
122123
return null;
123124
}
124125

126+
/// <summary>Get script errors</summary>
127+
/// <param name="exception">The exception</param>
128+
/// <returns>The payroll API error, null on others errors</returns>
129+
private static string GetScriptErrors(Exception exception)
130+
{
131+
// script errors resulting to a http request exception with status code unprocessable
132+
if (exception is not HttpRequestException httpException ||
133+
httpException.StatusCode != HttpStatusCode.UnprocessableContent)
134+
{
135+
return null;
136+
}
137+
138+
// script errors
139+
var message = GetPlainErrorMessage(exception);
140+
return string.IsNullOrWhiteSpace(message) ? null : message;
141+
}
142+
143+
/// <summary>Get plain error message</summary>
144+
/// <param name="exception">The exception</param>
145+
/// <param name="maxLines">Maximum exception lines</param>
146+
private static string GetPlainErrorMessage(Exception exception, int maxLines = 0)
147+
{
148+
var message = exception.GetBaseMessage();
149+
message = message.Replace(@"\r\n", "\n");
150+
var lines = message.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).ToList();
151+
152+
if (maxLines > 0 && lines.Count > maxLines)
153+
{
154+
lines.RemoveRange(maxLines, lines.Count - maxLines);
155+
}
156+
157+
// trim quotes and line separators
158+
for (var i = 0; i < lines.Count; i++)
159+
{
160+
lines[i] = lines[i].Trim('\r', '\n', '"');
161+
}
162+
return string.Join("\n", lines);
163+
}
164+
125165
private static string GetExceptionMessage(Exception exception) =>
126166
exception.GetBaseMessage().Trim('"')
127167
.Replace("\\u0027", "'")

Client.Core/PayrollEngine.Client.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
</None>
9090
</ItemGroup>
9191
<ItemGroup>
92-
<PackageReference Include="PayrollEngine.Core" Version="0.9.0-beta.1" />
92+
<PackageReference Include="PayrollEngine.Core" Version="0.9.0-beta.3" />
9393
</ItemGroup>
9494

9595
<!-- build json schema -->

0 commit comments

Comments
 (0)