Skip to content

Commit 0cbdba6

Browse files
committed
feat(cli): add plugin management commands
1 parent a7d2d88 commit 0cbdba6

File tree

16 files changed

+594
-6
lines changed

16 files changed

+594
-6
lines changed

src/Proxxi.Cli/Commands/Fetch/FetchCommand.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ public override async Task<int> ExecuteAsync(CommandContext context, FetchComman
7171
console.MarkupLine("[yellow]Operation canceled.[/]");
7272
return 130;
7373
}
74+
catch (Exception ex)
75+
{
76+
console.MarkupLine($"[red]{ex.Message}[/]");
77+
return 1;
78+
}
7479
finally
7580
{
7681
if (settings.Output != null)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using Proxxi.Core.Providers;
2+
3+
using Spectre.Console;
4+
using Spectre.Console.Cli;
5+
6+
namespace Proxxi.Cli.Commands.Plugin.PluginAlias;
7+
8+
public class PluginAliasCommand(IAnsiConsole console, IPluginConfigProvider configProvider)
9+
: Command<PluginAliasCommandSettings>
10+
{
11+
public override int Execute(CommandContext context, PluginAliasCommandSettings settings, CancellationToken ct)
12+
{
13+
var config = configProvider.Get(settings.Id);
14+
15+
if (config == null)
16+
{
17+
console.MarkupLine($"[red]Plugin '{settings.Id}' is not installed.[/]");
18+
return 1;
19+
}
20+
21+
if (settings.Value != null)
22+
{
23+
if (configProvider.AliasExists(settings.Value, config.Id))
24+
{
25+
console.MarkupLine($"[red]Alias '{settings.Value}' is already in use.[/]");
26+
return 1;
27+
}
28+
29+
var oldAlias = config.Alias;
30+
config.Alias = settings.Value;
31+
32+
configProvider.Upsert(config);
33+
configProvider.Save();
34+
35+
console.MarkupLine($"[green]✓[/] Alias updated: {oldAlias ?? "<none>"} → [yellow]{config.Alias}[/]");
36+
return 0;
37+
}
38+
39+
if (settings.Remove)
40+
{
41+
if (config.Alias == null)
42+
{
43+
console.MarkupLine("[yellow]Plugin has no alias to remove.[/]");
44+
return 0;
45+
}
46+
47+
config.Alias = null;
48+
49+
configProvider.Upsert(config);
50+
configProvider.Save();
51+
52+
console.MarkupLine("[green]✓[/] Alias removed.");
53+
return 0;
54+
}
55+
56+
console.MarkupLine(config.Alias != null
57+
? $"Alias: [yellow]{config.Alias}[/]"
58+
: "[yellow]No alias set.[/]");
59+
60+
return 0;
61+
}
62+
63+
public override ValidationResult Validate(CommandContext context, PluginAliasCommandSettings settings)
64+
{
65+
if (settings.Value != null && settings.Remove)
66+
return ValidationResult.Error("Cannot specify [VALUE] and --remove together.");
67+
68+
return ValidationResult.Success();
69+
}
70+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.ComponentModel;
2+
3+
using Spectre.Console.Cli;
4+
5+
namespace Proxxi.Cli.Commands.Plugin.PluginAlias;
6+
7+
public class PluginAliasCommandSettings : PluginCommandSettings
8+
{
9+
[CommandArgument(0, "[VALUE]")]
10+
[Description("The alias to set for the plugin (if omitted, the print the current alias)")]
11+
public string? Value { get; init; }
12+
13+
[CommandOption("-r|--remove")]
14+
[Description("Remove the alias for the plugin (if set)")]
15+
public bool Remove { get; init; }
16+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.ComponentModel;
2+
3+
using Spectre.Console.Cli;
4+
5+
namespace Proxxi.Cli.Commands.Plugin;
6+
7+
public abstract class PluginCommandSettings : CommandSettings
8+
{
9+
[CommandArgument(0, "<ID>")]
10+
[Description("The plugin ID to plugin manage")]
11+
public required string Id { get; init; }
12+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Proxxi.Core.Providers;
2+
3+
using Spectre.Console;
4+
using Spectre.Console.Cli;
5+
6+
namespace Proxxi.Cli.Commands.Plugin.PluginDisable;
7+
8+
public class PluginDisableCommand(IAnsiConsole console, IPluginConfigProvider configProvider)
9+
: Command<PluginDisableCommand.PluginDisableCommandSettings>
10+
{
11+
public class PluginDisableCommandSettings : PluginCommandSettings;
12+
13+
public override int Execute(CommandContext context, PluginDisableCommandSettings settings, CancellationToken ct)
14+
{
15+
var config = configProvider.Get(settings.Id);
16+
17+
if (config == null)
18+
{
19+
console.MarkupLine($"[red]Plugin '{settings.Id}' not found.[/]");
20+
return 1;
21+
}
22+
23+
if (!config.Enabled)
24+
{
25+
console.MarkupLine("[yellow]Plugin already disabled.[/]");
26+
return 0;
27+
}
28+
29+
config.Enabled = false;
30+
31+
configProvider.Upsert(config);
32+
configProvider.Save();
33+
34+
console.MarkupLine("[green]✓[/] Plugin disabled.");
35+
return 0;
36+
}
37+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Proxxi.Core.Providers;
2+
3+
using Spectre.Console;
4+
using Spectre.Console.Cli;
5+
6+
namespace Proxxi.Cli.Commands.Plugin.PluginEnable;
7+
8+
public class PluginEnableCommand(IAnsiConsole console, IPluginConfigProvider configProvider)
9+
: Command<PluginEnableCommand.PluginEnableCommandSettings>
10+
{
11+
public class PluginEnableCommandSettings : PluginCommandSettings;
12+
13+
public override int Execute(CommandContext context, PluginEnableCommandSettings settings, CancellationToken ct)
14+
{
15+
var config = configProvider.Get(settings.Id);
16+
17+
if (config == null)
18+
{
19+
console.MarkupLine($"[red]Plugin '{settings.Id}' not found.[/]");
20+
return 1;
21+
}
22+
23+
if (config.Enabled)
24+
{
25+
console.MarkupLine("[yellow]Plugin already enabled.[/]");
26+
return 0;
27+
}
28+
29+
config.Enabled = true;
30+
31+
configProvider.Upsert(config);
32+
configProvider.Save();
33+
34+
console.MarkupLine("[green]✓[/] Plugin enabled.");
35+
return 0;
36+
}
37+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using Microsoft.Extensions.Options;
2+
3+
using Proxxi.Core.Options;
4+
using Proxxi.Core.Providers;
5+
using Proxxi.Plugin.Loader.PluginLoaders;
6+
using Proxxi.Plugin.Sdk.ProxySources;
7+
8+
using Spectre.Console;
9+
using Spectre.Console.Cli;
10+
11+
namespace Proxxi.Cli.Commands.Plugin.PluginInfo;
12+
13+
public class PluginInfoCommand(
14+
IAnsiConsole console,
15+
IPluginConfigProvider configProvider,
16+
IPluginLoader pluginLoader,
17+
IOptions<ProxxiPathsOptions> options
18+
) : Command<PluginInfoCommand.PluginInfoCommandSettings>
19+
{
20+
public class PluginInfoCommandSettings : PluginCommandSettings;
21+
22+
private readonly ProxxiPathsOptions _pathOptions = options.Value;
23+
24+
public override int Execute(CommandContext context, PluginInfoCommandSettings settings, CancellationToken ct)
25+
{
26+
var config = configProvider.Get(settings.Id);
27+
28+
if (config == null)
29+
{
30+
console.MarkupLine($"[red]Plugin '{settings.Id}' is not installed.[/]");
31+
return 1;
32+
}
33+
34+
var fullPath = Path.Combine(_pathOptions.PluginsDir, config.Path);
35+
36+
var descriptor = pluginLoader.LoadPlugins([fullPath])
37+
.FirstOrDefault(pd => StringComparer.OrdinalIgnoreCase.Equals(pd.Id, config.Id));
38+
39+
if (descriptor == null)
40+
{
41+
console.MarkupLine($"[red]Plugin '{settings.Id}' is not loaded.[/]");
42+
return 1;
43+
}
44+
45+
var grid = new Grid();
46+
grid.AddColumns(2);
47+
48+
var id = string.Concat(descriptor.Id, " (", config.Enabled ? "[green]enabled[/]" : "[red]disabled[/]", ")");
49+
var desc = !string.IsNullOrWhiteSpace(descriptor.Description) ? descriptor.Description : "[grey]<none>[/]";
50+
51+
var supportBatchMode = !descriptor.HideBatch &&
52+
descriptor.ProxySourceType.IsAssignableTo(typeof(IBatchProxySource));
53+
54+
var supportStreamMode = !descriptor.HideStream &&
55+
descriptor.ProxySourceType.IsAssignableTo(typeof(IStreamProxySource));
56+
57+
console.MarkupLine($"[bold underline]{descriptor.Name}[/]");
58+
59+
grid.AddRow("[cyan]Id[/]:", id);
60+
grid.AddRow("[cyan]Alias[/]:", config.Alias ?? "[grey]<none>[/]");
61+
grid.AddRow("[cyan]Description[/]:", desc);
62+
grid.AddRow("[cyan]Path[/]:", descriptor.Path);
63+
grid.AddRow("[cyan]Version[/]:", descriptor.Version);
64+
grid.AddRow("[cyan]Batch mode[/]:", supportBatchMode ? "[green]yes[/]" : "[red]no[/]");
65+
grid.AddRow("[cyan]Stream mode[/]:", supportStreamMode ? "[green]yes[/]" : "[red]no[/]");
66+
67+
console.Write(grid);
68+
69+
return 0;
70+
}
71+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using Microsoft.Extensions.Options;
2+
3+
using Proxxi.Core.Options;
4+
using Proxxi.Core.Providers;
5+
using Proxxi.Plugin.Loader.PluginLoaders;
6+
7+
using Spectre.Console;
8+
using Spectre.Console.Cli;
9+
10+
namespace Proxxi.Cli.Commands.Plugin.PluginParameter;
11+
12+
public class PluginParameterCommand(
13+
IAnsiConsole console,
14+
IPluginConfigProvider configProvider,
15+
IPluginLoader pluginLoader,
16+
IOptions<ProxxiPathsOptions> options
17+
) : Command<PluginParameterCommandSettings>
18+
{
19+
private readonly ProxxiPathsOptions _pathOptions = options.Value;
20+
21+
public override int Execute(CommandContext context, PluginParameterCommandSettings settings, CancellationToken ct)
22+
{
23+
var config = configProvider.Get(settings.Id);
24+
25+
if (config == null)
26+
{
27+
console.MarkupLine($"[red]Plugin '{settings.Id}' is not installed.[/]");
28+
return 1;
29+
}
30+
31+
var fullPath = Path.Combine(_pathOptions.PluginsDir, config.Path);
32+
33+
var descriptor = pluginLoader.LoadPlugins([fullPath])
34+
.FirstOrDefault(pd => StringComparer.OrdinalIgnoreCase.Equals(pd.Id, config.Id));
35+
36+
if (descriptor == null)
37+
{
38+
console.MarkupLine($"[red]Plugin '{settings.Id}' is not loaded.[/]");
39+
return 1;
40+
}
41+
42+
string? parameterName;
43+
44+
if (settings.Force)
45+
parameterName = settings.Name;
46+
else
47+
parameterName = descriptor.Parameters
48+
.FirstOrDefault(p => StringComparer.OrdinalIgnoreCase.Equals(p.Name, settings.Name))?.Name;
49+
50+
if (parameterName == null)
51+
{
52+
console.MarkupLine($"[red]Plugin does not support parameter '{settings.Name}'.[/]");
53+
return 1;
54+
}
55+
56+
if (settings.Value != null)
57+
{
58+
config.Parameters[parameterName] = settings.Value;
59+
60+
configProvider.Upsert(config);
61+
configProvider.Save();
62+
63+
console.MarkupLine($"[green]✓[/] Parameter '{parameterName}' set to [yellow]{settings.Value}[/]");
64+
65+
return 0;
66+
}
67+
68+
if (settings.Remove)
69+
{
70+
if (!config.Parameters.Remove(parameterName))
71+
{
72+
console.MarkupLine("[yellow]Plugin has no parameter to remove.[/]");
73+
return 0;
74+
}
75+
76+
configProvider.Upsert(config);
77+
configProvider.Save();
78+
79+
console.MarkupLine("[green]✓[/] Parameter removed.");
80+
81+
return 0;
82+
}
83+
84+
console.MarkupLine(config.Parameters.TryGetValue(parameterName, out var value)
85+
? $"Parameter '{parameterName}': [yellow]{value}[/]"
86+
: $"[yellow]Parameter '{parameterName}' is not set.[/]");
87+
88+
return 0;
89+
}
90+
91+
public override ValidationResult Validate(CommandContext context, PluginParameterCommandSettings settings)
92+
{
93+
if (settings.Value != null && settings.Remove)
94+
return ValidationResult.Error("Cannot specify [VALUE] and --remove together.");
95+
96+
return ValidationResult.Success();
97+
}
98+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.ComponentModel;
2+
3+
using Spectre.Console.Cli;
4+
5+
namespace Proxxi.Cli.Commands.Plugin.PluginParameter;
6+
7+
public class PluginParameterCommandSettings : PluginCommandSettings
8+
{
9+
[CommandArgument(0, "<NAME>")]
10+
[Description("The parameter name to set for the plugin")]
11+
public required string Name { get; init; }
12+
13+
[CommandArgument(1, "[VALUE]")]
14+
[Description("The value to set for the parameter (if omitted, the print the current value)")]
15+
public string? Value { get; init; }
16+
17+
[CommandOption("-r|--remove")]
18+
[Description("Remove the parameter for the plugin (if set)")]
19+
public bool Remove { get; init; }
20+
21+
[CommandOption("-f|--force")]
22+
[Description("Allow setting or removing parameters not declared by the plugin")]
23+
public bool Force { get; init; }
24+
}

0 commit comments

Comments
 (0)