void ExceptionOnMessagePump(Exception ex) { if (!_Disposed) { ListenerTrace.Error("Error on azure message pumped", ex); LastException = ex; } }
void HandleException(Task t) { if (t.IsFaulted) { if (!_Disposed) { ListenerTrace.Error("Error during asynchronous task", t.Exception); LastException = t.Exception; } } }
public IDisposable OnMessageAsync(Func <T, MessageControl, Task> evt, OnMessageOptions options = null) { if (options == null) { options = new OnMessageOptions() { AutoComplete = true, MaxConcurrentCalls = 10, AutoRenewTimeout = TimeSpan.Zero } } ; return(OnMessageAsyncCore(async bm => { var control = new MessageControl(); control.Options = options; var obj = ToObject(bm); if (obj == null) { return; } await evt(obj, control).ConfigureAwait(false); if (control._Scheduled != null) { BrokeredMessage message = new BrokeredMessage(Serializer.ToString(obj)); message.MessageId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(32)); message.ScheduledEnqueueTimeUtc = control._Scheduled.Value; await SendAsync(message).ConfigureAwait(false); if (!options.AutoComplete) { if (control._Complete) { try { await bm.CompleteAsync().ConfigureAwait(false); } catch (ObjectDisposedException) { ListenerTrace.Error("Brokered message already disposed", null); } } } } }, options)); }
Task Async(Action act) { var t = new Task(() => { try { act(); } catch (Exception ex) { if (!_Disposed) { ListenerTrace.Error("Error during task.", ex); LastException = ex; } } }); t.Start(TaskScheduler.Default); return(t); }
public void Listen(ConcurrentChain chain = null) { ListenerTrace.Info($"Connecting to node {_Configuration.Indexer.Node}"); var ip = Utils.ParseIpEndpoint(_Configuration.Indexer.Node, Configuration.Indexer.Network.DefaultPort); ListenerTrace.Info($"Connecting to node ip {ip.ToString()}"); var node = Node.Connect(Configuration.Indexer.Network, ip); ListenerTrace.Info($"Connected, trying handshake..."); node.VersionHandshake(); ListenerTrace.Info($"Hanshaked"); node.Disconnect(); _Chain = new ConcurrentChain(_Configuration.Indexer.Network); _Indexer = Configuration.Indexer.CreateIndexer(); if (chain == null) { chain = new ConcurrentChain(_Configuration.Indexer.Network); } _Chain = chain; ListenerTrace.Info("Fetching headers from " + _Chain.Tip.Height + " (from azure)"); var client = Configuration.Indexer.CreateIndexerClient(); client.SynchronizeChain(chain); ListenerTrace.Info("Headers fetched tip " + _Chain.Tip.Height); _Disposables.Add(_IndexerScheduler = new CustomThreadPoolTaskScheduler(50, 100, "Indexing Threads")); _Indexer.TaskScheduler = _IndexerScheduler; _Group = new NodesGroup(Configuration.Indexer.Network); _Disposables.Add(_Group); _Group.AllowSameGroup = true; _Group.MaximumNodeConnection = 2; AddressManager addrman = new AddressManager(); addrman.Add(new NetworkAddress(ip), IPAddress.Parse("127.0.0.1")); _Group.NodeConnectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addrman) { Mode = AddressManagerBehaviorMode.None }); _Group.NodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(_Chain) { SkipPoWCheck = true }); _Group.NodeConnectionParameters.TemplateBehaviors.Add(new Behavior(this)); ListenerTrace.Info("Fetching wallet rules..."); _Wallets = _Configuration.Indexer.CreateIndexerClient().GetAllWalletRules(); ListenerTrace.Info("Wallet rules fetched"); ListenerTrace.Info("Fetching wallet subscriptions..."); _Subscriptions = new SubscriptionCollection(_Configuration.GetSubscriptionsTable().Read()); ListenerTrace.Info("Subscriptions fetched"); _Group.Connect(); ListenerTrace.Info("Fetching transactions to broadcast..."); _Disposables.Add( Configuration .Topics .BroadcastedTransactions .CreateConsumer("listener", true) .EnsureSubscriptionExists() .OnMessage((tx, ctl) => { uint256 hash = null; var repo = Configuration.Indexer.CreateIndexerClient(); var rejects = Configuration.GetRejectTable(); try { hash = tx.Transaction.GetHash(); var indexedTx = repo.GetTransaction(hash); ListenerTrace.Info("Broadcasting " + hash); var reject = rejects.ReadOne(hash.ToString()); if (reject != null) { ListenerTrace.Info("Abort broadcasting of rejected"); return; } if (_Broadcasting.Count > 1000) { _Broadcasting.Clear(); } _Broadcasting.TryAdd(hash, tx.Transaction); if (indexedTx == null || !indexedTx.BlockIds.Any(id => Chain.Contains(id))) { var unused = SendMessageAsync(tx.Transaction); } var reschedule = new[] { TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10), TimeSpan.FromHours(1), TimeSpan.FromHours(6), TimeSpan.FromHours(24), }; if (tx.Tried <= reschedule.Length - 1) { ctl.RescheduleIn(reschedule[tx.Tried]); tx.Tried++; } } catch (Exception ex) { if (!_Disposed) { LastException = ex; ListenerTrace.Error("Error for new broadcasted transaction " + hash, ex); throw; } } })); ListenerTrace.Info("Transactions to broadcast fetched"); _Disposables.Add(_Configuration .Topics .SubscriptionChanges .EnsureSubscriptionExists() .AddUnhandledExceptionHandler(ExceptionOnMessagePump) .OnMessage(c => { using (_SubscriptionSlimLock.LockWrite()) { if (c.Added) { _Subscriptions.Add(c.Subscription); } else { _Subscriptions.Remove(c.Subscription.Id); } } })); _Disposables.Add(_Configuration .Topics .SendNotifications .AddUnhandledExceptionHandler(ExceptionOnMessagePump) .OnMessageAsync((n, act) => { return(SendAsync(n, act).ContinueWith(t => { if (!_Disposed) { if (t.Exception != null) { LastException = t.Exception; } } })); }, new OnMessageOptions() { MaxConcurrentCalls = 1000, AutoComplete = true, AutoRenewTimeout = TimeSpan.Zero })); _Disposables.Add(Configuration .Topics .AddedAddresses .CreateConsumer("updater", true) .EnsureSubscriptionExists() .AddUnhandledExceptionHandler(ExceptionOnMessagePump) .OnMessage(evt => { if (evt == null) { return; } ListenerTrace.Info("New wallet rule"); using (_WalletsSlimLock.LockWrite()) { foreach (var address in evt) { _Wallets.Add(address.CreateWalletRuleEntry()); } } })); }
static void Main(string[] args) { var options = new ListenerOptions(); if (args.Length == 0) { System.Console.WriteLine(options.GetUsage()); } if (Parser.Default.ParseArguments(args, options)) { if (options.Configuration != null) { if (!File.Exists(options.Configuration)) { System.Console.WriteLine("File " + new FileInfo(options.Configuration).FullName + " not found"); return; } AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", new FileInfo(options.Configuration).FullName); } var iconf = new ConfigurationManagerConfiguration(); var conf = QBitNinjaConfiguration.FromConfiguration(iconf); conf.EnsureSetup(); if (options.CancelInit) { var indexer = new InitialIndexer(conf); indexer.Cancel(); } if (options.Init) { var indexer = new InitialIndexer(conf); while (true) { try { indexer.Run(); break; } catch (Exception ex) { ListenerTrace.Error("Error while Running the initial sync indexer, retrying...", ex); System.Threading.Thread.Sleep(5000); } } } List <IDisposable> dispo = new List <IDisposable>(); List <Task> running = new List <Task>(); try { if (options.Listen) { QBitNinjaNodeListener listener = new QBitNinjaNodeListener(conf); dispo.Add(listener); listener.Listen(); running.Add(listener.Running); } if (options.Web) { System.Console.WriteLine("Trying to listen on http://*:" + options.Port + "/"); var server = WebApp.Start("http://*:" + options.Port, appBuilder => { var config = new HttpConfiguration(); var qbit = QBitNinjaConfiguration.FromConfiguration(iconf); qbit.EnsureSetup(); WebApiConfig.Register(config, qbit); UpdateChainListener listener = new UpdateChainListener(); dispo.Add(listener); listener.Listen(config); appBuilder.UseWebApi(config); running.Add(new TaskCompletionSource <int>().Task); }); dispo.Add(server); System.Console.WriteLine("Server started"); Process.Start("http://localhost:" + options.Port + "/blocks/tip"); } if (running.Count != 0) { try { running.Add(WaitInput()); Task.WaitAny(running.ToArray()); } catch (AggregateException aex) { ExceptionDispatchInfo.Capture(aex.InnerException).Throw(); throw; } } } finally { foreach (var d in dispo) { d.Dispose(); } } } }