forked from planetarium/libplanet
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request planetarium#3925 from planetarium/introduce/render…
…-observables ✨ Introduce/render observables
- Loading branch information
Showing
31 changed files
with
487 additions
and
148 deletions.
There are no files selected for viewing
28 changes: 28 additions & 0 deletions
28
sdk/node/Libplanet.Node.Executable/BlockChainRendererTracer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using Libplanet.Node.Services; | ||
|
||
namespace Libplanet.Node.API; | ||
|
||
internal sealed class BlockChainRendererTracer( | ||
IRendererService rendererService, ILogger<BlockChainRendererTracer> logger) | ||
: IHostedService | ||
{ | ||
private readonly ILogger<BlockChainRendererTracer> _logger = logger; | ||
private IDisposable? _observer; | ||
|
||
public Task StartAsync(CancellationToken cancellationToken) | ||
{ | ||
rendererService.RenderBlockEnd.Subscribe( | ||
info => _logger.LogInformation( | ||
"-Pattern2- #{Height} Block end: {Hash}", | ||
info.NewTip.Index, | ||
info.NewTip.Hash)); | ||
return Task.CompletedTask; | ||
} | ||
|
||
public Task StopAsync(CancellationToken cancellationToken) | ||
{ | ||
_observer?.Dispose(); | ||
_observer = null; | ||
return Task.CompletedTask; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System.Diagnostics; | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
using Libplanet.Action.State; | ||
|
||
namespace Libplanet.Node.Tests; | ||
|
||
public class DumbAction : IAction | ||
{ | ||
public string ErrorMessage { get; set; } = string.Empty; | ||
|
||
public IValue PlainValue => Dictionary.Empty | ||
.Add("error_message", ErrorMessage); | ||
|
||
public void LoadPlainValue(IValue plainValue) | ||
{ | ||
if (plainValue is Dictionary dictionary) | ||
{ | ||
ErrorMessage = (Text)dictionary["error_message"]; | ||
} | ||
else | ||
{ | ||
throw new UnreachableException("The plain value of DumbAction must be a dictionary."); | ||
} | ||
} | ||
|
||
public IWorld Execute(IActionContext context) | ||
{ | ||
if (ErrorMessage != string.Empty) | ||
{ | ||
throw new InvalidOperationException(ErrorMessage); | ||
} | ||
|
||
return context.PreviousState; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
using Libplanet.Action.Loader; | ||
using Libplanet.Action.Sys; | ||
|
||
namespace Libplanet.Node.Tests; | ||
|
||
public sealed class DumbActionLoader : IActionLoader | ||
{ | ||
public IAction LoadAction(long index, IValue value) | ||
{ | ||
if (Registry.IsSystemAction(value)) | ||
{ | ||
return Registry.Deserialize(value); | ||
} | ||
|
||
var action = new DumbAction(); | ||
action.LoadPlainValue(value); | ||
return action; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
sdk/node/Libplanet.Node.Tests/Services/RendererServiceTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
using Libplanet.Action; | ||
using Libplanet.Node.Options; | ||
using Libplanet.Node.Services; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Libplanet.Node.Tests.Services; | ||
|
||
public class RendererServiceTest | ||
{ | ||
[Fact] | ||
public async Task RenderBlock_TestAsync() | ||
{ | ||
var serviceProvider = TestUtility.CreateServiceProvider(); | ||
var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>(); | ||
var rendererService = serviceProvider.GetRequiredService<IRendererService>(); | ||
var blockChain = blockChainService.BlockChain; | ||
|
||
using var observer = new TestObserver<RenderBlockInfo>(rendererService.RenderBlock); | ||
await Assert.RaisesAnyAsync<RenderBlockInfo>( | ||
attach: handler => observer.Next += handler, | ||
detach: handler => observer.Next -= handler, | ||
testCode: async () => await BlockChainUtility.AppendBlockAsync(blockChain)); | ||
} | ||
|
||
[Fact] | ||
public async Task RenderAction_TestAsync() | ||
{ | ||
var settings = new Dictionary<string, string?> | ||
{ | ||
[$"{ActionOptions.Position}:{nameof(ActionOptions.ModulePath)}"] | ||
= typeof(DumbActionLoader).Assembly.Location, | ||
[$"{ActionOptions.Position}:{nameof(ActionOptions.ActionLoaderType)}"] | ||
= typeof(DumbActionLoader).FullName, | ||
}; | ||
|
||
var serviceProvider = TestUtility.CreateServiceProvider(settings); | ||
var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>(); | ||
var rendererService = serviceProvider.GetRequiredService<IRendererService>(); | ||
var blockChain = blockChainService.BlockChain; | ||
|
||
var actions = new IAction[] | ||
{ | ||
new DumbAction(), | ||
new DumbAction(), | ||
new DumbAction(), | ||
}; | ||
|
||
using var observer = new TestObserver<RenderActionInfo>(rendererService.RenderAction); | ||
await Assert.RaisesAnyAsync<RenderActionInfo>( | ||
attach: handler => observer.Next += handler, | ||
detach: handler => observer.Next -= handler, | ||
testCode: async () => | ||
{ | ||
BlockChainUtility.StageTransaction(blockChain, actions); | ||
await BlockChainUtility.AppendBlockAsync(blockChain); | ||
}); | ||
} | ||
|
||
[Fact] | ||
public async Task RenderActionError_TestAsync() | ||
{ | ||
var settings = new Dictionary<string, string?> | ||
{ | ||
[$"{ActionOptions.Position}:{nameof(ActionOptions.ModulePath)}"] | ||
= typeof(DumbActionLoader).Assembly.Location, | ||
[$"{ActionOptions.Position}:{nameof(ActionOptions.ActionLoaderType)}"] | ||
= typeof(DumbActionLoader).FullName, | ||
}; | ||
|
||
var serviceProvider = TestUtility.CreateServiceProvider(settings); | ||
var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>(); | ||
var rendererService = serviceProvider.GetRequiredService<IRendererService>(); | ||
var blockChain = blockChainService.BlockChain; | ||
var errorMessage = "123"; | ||
|
||
var actions = new IAction[] | ||
{ | ||
new DumbAction() { ErrorMessage = errorMessage }, | ||
}; | ||
|
||
using var observer = new TestObserver<RenderActionErrorInfo>( | ||
rendererService.RenderActionError); | ||
var errorInfo = await Assert.RaisesAnyAsync<RenderActionErrorInfo>( | ||
attach: handler => observer.Next += handler, | ||
detach: handler => observer.Next -= handler, | ||
testCode: async () => | ||
{ | ||
BlockChainUtility.StageTransaction(blockChain, actions); | ||
await BlockChainUtility.AppendBlockAsync(blockChain); | ||
}); | ||
Assert.Equal(errorMessage, errorInfo.Arguments.Exception.InnerException!.Message); | ||
} | ||
|
||
[Fact] | ||
public async Task RenderBlockEnd_TestAsync() | ||
{ | ||
var serviceProvider = TestUtility.CreateServiceProvider(); | ||
var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>(); | ||
var rendererService = serviceProvider.GetRequiredService<IRendererService>(); | ||
var blockChain = blockChainService.BlockChain; | ||
|
||
using var observer = new TestObserver<RenderBlockInfo>(rendererService.RenderBlockEnd); | ||
await Assert.RaisesAnyAsync<RenderBlockInfo>( | ||
attach: handler => observer.Next += handler, | ||
detach: handler => observer.Next -= handler, | ||
testCode: async () => await BlockChainUtility.AppendBlockAsync(blockChain)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
namespace Libplanet.Node.Tests; | ||
|
||
internal sealed class TestObserver<T> : IObserver<T>, IDisposable | ||
{ | ||
private IDisposable? _subscription; | ||
|
||
public TestObserver(IObservable<T> observable) | ||
{ | ||
_subscription = observable.Subscribe(this); | ||
} | ||
|
||
public event EventHandler? Completed; | ||
|
||
public event EventHandler? Error; | ||
|
||
public event EventHandler<T>? Next; | ||
|
||
public void Dispose() | ||
{ | ||
if (_subscription is not null) | ||
{ | ||
_subscription.Dispose(); | ||
_subscription = null; | ||
} | ||
} | ||
|
||
void IObserver<T>.OnCompleted() => Completed?.Invoke(this, EventArgs.Empty); | ||
|
||
void IObserver<T>.OnError(Exception error) => Error?.Invoke(this, EventArgs.Empty); | ||
|
||
void IObserver<T>.OnNext(T value) => Next?.Invoke(this, value); | ||
} |
Oops, something went wrong.