Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.

Commit 14c87da

Browse files
committed
Add console command and version management features
This commit introduces the `ConsoleCommand` for executing the FlowSynx console, along with options for specifying an address. A new `ConsoleVersionCommand` is added to retrieve and display the console version. New classes `ConsoleCommandOptions` and `ConsoleVersionCommandOptions` are created to manage command options, while their respective handlers handle execution and logging. Localized strings for error messages and command descriptions are added, and the `ServiceCollectionExtensions` class is updated to register the new commands. Minor corrections to existing resource strings enhance clarity and consistency. #107
1 parent 41f70c2 commit 14c87da

9 files changed

Lines changed: 296 additions & 5 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using FlowCtl.Commands.Console.Version;
2+
using System.CommandLine;
3+
4+
namespace FlowCtl.Commands.Console;
5+
6+
internal class ConsoleCommand : BaseCommand<ConsoleCommandOptions, ConsoleCommandOptionsHandler>
7+
{
8+
public ConsoleCommand() : base("console", Resources.Command_Console_Description)
9+
{
10+
var addressOption = new Option<string?>(new[] { "-a", "--address" },
11+
description: Resources.Commands_FlowSynxAddress);
12+
13+
AddOption(addressOption);
14+
AddCommand(new ConsoleVersionCommand());
15+
}
16+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace FlowCtl.Commands.Console;
2+
3+
internal class ConsoleCommandOptions : ICommandOptions
4+
{
5+
public string? Address { get; set; } = string.Empty;
6+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using FlowCtl.Core.Services.Location;
2+
using FlowCtl.Core.Services.Logger;
3+
using System.Diagnostics;
4+
using System.Runtime.InteropServices;
5+
6+
namespace FlowCtl.Commands.Console;
7+
8+
internal class ConsoleCommandOptionsHandler : ICommandOptionsHandler<ConsoleCommandOptions>
9+
{
10+
private readonly IFlowCtlLogger _flowCtlLogger;
11+
private readonly ILocation _location;
12+
13+
public ConsoleCommandOptionsHandler(
14+
IFlowCtlLogger flowCtlLogger,
15+
ILocation location)
16+
{
17+
_flowCtlLogger = flowCtlLogger ?? throw new ArgumentNullException(nameof(flowCtlLogger));
18+
_location = location;
19+
}
20+
21+
public async Task<int> HandleAsync(ConsoleCommandOptions options, CancellationToken cancellationToken)
22+
{
23+
await Execute(options);
24+
return 0;
25+
}
26+
27+
private Task Execute(ConsoleCommandOptions options)
28+
{
29+
try
30+
{
31+
var dashboardPath = Path.Combine(_location.DefaultFlowSynxBinaryDirectoryName, "console");
32+
var dashboardBinaryFile = _location.LookupConsoleBinaryFilePath(dashboardPath);
33+
if (!Path.Exists(dashboardBinaryFile))
34+
{
35+
_flowCtlLogger.WriteError(Resources.Command_Console_ConsleIsNotInstalled);
36+
return Task.CompletedTask;
37+
}
38+
39+
var startInfo = new ProcessStartInfo(dashboardBinaryFile)
40+
{
41+
Arguments = GetArgumentStr(options),
42+
UseShellExecute = false,
43+
RedirectStandardOutput = true,
44+
RedirectStandardError = true,
45+
WorkingDirectory = dashboardPath
46+
};
47+
48+
var process = new Process { StartInfo = startInfo };
49+
process.OutputDataReceived += OutputDataHandler;
50+
process.ErrorDataReceived += ErrorDataHandler;
51+
var processStarted = process.Start();
52+
53+
process.BeginOutputReadLine();
54+
process.BeginErrorReadLine();
55+
process?.WaitForExit();
56+
}
57+
catch (Exception e)
58+
{
59+
_flowCtlLogger.WriteError(e.Message);
60+
}
61+
return Task.CompletedTask;
62+
}
63+
64+
private string GetArgumentStr(ConsoleCommandOptions options)
65+
{
66+
var argList = new List<string>();
67+
68+
if (!string.IsNullOrEmpty(options.Address))
69+
argList.Add($"--address {options.Address}");
70+
71+
return argList.Count == 0 ? string.Empty : string.Join(' ', argList);
72+
}
73+
74+
private void OutputDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
75+
{
76+
if (outLine.Data != null) _flowCtlLogger.Write(outLine.Data);
77+
}
78+
79+
private void ErrorDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
80+
{
81+
if (outLine.Data != null) _flowCtlLogger.WriteError(outLine.Data);
82+
}
83+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using FlowCtl.Core.Services.Logger;
2+
using System.CommandLine;
3+
4+
namespace FlowCtl.Commands.Console.Version;
5+
6+
internal class ConsoleVersionCommand : BaseCommand<ConsoleVersionCommandOptions, ConsoleVersionCommandOptionsHandler>
7+
{
8+
public ConsoleVersionCommand() : base("version", Resources.Command_ConsoleVersion_Description)
9+
{
10+
var outputOption = new Option<OutputType>(new[] { "-o", "--output" },
11+
getDefaultValue: () => OutputType.Json,
12+
description: Resources.Commands_Output_Format);
13+
14+
AddOption(outputOption);
15+
}
16+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using FlowCtl.Core.Services.Logger;
2+
3+
namespace FlowCtl.Commands.Console.Version;
4+
5+
internal class ConsoleVersionCommandOptions : ICommandOptions
6+
{
7+
public OutputType Output { get; set; } = OutputType.Json;
8+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using FlowCtl.Core.Services.Location;
2+
using FlowCtl.Core.Services.Logger;
3+
using FlowCtl.Services.Version;
4+
5+
namespace FlowCtl.Commands.Console.Version;
6+
7+
internal class ConsoleVersionCommandOptionsHandler : ICommandOptionsHandler<ConsoleVersionCommandOptions>
8+
{
9+
private readonly IFlowCtlLogger _flowCtlLogger;
10+
private readonly ILocation _location;
11+
private readonly IVersion _version;
12+
13+
public ConsoleVersionCommandOptionsHandler(IFlowCtlLogger flowCtlLogger,
14+
ILocation location, IVersion version)
15+
{
16+
_flowCtlLogger = flowCtlLogger ?? throw new ArgumentNullException(nameof(flowCtlLogger));
17+
_location = location ?? throw new ArgumentNullException(nameof(location));
18+
_version = version ?? throw new ArgumentNullException(nameof(version));
19+
}
20+
21+
public Task<int> HandleAsync(ConsoleVersionCommandOptions options, CancellationToken cancellationToken)
22+
{
23+
Execute(options);
24+
return Task.FromResult(0);
25+
}
26+
27+
private Task Execute(ConsoleVersionCommandOptions options)
28+
{
29+
try
30+
{
31+
var fullVersion = new
32+
{
33+
Version = GetConsoleVersion()
34+
};
35+
36+
_flowCtlLogger.Write(fullVersion, options.Output);
37+
return Task.CompletedTask;
38+
}
39+
catch (Exception ex)
40+
{
41+
_flowCtlLogger.WriteError(ex.Message);
42+
return Task.CompletedTask;
43+
}
44+
}
45+
46+
private string GetConsoleVersion()
47+
{
48+
var consoleBinaryFile = _location.LookupConsoleBinaryFilePath(Path.Combine(_location.DefaultFlowSynxBinaryDirectoryName, "console"));
49+
var consoleVersion = _version.GetVersionFromPath(consoleBinaryFile);
50+
return string.IsNullOrEmpty(consoleVersion) ? Resources.Commands_Version_NotInitialized : consoleVersion;
51+
}
52+
}

src/FlowCtl/Extensions/ServiceCollectionExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
using FlowSynx.Client;
2828
using Spectre.Console;
2929
using FlowSynx.Client.Authentication;
30+
using FlowCtl.Commands.Console;
3031

3132
namespace FlowCtl.Extensions;
3233

@@ -43,6 +44,7 @@ public static IServiceCollection AddCommands(this IServiceCollection services)
4344
{
4445
services.AddTransient<RootCommand, Root>()
4546
.AddTransient<Command, ConfigCommand>()
47+
.AddTransient<Command, ConsoleCommand>()
4648
.AddTransient<Command, HealthCommand>()
4749
.AddTransient<Command, InitCommand>()
4850
.AddTransient<Command, LoginCommand>()

src/FlowCtl/Resources.Designer.cs

Lines changed: 84 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)