blob: 9e567a6f41f161582a3c3769a6a0b13eef28a847 [file] [log] [blame]
wuchimedes223bfab2025-04-04 17:16:05 +08001package com.example.g8backend.controller;
2
wuchimedesdb9fe682025-04-22 19:24:11 +08003import com.example.g8backend.dto.AnnounceRequestDTO;
4import com.example.g8backend.dto.AnnounceResponseDTO;
2230107166504b72025-06-08 13:54:29 +08005import com.example.g8backend.util.BencodeUtil;
wuchimedesdb9fe682025-04-22 19:24:11 +08006import jakarta.servlet.http.HttpServletRequest;
22301071f1381f82025-06-06 21:32:34 +08007import org.slf4j.Logger;
8import org.slf4j.LoggerFactory;
wuchimedes223bfab2025-04-04 17:16:05 +08009import org.springframework.beans.factory.annotation.Autowired;
10import org.springframework.http.ResponseEntity;
wuchimedesa0649c62025-04-05 15:53:39 +080011import org.springframework.web.bind.annotation.*;
wuchimedes223bfab2025-04-04 17:16:05 +080012import com.example.g8backend.service.ITrackerService;
13
2230107123955142025-06-09 16:37:03 +080014import java.io.UnsupportedEncodingException;
15import java.net.URLDecoder;
16import java.util.HashMap;
17import java.util.Map;
18import java.util.regex.Matcher;
19import java.util.regex.Pattern;
20
wuchimedes223bfab2025-04-04 17:16:05 +080021@RestController
wuchimedesa0649c62025-04-05 15:53:39 +080022@RequestMapping("/tracker")
wuchimedes223bfab2025-04-04 17:16:05 +080023public class TrackerController {
24
2230107166504b72025-06-08 13:54:29 +080025 private static final Logger logger = LoggerFactory.getLogger(TrackerController.class);
26
wuchimedesa0649c62025-04-05 15:53:39 +080027 @Autowired
28 private ITrackerService trackerService;
2230107123955142025-06-09 16:37:03 +080029 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 }
wuchimedesa0649c62025-04-05 15:53:39 +080049
2230107166504b72025-06-08 13:54:29 +080050 @GetMapping(value = "/announce/{passkey}", produces = "application/x-bittorrent")
2230107123955142025-06-09 16:37:03 +080051 public ResponseEntity<String> getAnnouncements(
wuchimedesdb9fe682025-04-22 19:24:11 +080052 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,
2230107123955142025-06-09 16:37:03 +080061 @PathVariable String passkey) throws UnsupportedEncodingException {
wuchimedesa0649c62025-04-05 15:53:39 +080062
2230107166504b72025-06-08 13:54:29 +080063 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);
2230107123955142025-06-09 16:37:03 +080065 String url = request.getQueryString();
wuchimedesdb9fe682025-04-22 19:24:11 +080066 AnnounceRequestDTO requestDTO = new AnnounceRequestDTO();
67 requestDTO.setPasskey(passkey);
2230107123955142025-06-09 16:37:03 +080068 logger.info("Passkey:{}", getInfoHash(url));
69 requestDTO.setInfoHash(getInfoHash(url));
wuchimedesdb9fe682025-04-22 19:24:11 +080070 requestDTO.setPeerId(peerId);
71 requestDTO.setPort(port);
72 requestDTO.setUploaded(uploaded);
73 requestDTO.setDownloaded(downloaded);
74 requestDTO.setEvent(event);
2230107166504b72025-06-08 13:54:29 +080075 requestDTO.setLeft(left != null ? left : 0.0);
wuchimedesdb9fe682025-04-22 19:24:11 +080076 requestDTO.setCompact(compact);
77
2230107166504b72025-06-08 13:54:29 +080078 String ipAddress = extractClientIp(request);
79 requestDTO.setIp(ipAddress);
22301071f1381f82025-06-06 21:32:34 +080080
2230107166504b72025-06-08 13:54:29 +080081 AnnounceResponseDTO responseDTO = trackerService.handleAnnounce(requestDTO);
2230107123955142025-06-09 16:37:03 +080082 Map<String, Object> response = new HashMap<>();
83 response.put("interval", responseDTO.getInterval());
84 response.put("peers", responseDTO.getPeers());
85 String bencodeResponse = BencodeUtil.encodeISO(response);
2230107166504b72025-06-08 13:54:29 +080086 return ResponseEntity
87 .ok()
88 .header("Content-Type", "application/x-bittorrent")
2230107123955142025-06-09 16:37:03 +080089 .body(bencodeResponse);
2230107166504b72025-06-08 13:54:29 +080090 }
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();
wuchimedesdb9fe682025-04-22 19:24:11 +080099 }
2230107166504b72025-06-08 13:54:29 +0800100 return request.getRemoteAddr();
wuchimedesa0649c62025-04-05 15:53:39 +0800101 }
wuchimedes223bfab2025-04-04 17:16:05 +0800102}