-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add IRendererService and implementations of IObservable
- Loading branch information
Showing
13 changed files
with
265 additions
and
38 deletions.
There are no files selected for viewing
40 changes: 40 additions & 0 deletions
40
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,40 @@ | ||
using Libplanet.Node.Services; | ||
|
||
namespace Libplanet.Node.API; | ||
|
||
internal sealed class BlockChainRendererTracer( | ||
IRendererService rendererService, ILogger<BlockChainRendererTracer> logger) | ||
: IObserver<RenderBlockInfo>, IHostedService | ||
{ | ||
private readonly ILogger<BlockChainRendererTracer> _logger = logger; | ||
private IDisposable? _subscription; | ||
|
||
public Task StartAsync(CancellationToken cancellationToken) | ||
{ | ||
_subscription = rendererService.RenderBlockEnd.Subscribe(this); | ||
return Task.CompletedTask; | ||
} | ||
|
||
public Task StopAsync(CancellationToken cancellationToken) | ||
{ | ||
_subscription?.Dispose(); | ||
_subscription = null; | ||
return Task.CompletedTask; | ||
} | ||
|
||
void IObserver<RenderBlockInfo>.OnCompleted() | ||
{ | ||
} | ||
|
||
void IObserver<RenderBlockInfo>.OnError(Exception error) | ||
{ | ||
} | ||
|
||
void IObserver<RenderBlockInfo>.OnNext(RenderBlockInfo value) | ||
{ | ||
_logger.LogInformation( | ||
"#{Height} Block end: {Hash}", | ||
value.NewTip.Index, | ||
value.NewTip.Hash); | ||
} | ||
} |
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 |
---|---|---|
@@ -1,4 +1,5 @@ | ||
using Libplanet.Blockchain; | ||
using Libplanet.Types.Blocks; | ||
|
||
namespace Libplanet.Node.Services; | ||
|
||
|
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,12 @@ | ||
namespace Libplanet.Node.Services; | ||
|
||
public interface IRendererService | ||
{ | ||
IObservable<RenderBlockInfo> RenderBlock { get; } | ||
|
||
IObservable<RenderActionInfo> RenderAction { get; } | ||
|
||
IObservable<RenderActionErrorInfo> RenderActionError { get; } | ||
|
||
IObservable<RenderBlockInfo> RenderBlockEnd { get; } | ||
} |
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,51 @@ | ||
namespace Libplanet.Node.Services; | ||
|
||
public sealed class Observable<T> : IObservable<T>, IDisposable | ||
{ | ||
private readonly List<IObserver<T>> _observerList = []; | ||
private bool _isDisposed; | ||
|
||
public void Dispose() | ||
{ | ||
if (!_isDisposed) | ||
{ | ||
foreach (var observer in _observerList) | ||
{ | ||
observer.OnCompleted(); | ||
} | ||
|
||
_observerList.Clear(); | ||
_isDisposed = true; | ||
} | ||
|
||
GC.SuppressFinalize(this); | ||
} | ||
|
||
public void Invoke(T value) | ||
{ | ||
_observerList.ForEach(observer => observer.OnNext(value)); | ||
} | ||
|
||
public void InvokeError(Exception exception) | ||
{ | ||
_observerList.ForEach(observer => observer.OnError(exception)); | ||
} | ||
|
||
IDisposable IObservable<T>.Subscribe(IObserver<T> observer) | ||
{ | ||
_observerList.Add(observer); | ||
return new Unsubscriber(_observerList, observer); | ||
} | ||
|
||
private sealed class Unsubscriber(List<IObserver<T>> observerList, IObserver<T> observer) | ||
: IDisposable | ||
{ | ||
private readonly IObserver<T> _observer = observer; | ||
private readonly List<IObserver<T>> _observerList = observerList; | ||
|
||
public void Dispose() | ||
{ | ||
_observerList.Remove(_observer); | ||
} | ||
} | ||
} |
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,16 @@ | ||
namespace Libplanet.Node.Services; | ||
|
||
public sealed class Observer<T> : IObserver<T> | ||
{ | ||
public System.Action? Completed { get; init; } | ||
|
||
public Action<Exception>? Error { get; init; } | ||
|
||
public Action<T>? Next { get; init; } | ||
|
||
void IObserver<T>.OnCompleted() => Completed?.Invoke(); | ||
|
||
void IObserver<T>.OnError(Exception error) => Error?.Invoke(error); | ||
|
||
void IObserver<T>.OnNext(T value) => Next?.Invoke(value); | ||
} |
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,9 @@ | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
|
||
namespace Libplanet.Node.Services; | ||
|
||
public readonly record struct RenderActionErrorInfo( | ||
IValue Action, | ||
ICommittedActionContext Context, | ||
Exception Exception); |
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,11 @@ | ||
using System.Security.Cryptography; | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
using Libplanet.Common; | ||
|
||
namespace Libplanet.Node.Services; | ||
|
||
public readonly record struct RenderActionInfo( | ||
IValue Action, | ||
ICommittedActionContext Context, | ||
HashDigest<SHA256> NextState); |
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,7 @@ | ||
using Libplanet.Types.Blocks; | ||
|
||
namespace Libplanet.Node.Services; | ||
|
||
public readonly record struct RenderBlockInfo( | ||
Block OldTip, | ||
Block NewTip); |
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,95 @@ | ||
using System.Security.Cryptography; | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
using Libplanet.Blockchain.Renderers; | ||
using Libplanet.Common; | ||
using Libplanet.Types.Blocks; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Libplanet.Node.Services; | ||
|
||
internal sealed class RendererService( | ||
SynchronizationContext synchronizationContext, | ||
ILogger<RendererService> logger) : IRendererService, IActionRenderer, IDisposable | ||
{ | ||
private readonly Observable<RenderBlockInfo> _renderBlock = new(); | ||
private readonly Observable<RenderActionInfo> _renderAction = new(); | ||
private readonly Observable<RenderActionErrorInfo> _renderActionError = new(); | ||
private readonly Observable<RenderBlockInfo> _renderBlockEnd = new(); | ||
|
||
IObservable<RenderBlockInfo> IRendererService.RenderBlock => _renderBlock; | ||
|
||
IObservable<RenderActionInfo> IRendererService.RenderAction => _renderAction; | ||
|
||
IObservable<RenderActionErrorInfo> IRendererService.RenderActionError => _renderActionError; | ||
|
||
IObservable<RenderBlockInfo> IRendererService.RenderBlockEnd => _renderBlockEnd; | ||
|
||
public void Dispose() | ||
{ | ||
_renderBlock.Dispose(); | ||
_renderAction.Dispose(); | ||
_renderActionError.Dispose(); | ||
_renderBlockEnd.Dispose(); | ||
} | ||
|
||
void IActionRenderer.RenderAction( | ||
IValue action, ICommittedActionContext context, HashDigest<SHA256> nextState) | ||
{ | ||
synchronizationContext.Post( | ||
state => | ||
{ | ||
_renderAction.Invoke(new(action, context, nextState)); | ||
logger.LogDebug( | ||
"Rendered an action: {Action} {Context} {NextState}", | ||
action, | ||
context, | ||
nextState); | ||
}, | ||
null); | ||
} | ||
|
||
void IActionRenderer.RenderActionError( | ||
IValue action, ICommittedActionContext context, Exception exception) | ||
{ | ||
synchronizationContext.Post( | ||
state => | ||
{ | ||
_renderActionError.Invoke(new(action, context, exception)); | ||
logger.LogError( | ||
exception, | ||
"Failed to render an action: {Action} {Context}", | ||
action, | ||
context); | ||
}, | ||
null); | ||
} | ||
|
||
void IRenderer.RenderBlock(Block oldTip, Block newTip) | ||
{ | ||
synchronizationContext.Post( | ||
state => | ||
{ | ||
_renderBlock.Invoke(new(oldTip, newTip)); | ||
logger.LogDebug( | ||
"Rendered a block: {OldTip} {NewTip}", | ||
oldTip, | ||
newTip); | ||
}, | ||
null); | ||
} | ||
|
||
void IActionRenderer.RenderBlockEnd(Block oldTip, Block newTip) | ||
{ | ||
synchronizationContext.Post( | ||
state => | ||
{ | ||
_renderBlockEnd.Invoke(new(oldTip, newTip)); | ||
logger.LogDebug( | ||
"Rendered a block end: {OldTip} {NewTip}", | ||
oldTip, | ||
newTip); | ||
}, | ||
null); | ||
} | ||
} |