public P2PGroup Create(bool allowDirectP2P)
        {
            var group = new P2PGroup(_loggerFactory.CreateLogger <P2PGroup>(), _hostIdFactory.New(),
                                     _options, _sessionManager, allowDirectP2P);

            _groups.TryAdd(group.HostId, group);
            _logger.Debug("Created P2PGroup({HostId}) DirectP2P={AllowDirectP2P}", group.HostId, allowDirectP2P);
            return(group);
        }
        public override async void ChannelActive(IChannelHandlerContext context)
        {
            var hostId  = _hostIdFactory.New();
            var session = _sessionFactory.Create(_loggerFactory.CreateLogger <ProudSession>(), hostId, context.Channel);

            session.State = SessionState.Handshake;
            context.Channel.GetAttribute(ChannelAttributes.Session).Set(session);

            _logger?.Debug("New incoming client({HostId}) on {EndPoint}", hostId, context.Channel.RemoteAddress.ToString());

            var config = new NetConfigDto
            {
                EnableServerLog                    = _networkOptions.EnableServerLog,
                FallbackMethod                     = _networkOptions.FallbackMethod,
                MessageMaxLength                   = _networkOptions.MessageMaxLength,
                TimeoutTimeMs                      = _networkOptions.IdleTimeout.TotalMilliseconds,
                DirectP2PStartCondition            = _networkOptions.DirectP2PStartCondition,
                OverSendSuspectingThresholdInBytes = _networkOptions.OverSendSuspectingThresholdInBytes,
                EnableNagleAlgorithm               = _networkOptions.EnableNagleAlgorithm,
                EncryptedMessageKeyLength          = _networkOptions.EncryptedMessageKeyLength,
                AllowServerAsP2PGroupMember        = _networkOptions.AllowServerAsP2PGroupMember,
                EnableP2PEncryptedMessaging        = _networkOptions.EnableP2PEncryptedMessaging,
                UpnpDetectNatDevice                = _networkOptions.UpnpDetectNatDevice,
                UpnpTcpAddrPortMapping             = _networkOptions.UpnpTcpAddrPortMapping,
                EnablePingTest                     = _networkOptions.EnablePingTest,
                EmergencyLogLineCount              = _networkOptions.EmergencyLogLineCount
            };

            session.Send(new NotifyServerConnectionHintMessage(config, _rsa.ExportParameters(false)));
            context.Channel.Pipeline.Context(Constants.Pipeline.CoreMessageHandlerName).Read();

            using (var cts = new CancellationTokenSource(_networkOptions.ConnectTimeout))
            {
                try
                {
                    await session.HandhsakeEvent.WaitAsync(cts.Token);
                }
                catch (OperationCanceledException)
                {
                    if (!session.IsConnected)
                    {
                        return;
                    }

                    _logger.Debug("Client({HostId} - {EndPoint}) handshake timeout", hostId,
                                  context.Channel.RemoteAddress.ToString());
                    session.Send(new ConnectServerTimedoutMessage());
                    await session.CloseAsync();

                    return;
                }
            }

            base.ChannelActive(context);
        }