mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 11:44:56 +00:00
Refactor console client to new Govor.ConsoleClient project
Removed Govor.Console implementation and introduced a new Govor.ConsoleClient project with a modular command-based architecture. Added dependency injection, command dispatcher, middleware pipeline, logging, and interactive command support. Updated solution and project files to reflect the new structure.
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
using Govor.ConsoleClient.Services;
|
||||
|
||||
namespace Govor.ConsoleClient;
|
||||
|
||||
public class App
|
||||
{
|
||||
private readonly InputPipeline _inputPipeline;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public App(InputPipeline inputPipeline, ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_inputPipeline = inputPipeline;
|
||||
}
|
||||
|
||||
public async Task RunAsync()
|
||||
{
|
||||
_logger.Title("Добро пожаловать в консольный клиент Говор!");
|
||||
while (true)
|
||||
{
|
||||
Console.Write(">> ");
|
||||
var input = Console.ReadLine();
|
||||
if (input == null || input.Trim().ToLower() == "exit") break;
|
||||
await _inputPipeline.ProcessInputAsync(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Govor.ConsoleClient.Services;
|
||||
|
||||
namespace Govor.ConsoleClient.Commands;
|
||||
|
||||
public class HelpCommand : ICommand
|
||||
{
|
||||
public Task ExecuteAsync(CommandContext context)
|
||||
{
|
||||
Console.WriteLine("Commands:");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string LongHelp()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string ShortHelp()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Govor.ConsoleClient.Services;
|
||||
|
||||
namespace Govor.ConsoleClient.Commands;
|
||||
|
||||
public interface ICommand
|
||||
{
|
||||
Task ExecuteAsync(CommandContext context);
|
||||
string LongHelp();
|
||||
string ShortHelp();
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class CommandRouteAttribute : Attribute
|
||||
{
|
||||
public string Path { get; }
|
||||
public CommandRouteAttribute(string path) => Path = path;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Govor.ConsoleClient.Commands;
|
||||
|
||||
public interface IInteractiveCommand : ICommand
|
||||
{
|
||||
Task HandleInputAsync(string input);
|
||||
bool IsCompleted { get; }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Govor.ConsoleClient.Services;
|
||||
|
||||
namespace Govor.ConsoleClient.Commands;
|
||||
|
||||
[CommandRoute("/send")]
|
||||
public class SendMessageCommand : IInteractiveCommand
|
||||
{
|
||||
private string? _recipient;
|
||||
private bool _isCompleted;
|
||||
public bool IsCompleted => _isCompleted;
|
||||
|
||||
public Task ExecuteAsync(CommandContext context)
|
||||
{
|
||||
Console.WriteLine("Кому вы хотите отправить сообщение?");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task HandleInputAsync(string input)
|
||||
{
|
||||
if (_recipient == null)
|
||||
{
|
||||
_recipient = input;
|
||||
Console.WriteLine("Введите сообщение:");
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = input;
|
||||
Console.WriteLine($"(Отправка '{message}' пользователю '{_recipient}')");
|
||||
_isCompleted = true;
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string LongHelp()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string ShortHelp()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Reflection;
|
||||
using Govor.ConsoleClient.Commands;
|
||||
using Govor.ConsoleClient.Services;
|
||||
using Govor.ConsoleClient.Services.Middleware;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Govor.ConsoleClient;
|
||||
|
||||
public static class DependencyInjection
|
||||
{
|
||||
public static IServiceProvider Configure()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
// Регистрация команд
|
||||
services.AddCommands();
|
||||
|
||||
// Сервисы
|
||||
services.AddSingleton<CommandDispatcher>();
|
||||
services.AddSingleton<InputPipeline>();
|
||||
services.AddSingleton<ConsoleLogger>();
|
||||
services.AddSingleton<ILogger>(sp => sp.GetRequiredService<ConsoleLogger>());
|
||||
services.AddSingleton<CommandContext>();
|
||||
services.AddSingleton<MiddlewarePipeline>();
|
||||
|
||||
// Middleware
|
||||
services.AddSingleton<ICommandMiddleware, ExceptionHandlingMiddleware>();
|
||||
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
public static IServiceCollection AddCommands(this IServiceCollection services)
|
||||
{
|
||||
var commandTypes = Assembly.GetExecutingAssembly()
|
||||
.GetTypes()
|
||||
.Where(t => typeof(ICommand).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);
|
||||
|
||||
foreach (var type in commandTypes)
|
||||
{
|
||||
services.AddTransient(typeof(ICommand), type);
|
||||
services.AddTransient(type); // Для прямого внедрения
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>12</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.5" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Govor.Contracts\Govor.Contracts.csproj" />
|
||||
<ProjectReference Include="..\Govor.Core\Govor.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Api\" />
|
||||
<Folder Include="Commands\Auth\" />
|
||||
<Folder Include="Models\" />
|
||||
<Folder Include="Utils\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Govor.ConsoleClient;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
//private const string HubBaseUrl = "https://govor-team-govor-88b3.twc1.net/hubs";
|
||||
|
||||
static async Task Main()
|
||||
{
|
||||
Console.Title = "Govor Console Client";
|
||||
|
||||
var serviceProvider = DependencyInjection.Configure();
|
||||
|
||||
var app = ActivatorUtilities.CreateInstance<App>(serviceProvider);
|
||||
await app.RunAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Govor.ConsoleClient.Commands;
|
||||
|
||||
namespace Govor.ConsoleClient.Services;
|
||||
|
||||
public class CommandContext
|
||||
{
|
||||
public string Route { get; }
|
||||
public string? Arguments { get; }
|
||||
public ICommand Command { get; }
|
||||
|
||||
public CommandContext(string route, string? arguments, ICommand command)
|
||||
{
|
||||
Route = route;
|
||||
Arguments = arguments;
|
||||
Command = command;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Reflection;
|
||||
using Govor.ConsoleClient.Commands;
|
||||
|
||||
namespace Govor.ConsoleClient.Services;
|
||||
|
||||
public class CommandDispatcher
|
||||
{
|
||||
private readonly Dictionary<string, ICommand> _commands = new();
|
||||
private readonly ILogger _logger;
|
||||
private readonly MiddlewarePipeline _pipeline;
|
||||
|
||||
public CommandDispatcher(IEnumerable<ICommand> commands, ILogger logger, MiddlewarePipeline pipeline)
|
||||
{
|
||||
_logger = logger;
|
||||
_pipeline = pipeline;
|
||||
|
||||
foreach (var command in commands)
|
||||
{
|
||||
var route = command.GetType().GetCustomAttribute<CommandRouteAttribute>()?.Path.Replace("/","")
|
||||
?? command.GetType().Name.Replace("Command", "").ToLower();
|
||||
_commands[route.ToLower()] = command;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ICommand?> DispatchAsync(string input)
|
||||
{
|
||||
var args = input.Split(' ', 2);
|
||||
var cmd = args[0].ToLower();
|
||||
if (_commands.TryGetValue(cmd, out var command))
|
||||
{
|
||||
var context = new CommandContext(cmd, args.Length > 1 ? args[1] : null, command);
|
||||
await _pipeline.ExecuteAsync(context);
|
||||
return command;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warn("Неизвестная команда. Введите '/help'.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
namespace Govor.ConsoleClient.Services;
|
||||
|
||||
public class ConsoleLogger : ILogger
|
||||
{
|
||||
public void Log(string message)
|
||||
{
|
||||
Console.ResetColor();
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
public void Info(string message)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.WriteLine($"[INFO] {message}");
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
public void Warn(string message)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine($"[WARN] {message}");
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
public void Error(string message)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"[ERROR] {message}");
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
public void Title(string message)
|
||||
{
|
||||
var upper = message.ToUpper();
|
||||
var length = upper.Length + 6;
|
||||
var border = new string('=', length);
|
||||
var padded = $"= {upper} =";
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
Console.WriteLine(border);
|
||||
Console.WriteLine(padded);
|
||||
Console.WriteLine(border);
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Govor.ConsoleClient.Services;
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
void Log(string message);
|
||||
void Info(string message);
|
||||
void Warn(string message);
|
||||
void Error(string message);
|
||||
void Title(string title);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Govor.ConsoleClient.Commands;
|
||||
|
||||
namespace Govor.ConsoleClient.Services;
|
||||
|
||||
public class InputPipeline
|
||||
{
|
||||
private readonly CommandDispatcher _dispatcher;
|
||||
private readonly ILogger _logger;
|
||||
private IInteractiveCommand? _activeCommand;
|
||||
|
||||
public InputPipeline(CommandDispatcher dispatcher, ILogger logger)
|
||||
{
|
||||
_dispatcher = dispatcher;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task ProcessInputAsync(string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input)) return;
|
||||
|
||||
if (input.StartsWith("/"))
|
||||
{
|
||||
_activeCommand = null; // Сброс активной команды
|
||||
|
||||
var commandInput = input[1..];
|
||||
var result = await _dispatcher.DispatchAsync(commandInput);
|
||||
|
||||
// Если команда поддерживает интерактивность, сохраняем как активную
|
||||
if (result is IInteractiveCommand interactiveCommand && !interactiveCommand.IsCompleted)
|
||||
{
|
||||
_activeCommand = interactiveCommand;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_activeCommand != null)
|
||||
{
|
||||
await _activeCommand.HandleInputAsync(input);
|
||||
|
||||
if (_activeCommand.IsCompleted)
|
||||
_activeCommand = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Info($"[Ввод пользователя]: {input}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Govor.ConsoleClient.Services.Middleware;
|
||||
|
||||
public class ExceptionHandlingMiddleware : ICommandMiddleware
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public ExceptionHandlingMiddleware(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(CommandContext context, Func<Task> next)
|
||||
{
|
||||
try
|
||||
{
|
||||
await next();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Произошла ошибка при выполнении команды '{context.Route}': {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Govor.ConsoleClient.Services.Middleware;
|
||||
|
||||
public interface ICommandMiddleware
|
||||
{
|
||||
Task InvokeAsync(CommandContext context, Func<Task> next);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Govor.ConsoleClient.Services.Middleware;
|
||||
|
||||
namespace Govor.ConsoleClient.Services;
|
||||
|
||||
public delegate Task CommandMiddleware(CommandContext context, Func<Task> next);
|
||||
|
||||
public class MiddlewarePipeline
|
||||
{
|
||||
private readonly IList<ICommandMiddleware> _middlewares;
|
||||
|
||||
public MiddlewarePipeline(IEnumerable<ICommandMiddleware> middlewares)
|
||||
{
|
||||
_middlewares = middlewares.ToList();
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(CommandContext context)
|
||||
{
|
||||
return InvokeNext(0, context);
|
||||
}
|
||||
|
||||
private Task InvokeNext(int index, CommandContext context)
|
||||
{
|
||||
if (index < _middlewares.Count)
|
||||
{
|
||||
return _middlewares[index].InvokeAsync(context, () => InvokeNext(index + 1, context));
|
||||
}
|
||||
return context.Command.ExecuteAsync(context);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user