Skip to content

Commit

Permalink
refactor: Done
Browse files Browse the repository at this point in the history
  • Loading branch information
s2quake committed Oct 13, 2024
1 parent f307308 commit 0b15963
Show file tree
Hide file tree
Showing 66 changed files with 904 additions and 317 deletions.
7 changes: 7 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ dotnet_diagnostic.MEN007.severity = none
# MEN016: Avoid top-level statements
dotnet_diagnostic.MEN016.severity = none

[**/obj/**/*.cs]
# SA1200: Using directives should be placed correctly
dotnet_diagnostic.SA1200.severity = none

# CS8981: The type name only contains lower-cased ascii characters
dotnet_diagnostic.CS8981.severity = none

[*.csproj]
quote_type = double

Expand Down
5 changes: 4 additions & 1 deletion src/client/LibplanetConsole.Client.Executable/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ public Application(ApplicationOptions options, object[] instances)
options.ListenLocalhost(port, o => o.Protocols = HttpProtocols.Http2);
});

services.AddLogging(options.LogPath, "client.log", _filters);
if (options.LogPath != string.Empty)
{
services.AddLogging(options.LogPath, "client.log", _filters);
}

services.AddSingleton<CommandContext>();
services.AddSingleton<SystemTerminal>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ internal sealed record class ApplicationSettings

[CommandProperty]
[CommandSummary("Indicates the file path to save logs.")]
[Path(Type = PathType.File, AllowEmpty = true)]
[Path(Type = PathType.Directory, AllowEmpty = true)]
[DefaultValue("")]
public string LogPath { get; set; } = string.Empty;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ public InitializeCommand()
public string EndPoint { get; set; } = string.Empty;

[CommandProperty]
[CommandSummary("The file path to store the application logs." +
"If omitted, the 'app.log' file is used.")]
[Path(Type = PathType.File, ExistsType = PathExistsType.NotExistOrEmpty, AllowEmpty = true)]
[CommandSummary("Indicates the file path to save logs.")]
[Path(Type = PathType.Directory, AllowEmpty = true)]
public string LogPath { get; set; } = string.Empty;

[CommandPropertySwitch("quiet", 'q')]
Expand Down
79 changes: 76 additions & 3 deletions src/client/LibplanetConsole.Client.Executable/SystemTerminal.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,67 @@
using System.Text;
using JSSoft.Commands.Extensions;
using JSSoft.Terminals;
using LibplanetConsole.Blockchain;
using LibplanetConsole.Common.Extensions;

namespace LibplanetConsole.Client.Executable;

internal sealed class SystemTerminal : SystemTerminalBase
{
private const string PromptText = "libplanet-client $ ";
private readonly SynchronizationContext _synchronizationContext;
private readonly CommandContext _commandContext;
private readonly IBlockChain _blockChain;
private BlockInfo _tip;

public SystemTerminal(
IHostApplicationLifetime applicationLifetime, CommandContext commandContext)
IHostApplicationLifetime applicationLifetime,
CommandContext commandContext,
IBlockChain blockChain,
SynchronizationContext synchronizationContext)
{
_synchronizationContext = synchronizationContext;
_commandContext = commandContext;
_commandContext.Owner = applicationLifetime;
Prompt = "libplanet-client $ ";
_blockChain = blockChain;
_blockChain.BlockAppended += BlockChain_BlockAppended;
_blockChain.Started += BlockChain_Started;
_blockChain.Stopped += BlockChain_Stopped;
UpdatePrompt(_blockChain.Tip);
applicationLifetime.ApplicationStopping.Register(() => Prompt = "\u001b0");
}

protected override string FormatPrompt(string prompt) => prompt;
protected override void OnDispose()
{
_blockChain.Started -= BlockChain_Started;
_blockChain.Stopped -= BlockChain_Stopped;
_blockChain.BlockAppended -= BlockChain_BlockAppended;
base.OnDispose();
}

protected override string FormatPrompt(string prompt)
{
var tip = _tip;
if (_tip.Height == -1)
{
return prompt;
}
else
{
var tsb = new TerminalStringBuilder();
tsb.AppendEnd();
tsb.Append($"#{tip.Height} ");
tsb.Foreground = TerminalColorType.BrightGreen;
tsb.Append($"{tip.Hash.ToShortString()} ");
tsb.ResetOptions();
tsb.Append($"by ");
tsb.Foreground = TerminalColorType.BrightGreen;
tsb.Append($"{tip.Miner.ToShortString()}");
tsb.ResetOptions();
tsb.AppendEnd();
return $"[{tsb}] {PromptText}";
}
}

protected override string[] GetCompletion(string[] items, string find)
=> _commandContext.GetCompletion(items, find);
Expand All @@ -29,4 +74,32 @@ protected override void OnInitialize(TextWriter @out, TextWriter error)
_commandContext.Out = @out;
_commandContext.Error = error;
}

private void BlockChain_BlockAppended(object? sender, BlockEventArgs e)
=> _synchronizationContext.Post(_ => UpdatePrompt(e.BlockInfo), null);

private void BlockChain_Started(object? sender, EventArgs e)
=> _synchronizationContext.Post(_ => UpdatePrompt(_blockChain.Tip), null);

private void BlockChain_Stopped(object? sender, EventArgs e)
=> _synchronizationContext.Post(_ => UpdatePrompt(_blockChain.Tip), null);

private void UpdatePrompt(BlockInfo tip)
{
if (tip.Height == -1)
{
Prompt = PromptText;
}
else
{
var sb = new StringBuilder();
sb.Append($"#{tip.Height} ");
sb.Append($"{tip.Hash.ToShortString()} ");
sb.Append($"by ");
sb.Append($"{tip.Miner.ToShortString()}");
Prompt = $"[{sb}] {PromptText}";
}

_tip = tip;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ private void Client_BlockAppended(object? sender, BlockEventArgs e)
var blockInfo = e.BlockInfo;
var hash = blockInfo.Hash;
var miner = blockInfo.Miner;
var message = $"Block #{blockInfo.Height} '{hash.ToShortString()}' " +
$"Appended by '{miner.ToShortString()}'";
Console.Out.WriteColoredLine(message, TerminalColorType.BrightGreen);
_logger.LogInformation(message);
_logger.LogInformation(
"Block #{TipHeight} '{TipHash}' Appended by '{TipMiner}'",
blockInfo.Height,
hash.ToShortString(),
miner.ToShortString());
}
}
5 changes: 5 additions & 0 deletions src/client/LibplanetConsole.Client/Client.BlockChain.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Security.Cryptography;
using Grpc.Core;
using LibplanetConsole.Blockchain;
using LibplanetConsole.Blockchain.Grpc;
using LibplanetConsole.Node;

Expand All @@ -9,6 +10,10 @@ internal sealed partial class Client : IBlockChain
{
private static readonly Codec _codec = new();

public event EventHandler<BlockEventArgs>? BlockAppended;

public BlockInfo Tip => Info.Tip;

public async Task<TxId> SendTransactionAsync(
IAction[] actions, CancellationToken cancellationToken)
{
Expand Down
30 changes: 21 additions & 9 deletions src/client/LibplanetConsole.Client/Client.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Grpc.Core;
using Grpc.Net.Client;
using LibplanetConsole.Blockchain;
using LibplanetConsole.Blockchain.Grpc;
Expand Down Expand Up @@ -31,8 +32,6 @@ public Client(ILogger<Client> logger, ApplicationOptions options)
_logger.LogDebug("Client is created: {Address}", Address);
}

public event EventHandler<BlockEventArgs>? BlockAppended;

public event EventHandler? Started;

public event EventHandler? Stopped;
Expand Down Expand Up @@ -85,11 +84,11 @@ public async Task StartAsync(CancellationToken cancellationToken)
var blockChainService = new BlockChainService(channel);
nodeService.Started += (sender, e) => InvokeNodeStartedEvent(e);
nodeService.Stopped += (sender, e) => InvokeNodeStoppedEvent();
blockChainService.BlockAppended += (sender, e) => InvokeBlockAppendedEvent(e);
blockChainService.BlockAppended += BlockChainService_BlockAppended;
try
{
await nodeService.StartAsync(cancellationToken);
await blockChainService.StartAsync(cancellationToken);
await nodeService.InitializeAsync(cancellationToken);
await blockChainService.InitializeAsync(cancellationToken);
}
catch
{
Expand All @@ -102,7 +101,11 @@ public async Task StartAsync(CancellationToken cancellationToken)
_channel = channel;
_nodeService = nodeService;
_blockChainService = blockChainService;
_info = _info with { NodeAddress = NodeInfo.Address };
_info = _info with
{
NodeAddress = NodeInfo.Address,
Tip = nodeService.Info.Tip,
};
IsRunning = true;
_logger.LogDebug(
"Client is started: {Address} -> {NodeAddress}", Address, NodeInfo.Address);
Expand All @@ -124,13 +127,13 @@ public async Task StopAsync(CancellationToken cancellationToken)

if (_nodeService is not null)
{
await _nodeService.StopAsync(cancellationToken);
await _nodeService.ReleaseAsync(cancellationToken);
_nodeService = null;
}

if (_blockChainService is not null)
{
await _blockChainService.StopAsync(cancellationToken);
await _blockChainService.ReleaseAsync(cancellationToken);
_blockChainService = null;
}

Expand All @@ -140,7 +143,7 @@ public async Task StopAsync(CancellationToken cancellationToken)
_blockChainService = null;
_nodeService = null;
IsRunning = false;
_info = _info with { NodeAddress = default };
_info = ClientInfo.Empty;
_logger.LogDebug("Client is stopped: {Address}", Address);
Stopped?.Invoke(this, EventArgs.Empty);
}
Expand Down Expand Up @@ -186,4 +189,13 @@ private void NodeService_Disconnected(object? sender, EventArgs e)
Stopped?.Invoke(this, EventArgs.Empty);
}
}

private void BlockChainService_BlockAppended(object? sender, BlockEventArgs e)
{
_info = _info with
{
Tip = e.BlockInfo,
};
BlockAppended?.Invoke(this, e);
}
}
1 change: 1 addition & 0 deletions src/client/LibplanetConsole.Client/Commands/TxCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using JSSoft.Commands;
using LibplanetConsole.Blockchain;
using LibplanetConsole.Common.Actions;
using LibplanetConsole.Common.Extensions;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public async override Task<GetNextNonceResponse> GetNextNonce(
public override async Task<GetTipHashResponse> GetTipHash(
GetTipHashRequest request, ServerCallContext context)
{
var blockHash = await blockChain.GetTipHashAsync(context.CancellationToken);
var blockHash = await Task.FromResult(blockChain.Tip.Hash);
return new GetTipHashResponse { BlockHash = blockHash.ToString() };
}

Expand Down
2 changes: 0 additions & 2 deletions src/client/LibplanetConsole.Client/IClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,4 @@ public interface IClient : IVerifier
Task StartAsync(CancellationToken cancellationToken);

Task StopAsync(CancellationToken cancellationToken);

Task<TxId> SendTransactionAsync(IAction[] actions, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using JSSoft.Commands;
using LibplanetConsole.Blockchain;
using LibplanetConsole.Client.Commands;
using LibplanetConsole.Common;
using Microsoft.Extensions.DependencyInjection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public async Task NewAsync(
string nodeAddress = "", CancellationToken cancellationToken = default)
{
var node = nodes.Current ?? throw new InvalidOperationException("No node is selected.");
var evidence = node.GetRequiredService<IEvidence>();
var evidence = node.GetRequiredKeyedService<IEvidence>(INode.Key);
var evidenceInfo = await evidence.AddEvidenceAsync(cancellationToken);
await Out.WriteLineAsJsonAsync(evidenceInfo);
}
Expand All @@ -25,15 +25,15 @@ public async Task RaiseAsync(
CancellationToken cancellationToken = default)
{
var node = nodes.Current ?? throw new InvalidOperationException("No node is selected.");
var evidence = node.GetRequiredService<IEvidence>();
var evidence = node.GetRequiredKeyedService<IEvidence>(INode.Key);
await evidence.ViolateAsync(cancellationToken);
}

[CommandMethod]
public async Task ListAsync(long height = -1, CancellationToken cancellationToken = default)
{
var node = nodes.Current ?? throw new InvalidOperationException("No node is selected.");
var evidence = node.GetRequiredService<IEvidence>();
var evidence = node.GetRequiredKeyedService<IEvidence>(INode.Key);
var evidenceInfos = await evidence.GetEvidenceAsync(height, cancellationToken);
await Out.WriteLineAsJsonAsync(evidenceInfos);
}
Expand All @@ -44,7 +44,7 @@ public async Task UnjailAsync(
CancellationToken cancellationToken = default)
{
var node = nodes.Current ?? throw new InvalidOperationException("No node is selected.");
var evidence = node.GetService<IEvidenceContent>();
var evidence = node.GetRequiredKeyedService<IEvidence>(INode.Key);
await evidence.UnjailAsync(cancellationToken);
}
#endif // LIBPLANET_DPOS
Expand Down
Loading

0 comments on commit 0b15963

Please sign in to comment.