mirror of
https://github.com/g3rv4/FakeRelay.git
synced 2025-08-11 22:09:02 +02:00
Make it possible to store notes for instances
This commit is contained in:
@ -5,11 +5,11 @@ using Spectre.Console.Cli;
|
|||||||
|
|
||||||
namespace FakeRelay.Cli.Commands;
|
namespace FakeRelay.Cli.Commands;
|
||||||
|
|
||||||
public class AddInstanceCommand : ConfigEnabledAsyncCommand<InstanceSettings>
|
public class AddInstanceCommand : ConfigEnabledAsyncCommand<AddInstanceSettings>
|
||||||
{
|
{
|
||||||
public override async Task<int> ExecuteAsync(CommandContext context, InstanceSettings settings)
|
public override async Task<int> ExecuteAsync(CommandContext context, AddInstanceSettings settings)
|
||||||
{
|
{
|
||||||
var token = await ApiKeysHelper.AddTokenForHostAsync(settings.Host);
|
var token = await ApiKeysHelper.AddTokenForHostAsync(settings.Host, settings.Notes);
|
||||||
AnsiConsole.Markup($"[green]Key generated for {settings.Host}[/]\n");
|
AnsiConsole.Markup($"[green]Key generated for {settings.Host}[/]\n");
|
||||||
AnsiConsole.Markup($"[red]{token}[/]\n");
|
AnsiConsole.Markup($"[red]{token}[/]\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
16
src/FakeRelay.Cli/Commands/AnnotateInstanceCommand.cs
Normal file
16
src/FakeRelay.Cli/Commands/AnnotateInstanceCommand.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using FakeRelay.Cli.Settings;
|
||||||
|
using FakeRelay.Core.Helpers;
|
||||||
|
using Spectre.Console;
|
||||||
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
|
namespace FakeRelay.Cli.Commands;
|
||||||
|
|
||||||
|
public class AnnotateInstanceCommand : ConfigEnabledAsyncCommand<AnnotateInstanceSettings>
|
||||||
|
{
|
||||||
|
public override async Task<int> ExecuteAsync(CommandContext context, AnnotateInstanceSettings settings)
|
||||||
|
{
|
||||||
|
await ApiKeysHelper.UpdateNotesForHostAsync(settings.Host, settings.Notes);
|
||||||
|
AnsiConsole.Markup("[green]Done![/]\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -10,11 +10,13 @@ public class ListInstancesCommand : ConfigEnabledAsyncCommand<EmptyCommandSettin
|
|||||||
{
|
{
|
||||||
var keyToHost = await ApiKeysHelper.GetTokenToHostAsync();
|
var keyToHost = await ApiKeysHelper.GetTokenToHostAsync();
|
||||||
var hostToKeys = keyToHost.ToLookup(d => d.Value, d => d.Key);
|
var hostToKeys = keyToHost.ToLookup(d => d.Value, d => d.Key);
|
||||||
|
var hostToNotes = await ApiKeysHelper.GetHostToNotesAsync();
|
||||||
|
|
||||||
// Create a table
|
// Create a table
|
||||||
var table = new Table();
|
var table = new Table();
|
||||||
|
|
||||||
table.AddColumn("Instance");
|
table.AddColumn("Instance");
|
||||||
|
table.AddColumn("Notes");
|
||||||
table.AddColumn("Key");
|
table.AddColumn("Key");
|
||||||
|
|
||||||
foreach (var group in hostToKeys.OrderBy(g => g.Key))
|
foreach (var group in hostToKeys.OrderBy(g => g.Key))
|
||||||
@ -22,7 +24,8 @@ public class ListInstancesCommand : ConfigEnabledAsyncCommand<EmptyCommandSettin
|
|||||||
var host = group.Key;
|
var host = group.Key;
|
||||||
foreach (var key in group)
|
foreach (var key in group)
|
||||||
{
|
{
|
||||||
table.AddRow($"[green]{host}[/]", $"[red]{key}[/]");
|
var notes = hostToNotes.GetValueOrDefault(host) ?? "";
|
||||||
|
table.AddRow($"[green]{host}[/]", notes , $"[red]{key}[/]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ app.Configure(config =>
|
|||||||
{
|
{
|
||||||
instance.AddCommand<AddInstanceCommand>("add")
|
instance.AddCommand<AddInstanceCommand>("add")
|
||||||
.WithDescription("Adds an instance to the relay and generates a key.");
|
.WithDescription("Adds an instance to the relay and generates a key.");
|
||||||
|
instance.AddCommand<AnnotateInstanceCommand>("annotate")
|
||||||
|
.WithDescription("Adds or updates the notes associated with the instance.");
|
||||||
instance.AddCommand<UpdateInstanceCommand>("update")
|
instance.AddCommand<UpdateInstanceCommand>("update")
|
||||||
.WithDescription("Generates a new key for the instance. The old one can't be used anymore.");
|
.WithDescription("Generates a new key for the instance. The old one can't be used anymore.");
|
||||||
instance.AddCommand<DeleteInstanceCommand>("delete")
|
instance.AddCommand<DeleteInstanceCommand>("delete")
|
||||||
|
9
src/FakeRelay.Cli/Settings/AddInstanceSettings.cs
Normal file
9
src/FakeRelay.Cli/Settings/AddInstanceSettings.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
|
namespace FakeRelay.Cli.Settings;
|
||||||
|
|
||||||
|
public class AddInstanceSettings : InstanceSettings
|
||||||
|
{
|
||||||
|
[CommandOption("-n|--notes")]
|
||||||
|
public string? Notes { get; set; }
|
||||||
|
}
|
16
src/FakeRelay.Cli/Settings/AnnotateInstanceSettings.cs
Normal file
16
src/FakeRelay.Cli/Settings/AnnotateInstanceSettings.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
|
namespace FakeRelay.Cli.Settings;
|
||||||
|
|
||||||
|
public class AnnotateInstanceSettings : InstanceSettings
|
||||||
|
{
|
||||||
|
[Description("The notes for the instance.")]
|
||||||
|
[CommandArgument(1, "<NOTES>")]
|
||||||
|
public string Notes { get; set; }
|
||||||
|
|
||||||
|
public AnnotateInstanceSettings()
|
||||||
|
{
|
||||||
|
Notes = "";
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ namespace FakeRelay.Core;
|
|||||||
|
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
public static Config? Instance { get; private set; }
|
public static Config Instance { get; private set; } = new();
|
||||||
|
|
||||||
public byte[] PrivateKey { get; }
|
public byte[] PrivateKey { get; }
|
||||||
public string PublicKey { get; }
|
public string PublicKey { get; }
|
||||||
@ -14,6 +14,12 @@ public class Config
|
|||||||
public string ConfigPath { get; }
|
public string ConfigPath { get; }
|
||||||
public string? HomeRedirect { get; }
|
public string? HomeRedirect { get; }
|
||||||
|
|
||||||
|
private Config()
|
||||||
|
{
|
||||||
|
PrivateKey = Array.Empty<byte>();
|
||||||
|
PublicKey = Host = ConfigPath = "";
|
||||||
|
}
|
||||||
|
|
||||||
private Config(string publicKey, byte[] privateKey, string host, string configPath, string? homeRedirect)
|
private Config(string publicKey, byte[] privateKey, string host, string configPath, string? homeRedirect)
|
||||||
{
|
{
|
||||||
PrivateKey = privateKey;
|
PrivateKey = privateKey;
|
||||||
@ -25,7 +31,7 @@ public class Config
|
|||||||
|
|
||||||
public static void Init(string path)
|
public static void Init(string path)
|
||||||
{
|
{
|
||||||
if (Instance != null)
|
if (Instance.Host != "")
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
namespace FakeRelay.Core;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace FakeRelay.Core;
|
||||||
|
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
public static bool StartsWithCI(this string s, string prefix) =>
|
public static bool StartsWithCI(this string s, string prefix) =>
|
||||||
s.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
|
s.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public static bool IsNullOrEmpty([NotNullWhen(returnValue: false)]this string? s) => string.IsNullOrEmpty(s);
|
||||||
|
|
||||||
|
public static bool HasValue([NotNullWhen(returnValue: true)]this string? s) => !s.IsNullOrEmpty();
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,12 @@ namespace FakeRelay.Core.Helpers;
|
|||||||
public static class ApiKeysHelper
|
public static class ApiKeysHelper
|
||||||
{
|
{
|
||||||
private static string? _tokensFilePath;
|
private static string? _tokensFilePath;
|
||||||
private static string TokensFilePath => _tokensFilePath ??= Config.Instance.ConfigPath.Replace(".json", "-tokens.json");
|
private static string TokensFilePath =>
|
||||||
|
_tokensFilePath ??= Config.Instance.ConfigPath.Replace(".json", "-tokens.json");
|
||||||
|
|
||||||
|
private static string? _notesFilePath;
|
||||||
|
private static string NotesFilePath =>
|
||||||
|
_notesFilePath ??= Config.Instance.ConfigPath.Replace(".json", "-notes.json");
|
||||||
|
|
||||||
public static async Task<ImmutableDictionary<string, string>> GetTokenToHostAsync()
|
public static async Task<ImmutableDictionary<string, string>> GetTokenToHostAsync()
|
||||||
{
|
{
|
||||||
@ -21,6 +26,19 @@ public static class ApiKeysHelper
|
|||||||
.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase);
|
.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<Dictionary<string, string>> GetHostToNotesAsync()
|
||||||
|
{
|
||||||
|
if (!File.Exists(NotesFilePath))
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = await File.ReadAllTextAsync(NotesFilePath);
|
||||||
|
return JSON.Deserialize<Dictionary<string, string>>(content)
|
||||||
|
// set the comparer so that it's case insensitive
|
||||||
|
.ToDictionary(e => e.Key, e => e.Value, StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<string> UpdateTokenForHostAsync(string host)
|
public static async Task<string> UpdateTokenForHostAsync(string host)
|
||||||
{
|
{
|
||||||
var dict = await GetTokenToHostAsync();
|
var dict = await GetTokenToHostAsync();
|
||||||
@ -38,8 +56,41 @@ public static class ApiKeysHelper
|
|||||||
return await AddTokenForHostAsync(host, dict);
|
return await AddTokenForHostAsync(host, dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string> AddTokenForHostAsync(string host) =>
|
public static async Task UpdateNotesForHostAsync(string host, string? notes)
|
||||||
await AddTokenForHostAsync(host, await GetTokenToHostAsync());
|
{
|
||||||
|
var tokensToHost = await GetTokenToHostAsync();
|
||||||
|
if (!tokensToHost.Values.Contains(host))
|
||||||
|
{
|
||||||
|
throw new Exception($"There's no entry for {host}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var notesDict = await GetHostToNotesAsync();
|
||||||
|
if (notes.HasValue())
|
||||||
|
{
|
||||||
|
notesDict[host] = notes;
|
||||||
|
}
|
||||||
|
else if (notesDict.ContainsKey(host))
|
||||||
|
{
|
||||||
|
notesDict.Remove(host);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = JSON.Serialize(notesDict);
|
||||||
|
await File.WriteAllTextAsync(NotesFilePath, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<string> AddTokenForHostAsync(string host, string? notes)
|
||||||
|
{
|
||||||
|
if (notes.HasValue())
|
||||||
|
{
|
||||||
|
await UpdateNotesForHostAsync(host, notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await AddTokenForHostAsync(host, await GetTokenToHostAsync());
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task DeleteTokenForHostAsync(string host)
|
public static async Task DeleteTokenForHostAsync(string host)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user