Пример #1
0
        private static async Task RebuildConnectionAsync(
            KademliaProtocol protocol,
            CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    await Task.Delay(TimeSpan.FromMinutes(10), cancellationToken);

                    await protocol.RebuildConnectionAsync(Kademlia.MaxDepth, cancellationToken);
                }
                catch (OperationCanceledException e)
                {
                    Log.Warning(e, $"{nameof(RebuildConnectionAsync)}() is cancelled.");
                    throw;
                }
                catch (Exception e)
                {
                    var msg = "Unexpected exception occurred during " +
                              $"{nameof(RebuildConnectionAsync)}(): {{0}}";
                    Log.Warning(e, msg, e);
                }
            }
        }
Пример #2
0
        public TestTransport(
            Dictionary <Address, TestTransport> transports,
            PrivateKey privateKey,
            int?tableSize,
            int?bucketSize,
            TimeSpan?networkDelay)
        {
            _privateKey = privateKey;
            var loggerId = _privateKey.PublicKey.ToAddress().ToHex();

            _logger = Log.ForContext <TestTransport>()
                      .ForContext("Address", loggerId);

            _peersToReply    = new ConcurrentDictionary <byte[], Address>();
            _replyToReceive  = new ConcurrentDictionary <byte[], Message>();
            ReceivedMessages = new ConcurrentBag <Message>();
            MessageReceived  = new AsyncAutoResetEvent();
            _transports      = transports;
            _transports[privateKey.PublicKey.ToAddress()] = this;
            _networkDelay = networkDelay ?? TimeSpan.Zero;
            _requests     = new AsyncCollection <Request>();
            _ignoreTestMessageWithData = new List <string>();
            _random  = new Random();
            Protocol = new KademliaProtocol(this, Address, 0, _logger, tableSize, bucketSize);
        }
Пример #3
0
        private static async Task RefreshTableAsync(
            KademliaProtocol protocol,
            CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);

                    await protocol.RefreshTableAsync(TimeSpan.FromSeconds(60), cancellationToken);

                    await protocol.CheckReplacementCacheAsync(cancellationToken);
                }
                catch (OperationCanceledException e)
                {
                    Log.Warning(e, $"{nameof(RefreshTableAsync)}() is cancelled.");
                    throw;
                }
                catch (Exception e)
                {
                    var msg = "Unexpected exception occurred during " +
                              $"{nameof(RefreshTableAsync)}(): {{0}}";
                    Log.Warning(e, msg, e);
                }
            }
        }
Пример #4
0
        public TestTransport(
            Dictionary <Address, TestTransport> transports,
            PrivateKey privateKey,
            bool blockBroadcast,
            int tableSize,
            int bucketSize,
            TimeSpan?networkDelay)
        {
            _runningEvent   = new TaskCompletionSource <object>();
            _privateKey     = privateKey;
            _blockBroadcast = blockBroadcast;
            var loggerId = _privateKey.ToAddress().ToHex();

            _logger = Log.ForContext <TestTransport>()
                      .ForContext("Address", loggerId);

            _peersToReply    = new ConcurrentDictionary <byte[], Address>();
            _replyToReceive  = new ConcurrentDictionary <byte[], Message>();
            ReceivedMessages = new ConcurrentBag <Message>();
            MessageReceived  = new AsyncAutoResetEvent();
            _transports      = transports;
            _transports[privateKey.ToAddress()] = this;
            _networkDelay = networkDelay ?? TimeSpan.Zero;
            _requests     = new AsyncCollection <Request>();
            _ignoreTestMessageWithData = new List <string>();
            _random = new Random();
            Table   = new RoutingTable(Address, tableSize, bucketSize);
            ProcessMessageHandler = new AsyncDelegate <Message>();
            Protocol       = new KademliaProtocol(Table, this, Address);
            MessageHistory = new FixedSizedQueue <Message>(30);
        }
Пример #5
0
        private static async Task CheckStaticPeersAsync(
            IEnumerable <BoundPeer> peers,
            RoutingTable table,
            KademliaProtocol protocol,
            CancellationToken cancellationToken)
        {
            var boundPeers = peers as BoundPeer[] ?? peers.ToArray();

            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);

                    Log.Warning("Checking static peers. {@Peers}", boundPeers);
                    var peersToAdd = boundPeers.Where(peer => !table.Contains(peer)).ToArray();
                    if (peersToAdd.Any())
                    {
                        Log.Warning("Some of peers are not in routing table. {@Peers}", peersToAdd);
                        await protocol.AddPeersAsync(
                            peersToAdd,
                            TimeSpan.FromSeconds(5),
                            cancellationToken);
                    }
                }
                catch (OperationCanceledException e)
                {
                    Log.Warning(e, $"{nameof(CheckStaticPeersAsync)}() is cancelled.");
                    throw;
                }
                catch (Exception e)
                {
                    var msg = "Unexpected exception occurred during " +
                              $"{nameof(CheckStaticPeersAsync)}(): {{0}}";
                    Log.Warning(e, msg, e);
                }
            }
        }
Пример #6
0
#pragma warning disable MEN003 // Method Main must be no longer than 120 lines
        public static async Task Main(string[] args)
        {
            Options options = Options.Parse(args, Console.Error);

            var loggerConfig = new LoggerConfiguration();

            switch (options.LogLevel)
            {
            case "error":
                loggerConfig = loggerConfig.MinimumLevel.Error();
                break;

            case "warning":
                loggerConfig = loggerConfig.MinimumLevel.Warning();
                break;

            case "information":
                loggerConfig = loggerConfig.MinimumLevel.Information();
                break;

            case "debug":
                loggerConfig = loggerConfig.MinimumLevel.Debug();
                break;

            case "verbose":
                loggerConfig = loggerConfig.MinimumLevel.Verbose();
                break;

            default:
                loggerConfig = loggerConfig.MinimumLevel.Information();
                break;
            }

            loggerConfig = loggerConfig
                           .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
                           .Enrich.FromLogContext()
                           .WriteTo.Console();
            Log.Logger = loggerConfig.CreateLogger();

            if (options.IceServer is null && options.Host is null)
            {
                Log.Error(
                    "-h/--host is required if -I/--ice-server is not given."
                    );
                Environment.Exit(1);
                return;
            }

            if (!(options.IceServer is null || options.Host is null))
            {
                Log.Warning("-I/--ice-server will not work because -h/--host is given.");
            }

            try
            {
                var          privateKey = options.PrivateKey ?? new PrivateKey();
                RoutingTable table      = new RoutingTable(privateKey.ToAddress());
                ITransport   transport;
                switch (options.TransportType)
                {
                case "tcp":
                    transport = new TcpTransport(
                        privateKey,
                        AppProtocolVersion.FromToken(options.AppProtocolVersionToken),
                        null,
                        host: options.Host,
                        listenPort: options.Port,
                        iceServers: new[] { options.IceServer },
                        differentAppProtocolVersionEncountered: null);
                    break;

                case "netmq":
                    transport = new NetMQTransport(
                        privateKey,
                        AppProtocolVersion.FromToken(options.AppProtocolVersionToken),
                        null,
                        workers: options.Workers,
                        host: options.Host,
                        listenPort: options.Port,
                        iceServers: new[] { options.IceServer },
                        differentAppProtocolVersionEncountered: null);
                    break;

                default:
                    Log.Error(
                        "-t/--transport-type must be either \"tcp\" or \"netmq\".");
                    Environment.Exit(1);
                    return;
                }

                KademliaProtocol peerDiscovery = new KademliaProtocol(
                    table,
                    transport,
                    privateKey.ToAddress());
                Startup.TableSingleton = table;

                IWebHost webHost = WebHost.CreateDefaultBuilder()
                                   .UseStartup <SeedStartup <Startup> >()
                                   .UseSerilog()
                                   .UseUrls($"http://{options.GraphQLHost}:{options.GraphQLPort}/")
                                   .Build();

                using (var cts = new CancellationTokenSource())
                {
                    Console.CancelKeyPress += (sender, eventArgs) =>
                    {
                        eventArgs.Cancel = true;
                        cts.Cancel();
                    };

                    try
                    {
                        var tasks = new List <Task>
                        {
                            webHost.RunAsync(cts.Token),
                            StartTransportAsync(transport, cts.Token),
                            RefreshTableAsync(peerDiscovery, cts.Token),
                            RebuildConnectionAsync(peerDiscovery, cts.Token),
                        };
                        if (!(options.Peers is null) && options.Peers.Any())
                        {
                            tasks.Add(CheckStaticPeersAsync(
                                          options.Peers,
                                          table,
                                          peerDiscovery,
                                          cts.Token));
                        }

                        await Task.WhenAll(tasks);
                    }
                    catch (OperationCanceledException)
                    {
                        await transport.StopAsync(TimeSpan.FromSeconds(1));
                    }
                }
            }
            catch (InvalidOptionValueException e)
            {
                string expectedValues = string.Join(", ", e.ExpectedValues);
                Console.Error.WriteLine($"Unexpected value given through '{e.OptionName}'\n"
                                        + $"  given value: {e.OptionValue}\n"
                                        + $"  expected values: {expectedValues}");
            }
        }
Пример #7
0
        public static async Task Main(string[] args)
        {
            Options options = Options.Parse(args, Console.Error);

            var loggerConfig = new LoggerConfiguration();

            loggerConfig = options.Debug
                ? loggerConfig.MinimumLevel.Debug()
                : loggerConfig.MinimumLevel.Information();
            loggerConfig = loggerConfig
                           .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
                           .Enrich.FromLogContext()
                           .WriteTo.Console();
            Log.Logger = loggerConfig.CreateLogger();

            try
            {
                var            privateKey = options.PrivateKey ?? new PrivateKey();
                RoutingTable   table      = new RoutingTable(privateKey.ToAddress());
                NetMQTransport transport  = new NetMQTransport(
                    table,
                    privateKey,
                    AppProtocolVersion.FromToken(options.AppProtocolVersionToken),
                    null,
                    options.Workers,
                    options.Host,
                    options.Port,
                    new[] { options.IceServer },
                    null);
                KademliaProtocol peerDiscovery = new KademliaProtocol(
                    table,
                    transport,
                    privateKey.ToAddress());
                Startup.TableSingleton = table;

                IWebHost webHost = WebHost.CreateDefaultBuilder()
                                   .UseStartup <SeedStartup <Startup> >()
                                   .UseSerilog()
                                   .UseUrls($"http://{options.GraphQLHost}:{options.GraphQLPort}/")
                                   .Build();

                using (var cts = new CancellationTokenSource())
                {
                    Console.CancelKeyPress += (sender, eventArgs) =>
                    {
                        eventArgs.Cancel = true;
                        cts.Cancel();
                    };

                    try
                    {
                        var tasks = new List <Task>
                        {
                            webHost.RunAsync(cts.Token),
                            StartTransportAsync(transport, cts.Token),
                            RefreshTableAsync(peerDiscovery, cts.Token),
                            RebuildConnectionAsync(peerDiscovery, cts.Token),
                        };
                        if (!(options.Peers is null) && options.Peers.Any())
                        {
                            tasks.Add(CheckStaticPeersAsync(
                                          options.Peers,
                                          table,
                                          peerDiscovery,
                                          cts.Token));
                        }

                        await Task.WhenAll(tasks);
                    }
                    catch (OperationCanceledException)
                    {
                        await transport.StopAsync(TimeSpan.FromSeconds(1));
                    }
                }
            }
            catch (InvalidOptionValueException e)
            {
                string expectedValues = string.Join(", ", e.ExpectedValues);
                Console.Error.WriteLine($"Unexpected value given through '{e.OptionName}'\n"
                                        + $"  given value: {e.OptionValue}\n"
                                        + $"  expected values: {expectedValues}");
            }
        }