blob: 9e567a6f41f161582a3c3769a6a0b13eef28a847 [file] [log] [blame]
package com.example.g8backend.controller;
import com.example.g8backend.dto.AnnounceRequestDTO;
import com.example.g8backend.dto.AnnounceResponseDTO;
import com.example.g8backend.util.BencodeUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.example.g8backend.service.ITrackerService;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@RestController
@RequestMapping("/tracker")
public class TrackerController {
private static final Logger logger = LoggerFactory.getLogger(TrackerController.class);
@Autowired
private ITrackerService trackerService;
private String getInfoHash(String queryStr) throws UnsupportedEncodingException {
Pattern INFO_HASH = Pattern.compile("info_hash=([^&]+)");
Matcher matcher = INFO_HASH.matcher(queryStr);
StringBuilder hexString = new StringBuilder();
if (matcher.find()) {
String matchedHash = matcher.group(1);
String decodeInfoHash = URLDecoder.decode(matchedHash, "ISO-8859-1");
byte[] infoHashBytes = decodeInfoHash.getBytes("ISO-8859-1");
for (byte b : infoHashBytes) {
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} else {
return null;
}
}
@GetMapping(value = "/announce/{passkey}", produces = "application/x-bittorrent")
public ResponseEntity<String> getAnnouncements(
HttpServletRequest request,
@RequestParam("info_hash") String infoHash,
@RequestParam("peer_id") String peerId,
@RequestParam("port") int port,
@RequestParam("uploaded") double uploaded,
@RequestParam("downloaded") double downloaded,
@RequestParam(value = "event", required = false) String event,
@RequestParam(value = "left", required = false) Double left,
@RequestParam(value = "compact", required = false) Integer compact,
@PathVariable String passkey) throws UnsupportedEncodingException {
logger.info("Announce request received: info_hash={}, peer_id={}, port={}, uploaded={}, downloaded={}, event={}, left={}, compact={}, passkey={}",
infoHash, peerId, port, uploaded, downloaded, event, left, compact, passkey);
String url = request.getQueryString();
AnnounceRequestDTO requestDTO = new AnnounceRequestDTO();
requestDTO.setPasskey(passkey);
logger.info("Passkey:{}", getInfoHash(url));
requestDTO.setInfoHash(getInfoHash(url));
requestDTO.setPeerId(peerId);
requestDTO.setPort(port);
requestDTO.setUploaded(uploaded);
requestDTO.setDownloaded(downloaded);
requestDTO.setEvent(event);
requestDTO.setLeft(left != null ? left : 0.0);
requestDTO.setCompact(compact);
String ipAddress = extractClientIp(request);
requestDTO.setIp(ipAddress);
AnnounceResponseDTO responseDTO = trackerService.handleAnnounce(requestDTO);
Map<String, Object> response = new HashMap<>();
response.put("interval", responseDTO.getInterval());
response.put("peers", responseDTO.getPeers());
String bencodeResponse = BencodeUtil.encodeISO(response);
return ResponseEntity
.ok()
.header("Content-Type", "application/x-bittorrent")
.body(bencodeResponse);
}
/**
* 提取客户端 IP,支持 X-Forwarded-For
*/
private String extractClientIp(HttpServletRequest request) {
String xfHeader = request.getHeader("X-Forwarded-For");
if (xfHeader != null && !xfHeader.isEmpty()) {
return xfHeader.split(",")[0].trim();
}
return request.getRemoteAddr();
}
}