blob: ea840e14c9c693032bf65a0f0e59dd5353b182ec [file] [log] [blame]
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +08001package com.pt.service;
2
3import com.pt.entity.TorrentMeta;
4import com.pt.repository.TorrentMetaRepository;
5import com.pt.utils.BencodeCodec;
6import org.springframework.beans.factory.annotation.Autowired;
7import org.springframework.stereotype.Service;
8
22301102ca0fb2f2025-06-09 18:40:42 +08009import java.io.UnsupportedEncodingException;
10import java.net.URLDecoder;
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080011import java.nio.charset.StandardCharsets;
22301102ca0fb2f2025-06-09 18:40:42 +080012import java.util.*;
13import java.util.concurrent.ConcurrentHashMap;
14import java.util.concurrent.CopyOnWriteArrayList;
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080015
16@Service
17public class TrackerService {
18
22301102ca0fb2f2025-06-09 18:40:42 +080019 private final Map<String, List<PeerInfo>> torrentPeers = new ConcurrentHashMap<>();
22301102f5670302025-06-08 14:10:02 +080020
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080021 @Autowired
22 private TorrentMetaRepository torrentMetaRepository;
23
24 public byte[] handleAnnounce(Map<String, String[]> params, String ipAddress) {
25 try {
22301102ca0fb2f2025-06-09 18:40:42 +080026 if (!params.containsKey("info_hash") || !params.containsKey("peer_id") || !params.containsKey("port")) {
27 return BencodeCodec.encode(Map.of("failure reason", "Missing required parameters"));
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080028 }
29
22301102ca0fb2f2025-06-09 18:40:42 +080030 System.out.println("Received announce params: " + params);
31 System.out.println("Client IP: " + ipAddress);
32
33 // 用ISO-8859-1解码,确保二进制数据正确还原
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080034 String infoHash = decodeParam(params.get("info_hash")[0]);
22301102ca0fb2f2025-06-09 18:40:42 +080035 System.out.println("Decoded info_hash (raw bytes as hex): " + bytesToHex(infoHash.getBytes("ISO-8859-1")));
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080036
22301102ca0fb2f2025-06-09 18:40:42 +080037 Optional<TorrentMeta> meta = torrentMetaRepository.findByInfoHash(infoHash);
38 if (!meta.isPresent()) {
39 System.out.println("Invalid info_hash: not found in DB");
40 return BencodeCodec.encode(Map.of("failure reason", "Invalid info_hash"));
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080041 }
42
22301102ca0fb2f2025-06-09 18:40:42 +080043 String peerId = decodeParam(params.get("peer_id")[0]);
44 System.out.println("Decoded peer_id: " + peerId);
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080045
22301102ca0fb2f2025-06-09 18:40:42 +080046 int port = Integer.parseInt(params.get("port")[0]);
47 System.out.println("Port: " + port);
ystxdfd42b32025-06-07 13:26:52 +080048
22301102ca0fb2f2025-06-09 18:40:42 +080049 PeerInfo peer = new PeerInfo(ipAddress, port, peerId);
ystxdfd42b32025-06-07 13:26:52 +080050
22301102ca0fb2f2025-06-09 18:40:42 +080051 torrentPeers.computeIfAbsent(infoHash, k -> new CopyOnWriteArrayList<>());
52 List<PeerInfo> peers = torrentPeers.get(infoHash);
ystxdfd42b32025-06-07 13:26:52 +080053
22301102ca0fb2f2025-06-09 18:40:42 +080054 boolean exists = peers.stream().anyMatch(p -> p.peerId.equals(peerId));
55 if (!exists) {
56 peers.add(peer);
57 System.out.println("Added new peer: " + peerId);
58 } else {
59 System.out.println("Peer already exists: " + peerId);
60 }
ystxdfd42b32025-06-07 13:26:52 +080061
22301102ca0fb2f2025-06-09 18:40:42 +080062 List<String> ips = peers.stream().map(p -> p.ip).toList();
63 List<Integer> ports = peers.stream().map(p -> p.port).toList();
64 byte[] peerBytes = BencodeCodec.buildCompactPeers(ips, ports);
ystxdfd42b32025-06-07 13:26:52 +080065
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080066 return BencodeCodec.buildTrackerResponse(1800, peerBytes);
67 } catch (Exception e) {
22301102ca0fb2f2025-06-09 18:40:42 +080068 e.printStackTrace(); // 打印异常堆栈,方便定位错误
69 return BencodeCodec.encode(Map.of("failure reason", "Internal server error"));
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080070 }
71 }
72
22301102ca0fb2f2025-06-09 18:40:42 +080073 // 辅助函数:打印字节转成16进制字符串
74 private String bytesToHex(byte[] bytes) {
75 StringBuilder sb = new StringBuilder();
76 for (byte b : bytes) {
77 sb.append(String.format("%02x", b));
22301102f5670302025-06-08 14:10:02 +080078 }
22301102ca0fb2f2025-06-09 18:40:42 +080079 return sb.toString();
ystxdfd42b32025-06-07 13:26:52 +080080 }
81
22301102ca0fb2f2025-06-09 18:40:42 +080082 // decodeParam 建议用ISO-8859-1解码
83 private String decodeParam(String param) throws UnsupportedEncodingException {
84 return URLDecoder.decode(param, "ISO-8859-1");
ystxdfd42b32025-06-07 13:26:52 +080085 }
86
ystxdfd42b32025-06-07 13:26:52 +080087
22301102ca0fb2f2025-06-09 18:40:42 +080088 private static class PeerInfo {
89 String ip;
90 int port;
91 String peerId;
ystxdfd42b32025-06-07 13:26:52 +080092
22301102ca0fb2f2025-06-09 18:40:42 +080093 public PeerInfo(String ip, int port, String peerId) {
94 this.ip = ip;
95 this.port = port;
96 this.peerId = peerId;
ystxdfd42b32025-06-07 13:26:52 +080097 }
98 }
22301102ca0fb2f2025-06-09 18:40:42 +080099}
ystxdfd42b32025-06-07 13:26:52 +0800100