/// <summary> /// Starts the network services. /// </summary> /// <returns> /// A task that represents the asynchronous operation. /// </returns> /// <remarks> /// Starts the various IPFS and PeerTalk network services. This should /// be called after any configuration changes. /// </remarks> /// <exception cref="Exception"> /// When the engine is already started. /// </exception> public async Task StartAsync() { if (stopTasks.Count > 0) { throw new Exception("IPFS engine is already started."); } // Repository must be at the correct version. await MigrationManager.MirgrateToVersionAsync(MigrationManager.LatestVersion) .ConfigureAwait(false); var localPeer = await LocalPeer.ConfigureAwait(false); log.Debug("starting " + localPeer.Id); // Everybody needs the swarm. var swarm = await SwarmService.ConfigureAwait(false); stopTasks.Add(async() => { await swarm.StopAsync().ConfigureAwait(false); }); await swarm.StartAsync().ConfigureAwait(false); var peerManager = new PeerManager { Swarm = swarm }; await peerManager.StartAsync().ConfigureAwait(false); stopTasks.Add(async() => { await peerManager.StopAsync().ConfigureAwait(false); }); // Start the primary services. var tasks = new List <Func <Task> > { async() => { var bitswap = await BitswapService.ConfigureAwait(false); stopTasks.Add(async() => await bitswap.StopAsync().ConfigureAwait(false)); await bitswap.StartAsync().ConfigureAwait(false); }, async() => { var dht = await DhtService.ConfigureAwait(false); stopTasks.Add(async() => await dht.StopAsync().ConfigureAwait(false)); await dht.StartAsync().ConfigureAwait(false); }, async() => { var ping = await PingService.ConfigureAwait(false); stopTasks.Add(async() => await ping.StopAsync().ConfigureAwait(false)); await ping.StartAsync().ConfigureAwait(false); }, async() => { var pubsub = await PubSubService.ConfigureAwait(false); stopTasks.Add(async() => await pubsub.StopAsync().ConfigureAwait(false)); await pubsub.StartAsync().ConfigureAwait(false); }, }; log.Debug("waiting for services to start"); await Task.WhenAll(tasks.Select(t => t())).ConfigureAwait(false); // Starting listening to the swarm. var json = await Config.GetAsync("Addresses.Swarm").ConfigureAwait(false); var numberListeners = 0; foreach (string a in json) { try { await swarm.StartListeningAsync(a).ConfigureAwait(false); ++numberListeners; } catch (Exception e) { log.Warn($"Listener failure for '{a}'", e); // eat the exception } } if (numberListeners == 0) { log.Error("No listeners were created."); } // Now that the listener addresses are established, the discovery // services can begin. MulticastService multicast = null; if (!Options.Discovery.DisableMdns) { multicast = new MulticastService(); #pragma warning disable CS1998 stopTasks.Add(async() => multicast.Dispose()); #pragma warning restore CS1998 } var autodialer = new AutoDialer(swarm) { MinConnections = Options.Swarm.MinConnections }; #pragma warning disable CS1998 stopTasks.Add(async() => autodialer.Dispose()); #pragma warning restore CS1998 tasks = new List <Func <Task> > { // Bootstrap discovery async() => { var bootstrap = new PeerTalk.Discovery.Bootstrap { Addresses = await this.Bootstrap.ListAsync() }; bootstrap.PeerDiscovered += OnPeerDiscovered; stopTasks.Add(async() => await bootstrap.StopAsync().ConfigureAwait(false)); await bootstrap.StartAsync().ConfigureAwait(false); }, // New multicast DNS discovery async() => { if (Options.Discovery.DisableMdns) { return; } var mdns = new PeerTalk.Discovery.MdnsNext { LocalPeer = localPeer, MulticastService = multicast }; if (Options.Swarm.PrivateNetworkKey != null) { mdns.ServiceName = $"_p2p-{Options.Swarm.PrivateNetworkKey.Fingerprint().ToHexString()}._udp"; } mdns.PeerDiscovered += OnPeerDiscovered; stopTasks.Add(async() => await mdns.StopAsync().ConfigureAwait(false)); await mdns.StartAsync().ConfigureAwait(false); }, // Old style JS multicast DNS discovery async() => { if (Options.Discovery.DisableMdns || Options.Swarm.PrivateNetworkKey != null) { return; } var mdns = new PeerTalk.Discovery.MdnsJs { LocalPeer = localPeer, MulticastService = multicast }; mdns.PeerDiscovered += OnPeerDiscovered; stopTasks.Add(async() => await mdns.StopAsync().ConfigureAwait(false)); await mdns.StartAsync().ConfigureAwait(false); }, // Old style GO multicast DNS discovery async() => { if (Options.Discovery.DisableMdns || Options.Swarm.PrivateNetworkKey != null) { return; } var mdns = new PeerTalk.Discovery.MdnsGo { LocalPeer = localPeer, MulticastService = multicast }; mdns.PeerDiscovered += OnPeerDiscovered; stopTasks.Add(async() => await mdns.StopAsync().ConfigureAwait(false)); await mdns.StartAsync().ConfigureAwait(false); }, async() => { if (Options.Discovery.DisableRandomWalk) { return; } var randomWalk = new RandomWalk { Dht = Dht }; stopTasks.Add(async() => await randomWalk.StopAsync().ConfigureAwait(false)); await randomWalk.StartAsync().ConfigureAwait(false); } }; log.Debug("waiting for discovery services to start"); await Task.WhenAll(tasks.Select(t => t())).ConfigureAwait(false); multicast?.Start(); log.Debug("started"); }