-
Notifications
You must be signed in to change notification settings - Fork 152
Commit
- Loading branch information
There are no files selected for viewing
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); | ||
} | ||
} |
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; | ||
|
||
|
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; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
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) | ||
{ | ||
foreach (var observer in _observerList) | ||
{ | ||
observer.OnNext(value); | ||
} | ||
} | ||
|
||
public void InvokeError(Exception exception) | ||
{ | ||
foreach (var observer in _observerList) | ||
{ | ||
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); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
namespace Libplanet.Node.Services; | ||
|
||
public class Observer<T> : IObserver<T> | ||
{ | ||
public void OnCompleted() | ||
{ | ||
throw new NotImplementedException(); | ||
Check warning on line 7 in sdk/node/Libplanet.Node/Services/Observer.cs GitHub Actions / docs
Check warning on line 7 in sdk/node/Libplanet.Node/Services/Observer.cs GitHub Actions / docs
|
||
} | ||
|
||
public void OnError(Exception error) | ||
{ | ||
throw new NotImplementedException(); | ||
Check warning on line 12 in sdk/node/Libplanet.Node/Services/Observer.cs GitHub Actions / docs
Check warning on line 12 in sdk/node/Libplanet.Node/Services/Observer.cs GitHub Actions / docs
|
||
} | ||
|
||
public void OnNext(T value) | ||
{ | ||
throw new NotImplementedException(); | ||
Check warning on line 17 in sdk/node/Libplanet.Node/Services/Observer.cs GitHub Actions / docs
Check warning on line 17 in sdk/node/Libplanet.Node/Services/Observer.cs GitHub Actions / docs
|
||
} | ||
} |
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); |
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); |
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); |
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); | ||
} | ||
} |