public async Task <IActionResult> ConnectWebSocket( string cryptoCode, bool includeTransaction = true, CancellationToken cancellation = default) { if (!HttpContext.WebSockets.IsWebSocketRequest) { return(NotFound()); } GetNetwork(cryptoCode, false); // Internally check if cryptoCode is correct string listenAllDerivationSchemes = null; string listenAllTrackedSource = null; var listenedBlocks = new ConcurrentDictionary <string, string>(); var listenedDerivations = new ConcurrentDictionary <(Network, DerivationStrategyBase), DerivationStrategyBase>(); var listenedTrackedSource = new ConcurrentDictionary <(Network, TrackedSource), TrackedSource>(); WebsocketMessageListener server = new WebsocketMessageListener(await HttpContext.WebSockets.AcceptWebSocketAsync(), _SerializerSettings); CompositeDisposable subscriptions = new CompositeDisposable(); subscriptions.Add(_EventAggregator.Subscribe <Models.NewBlockEvent>(async o => { if (listenedBlocks.ContainsKey(o.CryptoCode)) { await server.Send(o); } })); subscriptions.Add(_EventAggregator.Subscribe <Models.NewTransactionEvent>(async o => { var network = Waiters.GetWaiter(o.CryptoCode); if (network == null) { return; } bool forward = false; var derivationScheme = (o.TrackedSource as DerivationSchemeTrackedSource)?.DerivationStrategy; if (derivationScheme != null) { forward |= listenAllDerivationSchemes == "*" || listenAllDerivationSchemes == o.CryptoCode || listenedDerivations.ContainsKey((network.Network.NBitcoinNetwork, derivationScheme)); } forward |= listenAllTrackedSource == "*" || listenAllTrackedSource == o.CryptoCode || listenedTrackedSource.ContainsKey((network.Network.NBitcoinNetwork, o.TrackedSource)); if (forward) { var derivation = (o.TrackedSource as DerivationSchemeTrackedSource)?.DerivationStrategy; await server.Send(o); } })); try { while (server.Socket.State == WebSocketState.Open) { object message = await server.NextMessageAsync(cancellation); switch (message) { case Models.NewBlockEventRequest r: r.CryptoCode = r.CryptoCode ?? cryptoCode; listenedBlocks.TryAdd(r.CryptoCode, r.CryptoCode); break; case Models.NewTransactionEventRequest r: var network = Waiters.GetWaiter(r.CryptoCode)?.Network; if (r.DerivationSchemes != null) { r.CryptoCode = r.CryptoCode ?? cryptoCode; if (network != null) { foreach (var derivation in r.DerivationSchemes) { var parsed = new DerivationStrategyFactory(network.NBitcoinNetwork).Parse(derivation); listenedDerivations.TryAdd((network.NBitcoinNetwork, parsed), parsed); } } } else if ( // Back compat: If no derivation scheme precised and ListenAllDerivationSchemes not set, we listen all (r.TrackedSources == null && r.ListenAllDerivationSchemes == null) || (r.ListenAllDerivationSchemes != null && r.ListenAllDerivationSchemes.Value)) { listenAllDerivationSchemes = r.CryptoCode; } if (r.ListenAllTrackedSource != null && r.ListenAllTrackedSource.Value) { listenAllTrackedSource = r.CryptoCode; } else if (r.TrackedSources != null) { r.CryptoCode = r.CryptoCode ?? cryptoCode; if (network != null) { foreach (var trackedSource in r.TrackedSources) { if (TrackedSource.TryParse(trackedSource, out var parsed, network.NBitcoinNetwork)) { listenedTrackedSource.TryAdd((network.NBitcoinNetwork, parsed), parsed); } } } } break; default: break; } } } catch when(server.Socket.State != WebSocketState.Open) { } finally { subscriptions.Dispose(); await server.DisposeAsync(cancellation); } return(new EmptyResult()); }
public async Task <IActionResult> ConnectWebSocket( string cryptoCode, bool includeTransaction = true, CancellationToken cancellation = default) { if (!HttpContext.WebSockets.IsWebSocketRequest) { return(NotFound()); } GetNetwork(cryptoCode); // Internally check if cryptoCode is correct string listenAllDerivationSchemes = null; var listenedBlocks = new ConcurrentDictionary <string, string>(); var listenedDerivations = new ConcurrentDictionary <(Network, DerivationStrategyBase), DerivationStrategyBase>(); WebsocketMessageListener server = new WebsocketMessageListener(await HttpContext.WebSockets.AcceptWebSocketAsync(), _SerializerSettings); CompositeDisposable subscriptions = new CompositeDisposable(); subscriptions.Add(_EventAggregator.Subscribe <Events.NewBlockEvent>(async o => { if (listenedBlocks.ContainsKey(o.CryptoCode)) { var chain = ChainProvider.GetChain(o.CryptoCode); if (chain == null) { return; } var block = chain.GetBlock(o.BlockId); if (block != null) { await server.Send(new Models.NewBlockEvent() { CryptoCode = o.CryptoCode, Hash = block.HashBlock, Height = block.Height, PreviousBlockHash = block?.Previous.HashBlock }); } } })); subscriptions.Add(_EventAggregator.Subscribe <Events.NewTransactionMatchEvent>(async o => { var network = Waiters.GetWaiter(o.CryptoCode); if (network == null) { return; } if ( listenAllDerivationSchemes == "*" || listenAllDerivationSchemes == o.CryptoCode || listenedDerivations.ContainsKey((network.Network.NBitcoinNetwork, o.Match.DerivationStrategy))) { var chain = ChainProvider.GetChain(o.CryptoCode); if (chain == null) { return; } var blockHeader = o.BlockId == null ? null : chain.GetBlock(o.BlockId); await server.Send(new Models.NewTransactionEvent() { CryptoCode = o.CryptoCode, DerivationStrategy = o.Match.DerivationStrategy, BlockId = blockHeader?.HashBlock, TransactionData = ToTransactionResult(includeTransaction, chain, new[] { o.SavedTransaction }), Inputs = o.Match.Inputs, Outputs = o.Match.Outputs }); } })); try { while (server.Socket.State == WebSocketState.Open) { object message = await server.NextMessageAsync(cancellation); switch (message) { case Models.NewBlockEventRequest r: r.CryptoCode = r.CryptoCode ?? cryptoCode; listenedBlocks.TryAdd(r.CryptoCode, r.CryptoCode); break; case Models.NewTransactionEventRequest r: if (r.DerivationSchemes != null) { r.CryptoCode = r.CryptoCode ?? cryptoCode; var network = Waiters.GetWaiter(r.CryptoCode)?.Network; if (network == null) { break; } foreach (var derivation in r.DerivationSchemes) { var parsed = new DerivationStrategyFactory(network.NBitcoinNetwork).Parse(derivation); listenedDerivations.TryAdd((network.NBitcoinNetwork, parsed), parsed); } } else { listenAllDerivationSchemes = r.CryptoCode; } break; default: break; } } } catch when(server.Socket.State != WebSocketState.Open) { } finally { subscriptions.Dispose(); await server.DisposeAsync(cancellation); } return(new EmptyResult()); }