wuchimedes | 223bfab | 2025-04-04 17:16:05 +0800 | [diff] [blame] | 1 | package com.example.g8backend.controller; |
| 2 | |
wuchimedes | db9fe68 | 2025-04-22 19:24:11 +0800 | [diff] [blame] | 3 | import com.example.g8backend.dto.AnnounceRequestDTO; |
| 4 | import com.example.g8backend.dto.AnnounceResponseDTO; |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 5 | import com.example.g8backend.util.BencodeUtil; |
wuchimedes | db9fe68 | 2025-04-22 19:24:11 +0800 | [diff] [blame] | 6 | import jakarta.servlet.http.HttpServletRequest; |
22301071 | f1381f8 | 2025-06-06 21:32:34 +0800 | [diff] [blame] | 7 | import org.slf4j.Logger; |
| 8 | import org.slf4j.LoggerFactory; |
wuchimedes | 223bfab | 2025-04-04 17:16:05 +0800 | [diff] [blame] | 9 | import org.springframework.beans.factory.annotation.Autowired; |
| 10 | import org.springframework.http.ResponseEntity; |
wuchimedes | a0649c6 | 2025-04-05 15:53:39 +0800 | [diff] [blame] | 11 | import org.springframework.web.bind.annotation.*; |
wuchimedes | 223bfab | 2025-04-04 17:16:05 +0800 | [diff] [blame] | 12 | import com.example.g8backend.service.ITrackerService; |
| 13 | |
22301071 | 2395514 | 2025-06-09 16:37:03 +0800 | [diff] [blame^] | 14 | import java.io.UnsupportedEncodingException; |
| 15 | import java.net.URLDecoder; |
| 16 | import java.util.HashMap; |
| 17 | import java.util.Map; |
| 18 | import java.util.regex.Matcher; |
| 19 | import java.util.regex.Pattern; |
| 20 | |
wuchimedes | 223bfab | 2025-04-04 17:16:05 +0800 | [diff] [blame] | 21 | @RestController |
wuchimedes | a0649c6 | 2025-04-05 15:53:39 +0800 | [diff] [blame] | 22 | @RequestMapping("/tracker") |
wuchimedes | 223bfab | 2025-04-04 17:16:05 +0800 | [diff] [blame] | 23 | public class TrackerController { |
| 24 | |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 25 | private static final Logger logger = LoggerFactory.getLogger(TrackerController.class); |
| 26 | |
wuchimedes | a0649c6 | 2025-04-05 15:53:39 +0800 | [diff] [blame] | 27 | @Autowired |
| 28 | private ITrackerService trackerService; |
22301071 | 2395514 | 2025-06-09 16:37:03 +0800 | [diff] [blame^] | 29 | private String getInfoHash(String queryStr) throws UnsupportedEncodingException { |
| 30 | Pattern INFO_HASH = Pattern.compile("info_hash=([^&]+)"); |
| 31 | Matcher matcher = INFO_HASH.matcher(queryStr); |
| 32 | StringBuilder hexString = new StringBuilder(); |
| 33 | if (matcher.find()) { |
| 34 | String matchedHash = matcher.group(1); |
| 35 | String decodeInfoHash = URLDecoder.decode(matchedHash, "ISO-8859-1"); |
| 36 | byte[] infoHashBytes = decodeInfoHash.getBytes("ISO-8859-1"); |
| 37 | for (byte b : infoHashBytes) { |
| 38 | String hex = Integer.toHexString(b & 0xFF); |
| 39 | if (hex.length() == 1) { |
| 40 | hexString.append('0'); |
| 41 | } |
| 42 | hexString.append(hex); |
| 43 | } |
| 44 | return hexString.toString(); |
| 45 | } else { |
| 46 | return null; |
| 47 | } |
| 48 | } |
wuchimedes | a0649c6 | 2025-04-05 15:53:39 +0800 | [diff] [blame] | 49 | |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 50 | @GetMapping(value = "/announce/{passkey}", produces = "application/x-bittorrent") |
22301071 | 2395514 | 2025-06-09 16:37:03 +0800 | [diff] [blame^] | 51 | public ResponseEntity<String> getAnnouncements( |
wuchimedes | db9fe68 | 2025-04-22 19:24:11 +0800 | [diff] [blame] | 52 | HttpServletRequest request, |
| 53 | @RequestParam("info_hash") String infoHash, |
| 54 | @RequestParam("peer_id") String peerId, |
| 55 | @RequestParam("port") int port, |
| 56 | @RequestParam("uploaded") double uploaded, |
| 57 | @RequestParam("downloaded") double downloaded, |
| 58 | @RequestParam(value = "event", required = false) String event, |
| 59 | @RequestParam(value = "left", required = false) Double left, |
| 60 | @RequestParam(value = "compact", required = false) Integer compact, |
22301071 | 2395514 | 2025-06-09 16:37:03 +0800 | [diff] [blame^] | 61 | @PathVariable String passkey) throws UnsupportedEncodingException { |
wuchimedes | a0649c6 | 2025-04-05 15:53:39 +0800 | [diff] [blame] | 62 | |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 63 | logger.info("Announce request received: info_hash={}, peer_id={}, port={}, uploaded={}, downloaded={}, event={}, left={}, compact={}, passkey={}", |
| 64 | infoHash, peerId, port, uploaded, downloaded, event, left, compact, passkey); |
22301071 | 2395514 | 2025-06-09 16:37:03 +0800 | [diff] [blame^] | 65 | String url = request.getQueryString(); |
wuchimedes | db9fe68 | 2025-04-22 19:24:11 +0800 | [diff] [blame] | 66 | AnnounceRequestDTO requestDTO = new AnnounceRequestDTO(); |
| 67 | requestDTO.setPasskey(passkey); |
22301071 | 2395514 | 2025-06-09 16:37:03 +0800 | [diff] [blame^] | 68 | logger.info("Passkey:{}", getInfoHash(url)); |
| 69 | requestDTO.setInfoHash(getInfoHash(url)); |
wuchimedes | db9fe68 | 2025-04-22 19:24:11 +0800 | [diff] [blame] | 70 | requestDTO.setPeerId(peerId); |
| 71 | requestDTO.setPort(port); |
| 72 | requestDTO.setUploaded(uploaded); |
| 73 | requestDTO.setDownloaded(downloaded); |
| 74 | requestDTO.setEvent(event); |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 75 | requestDTO.setLeft(left != null ? left : 0.0); |
wuchimedes | db9fe68 | 2025-04-22 19:24:11 +0800 | [diff] [blame] | 76 | requestDTO.setCompact(compact); |
| 77 | |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 78 | String ipAddress = extractClientIp(request); |
| 79 | requestDTO.setIp(ipAddress); |
22301071 | f1381f8 | 2025-06-06 21:32:34 +0800 | [diff] [blame] | 80 | |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 81 | AnnounceResponseDTO responseDTO = trackerService.handleAnnounce(requestDTO); |
22301071 | 2395514 | 2025-06-09 16:37:03 +0800 | [diff] [blame^] | 82 | Map<String, Object> response = new HashMap<>(); |
| 83 | response.put("interval", responseDTO.getInterval()); |
| 84 | response.put("peers", responseDTO.getPeers()); |
| 85 | String bencodeResponse = BencodeUtil.encodeISO(response); |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 86 | return ResponseEntity |
| 87 | .ok() |
| 88 | .header("Content-Type", "application/x-bittorrent") |
22301071 | 2395514 | 2025-06-09 16:37:03 +0800 | [diff] [blame^] | 89 | .body(bencodeResponse); |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | /** |
| 93 | * 提取客户端 IP,支持 X-Forwarded-For |
| 94 | */ |
| 95 | private String extractClientIp(HttpServletRequest request) { |
| 96 | String xfHeader = request.getHeader("X-Forwarded-For"); |
| 97 | if (xfHeader != null && !xfHeader.isEmpty()) { |
| 98 | return xfHeader.split(",")[0].trim(); |
wuchimedes | db9fe68 | 2025-04-22 19:24:11 +0800 | [diff] [blame] | 99 | } |
22301071 | 66504b7 | 2025-06-08 13:54:29 +0800 | [diff] [blame] | 100 | return request.getRemoteAddr(); |
wuchimedes | a0649c6 | 2025-04-05 15:53:39 +0800 | [diff] [blame] | 101 | } |
wuchimedes | 223bfab | 2025-04-04 17:16:05 +0800 | [diff] [blame] | 102 | } |