添加bt与tracker交互

Change-Id: I1327c2ed89a76bee8e2abeb8cb3014b56357689a
diff --git a/src/main/java/com/pt/service/TrackerService.java b/src/main/java/com/pt/service/TrackerService.java
new file mode 100644
index 0000000..7167ff3
--- /dev/null
+++ b/src/main/java/com/pt/service/TrackerService.java
@@ -0,0 +1,76 @@
+package com.pt.service;
+
+import com.pt.entity.TorrentMeta;
+import com.pt.repository.TorrentMetaRepository;
+import com.pt.utils.BencodeCodec;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+@Service
+public class TrackerService {
+
+    private final Map<String, List<PeerInfo>> torrentPeers = new ConcurrentHashMap<>();
+
+    @Autowired
+    private TorrentMetaRepository torrentMetaRepository;
+
+    public byte[] handleAnnounce(Map<String, String[]> params, String ipAddress) {
+        try {
+            if (!params.containsKey("info_hash") || !params.containsKey("peer_id") || !params.containsKey("port")) {
+                return BencodeCodec.encode(Map.of("failure reason", "Missing required parameters"));
+            }
+
+            String infoHash = decodeParam(params.get("info_hash")[0]);
+            TorrentMeta meta = torrentMetaRepository.findByInfoHash(infoHash);
+            if (meta == null) {
+                return BencodeCodec.encode(Map.of("failure reason", "Invalid info_hash"));
+            }
+
+            String peerId = decodeParam(params.get("peer_id")[0]);
+            int port = Integer.parseInt(params.get("port")[0]);
+
+            PeerInfo peer = new PeerInfo(ipAddress, port, peerId);
+
+            torrentPeers.computeIfAbsent(infoHash, k -> new CopyOnWriteArrayList<>());
+            List<PeerInfo> peers = torrentPeers.get(infoHash);
+
+            boolean exists = peers.stream().anyMatch(p -> p.peerId.equals(peerId));
+            if (!exists) {
+                peers.add(peer);
+            }
+
+            List<String> ips = peers.stream().map(p -> p.ip).toList();
+            List<Integer> ports = peers.stream().map(p -> p.port).toList();
+            byte[] peerBytes = BencodeCodec.buildCompactPeers(ips, ports);
+
+            return BencodeCodec.buildTrackerResponse(1800, peerBytes);
+        } catch (Exception e) {
+            return BencodeCodec.encode(Map.of("failure reason", "Internal server error"));
+        }
+    }
+
+    private String decodeParam(String raw) {
+        return new String(raw.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
+    }
+
+    private static class PeerInfo {
+        String ip;
+        int port;
+        String peerId;
+
+        public PeerInfo(String ip, int port, String peerId) {
+            this.ip = ip;
+            this.port = port;
+            this.peerId = peerId;
+        }
+    }
+}
+