/// <summary>
        /// 将客户端传递的 IP 地址与端口转换为 <see cref="IPEndPoint"/> 类型。
        /// </summary>
        private IPEndPoint ConvertClientAddress(GetPeersInfoInput apiInput)
        {
            if (IPAddress.TryParse(apiInput.Ip, out IPAddress ipAddress))
            {
                return(new IPEndPoint(ipAddress, apiInput.Port));
            }

            return(null);
        }
        public AnnounceInputParameters(GetPeersInfoInput apiInput)
        {
            Error = new BDictionary();

            ClientAddress   = ConvertClientAddress(apiInput);
            InfoHash        = ConvertInfoHash(apiInput);
            Event           = ConvertTorrentEvent(apiInput);
            PeerId          = apiInput.Peer_Id;
            Uploaded        = apiInput.Uploaded;
            Downloaded      = apiInput.Downloaded;
            Left            = apiInput.Left;
            IsEnableCompact = apiInput.Compact == 1;
            PeerWantCount   = apiInput.NumWant ?? 30;
        }
예제 #3
0
        public async Task GetPeersInfo(GetPeersInfoInput input)
        {
            // 如果 BT 客户端没有传递 IP,则通过 Context 获得。
            if (string.IsNullOrEmpty(input.Ip))
            {
                input.Ip = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
            }

            // 本机测试用。
            input.Ip = "127.0.0.1";

            AnnounceInputParameters inputPara = input;
            var resultDict = new BDictionary();

            // 如果产生了错误,则不执行其他操作,直接返回结果。
            if (inputPara.Error.Count == 0)
            {
                _bitTorrentManager.UpdatePeer(input.Info_Hash, inputPara);
                _bitTorrentManager.ClearZombiePeers(input.Info_Hash, TimeSpan.FromMinutes(10));
                var peers = _bitTorrentManager.GetPeers(input.Info_Hash);

                HandlePeersData(resultDict, peers, inputPara);

                // 构建剩余字段信息
                // 客户端等待时间
                resultDict.Add(TrackerServerConsts.IntervalKey, new BNumber((int)TimeSpan.FromSeconds(30).TotalSeconds));
                // 最小等待间隔
                resultDict.Add(TrackerServerConsts.MinIntervalKey, new BNumber((int)TimeSpan.FromSeconds(30).TotalSeconds));
                // Tracker 服务器的 Id
                resultDict.Add(TrackerServerConsts.TrackerIdKey, new BString("Tracker-DEMO"));
                // 已完成的 Peer 数量
                resultDict.Add(TrackerServerConsts.CompleteKey, new BNumber(_bitTorrentManager.GetComplete(input.Info_Hash)));
                // 非做种状态的 Peer 数量
                resultDict.Add(TrackerServerConsts.IncompleteKey, new BNumber(_bitTorrentManager.GetInComplete(input.Info_Hash)));
            }
            else
            {
                resultDict = inputPara.Error;
            }

            // 写入响应结果。
            var resultDictBytes = resultDict.EncodeAsBytes();
            var response        = _httpContextAccessor.HttpContext.Response;

            response.ContentType   = "text/plain";
            response.StatusCode    = 200;
            response.ContentLength = resultDictBytes.Length;
            await response.Body.WriteAsync(resultDictBytes);
        }
        /// <summary>
        /// 将 info_hash 参数从 URL 编码转换为标准的字符串。
        /// </summary>
        private string ConvertInfoHash(GetPeersInfoInput apiInput)
        {
            var infoHashBytes = HttpUtility.UrlDecodeToBytes(apiInput.Info_Hash);

            if (infoHashBytes == null)
            {
                Error.Add(TrackerServerConsts.FailureKey, new BString("info_hash 参数不能为空."));
                return(null);
            }

            if (infoHashBytes.Length != 20)
            {
                Error.Add(TrackerServerConsts.FailureKey, new BString($"info_hash 参数的长度 {{{infoHashBytes.Length}}} 不符合 BT 协议规范."));
            }

            return(BitConverter.ToString(infoHashBytes));
        }
        /// <summary>
        /// 将客户端传递的字符串 Event 转换为 <see cref="TorrentEvent"/> 枚举。
        /// </summary>
        private TorrentEvent ConvertTorrentEvent(GetPeersInfoInput apiInput)
        {
            switch (apiInput.Event)
            {
            case "started":
                return(TorrentEvent.Started);

            case "stopped":
                return(TorrentEvent.Stopped);

            case "completed":
                return(TorrentEvent.Completed);

            default:
                return(TorrentEvent.None);
            }
        }