修改Tracker服务器相关bug

Change-Id: Id3ec61034575bd794724be98f832f8c065448b92
diff --git a/src/main/java/com/pt/service/TrackerService.java b/src/main/java/com/pt/service/TrackerService.java
index ea840e1..29ac1ad 100644
--- a/src/main/java/com/pt/service/TrackerService.java
+++ b/src/main/java/com/pt/service/TrackerService.java
@@ -1,27 +1,40 @@
 package com.pt.service;
 
+import com.pt.constant.Constants;
+import com.pt.entity.PeerInfoEntity;
 import com.pt.entity.TorrentMeta;
+import com.pt.entity.User;
+import com.pt.repository.PeerInfoRepository;
 import com.pt.repository.TorrentMetaRepository;
+import com.pt.repository.UserRepository;
 import com.pt.utils.BencodeCodec;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
+import java.io.ByteArrayOutputStream;
 import java.util.*;
-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) {
+    @Autowired
+    private PeerInfoRepository peerInfoEntityRepository;
+
+    @Autowired
+    private TorrentMetaService torrentMetaService;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Transactional
+    public byte[] handleAnnounce(Map<String, Object> params, String ipAddress, String event) {
+
+        System.out.println("TrackerService------------------------handle announce");
+
         try {
             if (!params.containsKey("info_hash") || !params.containsKey("peer_id") || !params.containsKey("port")) {
                 return BencodeCodec.encode(Map.of("failure reason", "Missing required parameters"));
@@ -30,71 +43,300 @@
             System.out.println("Received announce params: " + params);
             System.out.println("Client IP: " + ipAddress);
 
-            // 用ISO-8859-1解码,确保二进制数据正确还原
-            String infoHash = decodeParam(params.get("info_hash")[0]);
-            System.out.println("Decoded info_hash (raw bytes as hex): " + bytesToHex(infoHash.getBytes("ISO-8859-1")));
-
-            Optional<TorrentMeta> meta = torrentMetaRepository.findByInfoHash(infoHash);
-            if (!meta.isPresent()) {
-                System.out.println("Invalid info_hash: not found in DB");
-                return BencodeCodec.encode(Map.of("failure reason", "Invalid info_hash"));
+            String username = (String) params.get("passkey");
+            User user = null;
+            if(username != null){
+                user = userRepository.findByUsername(username);
+                if (user == null) {
+                    System.out.println("User not found: " + username);
+                    return BencodeCodec.encode(Map.of("failure reason", "User not found"));
+                }
             }
 
-            String peerId = decodeParam(params.get("peer_id")[0]);
-            System.out.println("Decoded peer_id: " + peerId);
+            int compact = params.containsKey("compact") ? (int) params.get("compact") : 1;
 
-            int port = Integer.parseInt(params.get("port")[0]);
-            System.out.println("Port: " + port);
+            System.out.println("left" + (long)params.get("left"));
+            String infoHash = (String)params.get("info_hash");
 
-            PeerInfo peer = new PeerInfo(ipAddress, port, peerId);
+            switch(event){
+                case "started":
+                    String status = (long)params.get("left") == (long)0 ? "seeding" : "downloading"; // 默认状态为下载中
+                    System.out.println("Event: started");
+                    Optional<TorrentMeta> meta = torrentMetaRepository.findByInfoHash(infoHash);
 
-            torrentPeers.computeIfAbsent(infoHash, k -> new CopyOnWriteArrayList<>());
-            List<PeerInfo> peers = torrentPeers.get(infoHash);
+                    if(status.equals("seeding")) {
+                        if(meta.isEmpty()){
+                            torrentMetaService.save(infoHash, "", 123456789L);
+                        }
 
-            boolean exists = peers.stream().anyMatch(p -> p.peerId.equals(peerId));
-            if (!exists) {
-                peers.add(peer);
-                System.out.println("Added new peer: " + peerId);
-            } else {
-                System.out.println("Peer already exists: " + peerId);
+                        String peerId = (String) params.get("peer_id");
+                        System.out.println("Decoded peer_id: " + peerId);
+                        int port = (int) params.get("port");
+                        System.out.println("Port: " + port);
+
+                        if(peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).isEmpty()) {
+
+                            PeerInfoEntity peer = new PeerInfoEntity(ipAddress, port, peerId);
+                            peer.setInfoHash(infoHash);
+                            peer.setStatus(status);
+                            peer.setIsActive(1); // 默认活跃状态
+                            peer.setUploaded(0);
+                            peer.setDownloaded(0);
+                            peer.setPeerId((String) params.get("peer_id"));
+                            peerInfoEntityRepository.save(peer);
+
+                        }
+                        else {
+                            System.out.println("Peer already exists for info_hash: " + infoHash);
+                            peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).get(0).setStatus("seeding");
+                        }
+
+                        // 返回成功响应
+                        Map<String, Object> response = new HashMap<>();
+                        response.put("interval", 1800); // 客户端应该多久再次请求
+                        response.put("min interval", 900); // 最小请求间隔
+                        response.put("complete", peerInfoEntityRepository.findByInfoHash(infoHash).size()); // 种子数
+                        response.put("incomplete", peerInfoEntityRepository.findDownloadingPeersByInfoHash(infoHash).size()); // 下载者数
+
+                        // 紧凑格式 - 返回当前种子的信息
+                        if(compact == 1) {
+                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                            try {
+                                // 转换IP地址
+                                String[] ipParts = ipAddress.split("\\.");
+                                for(String part : ipParts) {
+                                    baos.write(Integer.parseInt(part));
+                                }
+                                // 转换端口(大端序)
+                                baos.write((port >> 8) & 0xFF);
+                                baos.write(port & 0xFF);
+                            } catch(Exception e) {
+                                System.out.println("Error encoding peer info: " + e.getMessage());
+                            }
+                            response.put("peers", baos.toByteArray());
+                        } else {
+                            // 非紧凑格式
+                            List<Map<String, Object>> peerList = new ArrayList<>();
+                            Map<String, Object> peerMap = new HashMap<>();
+                            peerMap.put("peer id", peerId);
+                            peerMap.put("ip", ipAddress);
+                            peerMap.put("port", port);
+                            peerList.add(peerMap);
+                            response.put("peers", peerList);
+                        }
+
+                        return BencodeCodec.encode(response);
+
+                    }
+
+                    if(status.equals("downloading")) {
+                        System.out.println("Torrent is being downloaded, checking for existing peers...");
+
+                        if(user.getDownloaded() > Constants.DOWNLOAD_EXEMPTION_BYTES){
+                            if(user.getShareRatio() < Constants.MIN_SHARE_RATIO_THRESHOLD) {
+                                return BencodeCodec.encode(Map.of("failure reason", "Share ratio too low"));
+                            }
+                        }
+
+                        List<PeerInfoEntity> peers = peerInfoEntityRepository.findSeedingPeersByInfoHash(infoHash);
+
+                        for(PeerInfoEntity peer : peers) {
+                            System.out.println("Peer: " + peer.getPeerId() + ", IP: " + peer.getIp() + ", Port: " + peer.getPort());
+                        }
+
+                        String peerId = (String)params.get("peer_id");
+                        System.out.println("Decoded peer_id: " + peerId);
+                        int port = (int) params.get("port");
+                        System.out.println("Port: " + port);
+                        if(peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).isEmpty()) {
+                            PeerInfoEntity peer = new PeerInfoEntity(ipAddress, port, peerId);
+                            peer.setInfoHash(infoHash);
+                            peer.setStatus(status);
+                            peer.setIsActive(1); // 默认活跃状态
+                            peer.setUploaded(0);
+                            peer.setDownloaded(0);
+                            peer.setPeerId((String) params.get("peer_id"));
+                            peer.setLeft((long)params.get("left"));
+                            peerInfoEntityRepository.save(peer);
+                        }
+                        else {
+                            System.out.println("Peer already exists for info_hash: " + infoHash);
+                            peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).get(0).setStatus("seeding");
+                        }
+
+                        if (peers.isEmpty()) {
+                            return BencodeCodec.encode(Map.of("failure reason", "Torrent is not being seeded yet"));
+                        }
+
+                        System.out.println("solve download, compact = " + compact);
+
+                        // 构建正确的响应
+                        Map<String, Object> response = new HashMap<>();
+                        // 添加基本信息
+                        response.put("interval", 1800);
+                        // 客户端应该多久再次请求
+                        response.put("min interval", 900);
+                        // 最小请求间隔
+                        response.put("complete", peers.size());
+                        // 种子数response.put("incomplete", 0);
+                        // 下载者数(这里只返回种子)
+                        // 构建peers列表
+                        if (compact == 1) {
+                            // 紧凑格式 - 每个peer用6字节表示 (4字节IP + 2字节端口)
+                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                            for (PeerInfoEntity tmpPeer : peers) {
+                                try {
+                                    // 转换IP地址
+                                    String[] ipParts = tmpPeer.getIp().split("\\.");
+                                    for (String part : ipParts) {
+                                        baos.write(Integer.parseInt(part));
+                                    }
+                                    // 转换端口(大端序)
+                                    int tmpPeerPort = tmpPeer.getPort();
+                                    baos.write((tmpPeerPort >> 8) & 0xFF);
+                                    baos.write(tmpPeerPort & 0xFF);
+                                } catch (Exception e) {
+                                    System.out.println(e.getMessage());
+                                }
+                            }
+                            response.put("peers", baos.toByteArray());
+                            System.out.println(response);
+                        } else {
+                            // 非紧凑格式 - 每个peer是一个字典
+                            List<Map<String, Object>> peerList = new ArrayList<>();
+                            for (PeerInfoEntity tmpPeer : peers) {
+                                Map<String, Object> peerMap = new HashMap<>();
+                                peerMap.put("peer id", tmpPeer.getPeerId());
+                                peerMap.put("ip", tmpPeer.getIp());
+                                peerMap.put("port", tmpPeer.getPort());
+                                peerList.add(peerMap);
+                            }
+                            response.put("peers", peerList);
+                        }
+                        System.out.println(BencodeCodec.encode(response));
+
+                        return BencodeCodec.encode(response);
+                    }
+                    break;
+                case "stopped":
+                    System.out.println("Event: stopped");
+
+                    String peerId = (String) params.get("peer_id");
+                    PeerInfoEntity peer = peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, peerId).get(0);
+                    peerInfoEntityRepository.delete(peer); // 删除该peer信息
+
+                    if(peerInfoEntityRepository.findByInfoHash(infoHash).isEmpty()) {
+                        torrentMetaRepository.deleteByInfoHash(infoHash); // 如果没有其他peer,删除种子信息
+                    }
+
+                    // 停止事件,通常不需要返回数据
+                    Map<String, Object> response = new HashMap<>();
+                    // 添加基本信息
+                    response.put("interval", 1800);
+                    // 客户端应该多久再次请求
+                    response.put("min interval", 900);
+                    System.out.println("solve stop");
+
+                    return BencodeCodec.encode(response);
+                case "completed":
+                    System.out.println("Event: completed");
+
+                    PeerInfoEntity complete_peer = peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).get(0);
+
+                    Map<String, Object> complete_response = new HashMap<>();
+                    // 添加基本信息
+                    complete_response.put("interval", 1800);
+                    // 客户端应该多久再次请求
+                    complete_response.put("min interval", 900);
+
+                    complete_response.put("complete", peerInfoEntityRepository.findByInfoHash(infoHash).size()); // 种子数
+                    complete_response.put("incomplete", peerInfoEntityRepository.findDownloadingPeersByInfoHash(infoHash).size()); // 下载者数
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    for (PeerInfoEntity tmpPeer : peerInfoEntityRepository.findSeedingPeersByInfoHash(infoHash)) {
+                        try {
+                            // 转换IP地址
+                            String[] ipParts = tmpPeer.getIp().split("\\.");
+                            for (String part : ipParts) {
+                                baos.write(Integer.parseInt(part));
+                            }
+                            // 转换端口(大端序)
+                            int tmpPeerPort = tmpPeer.getPort();
+                            baos.write((tmpPeerPort >> 8) & 0xFF);
+                            baos.write(tmpPeerPort & 0xFF);
+                        } catch (Exception e) {
+                            System.out.println(e.getMessage());
+                        }
+                    }
+                    complete_response.put("peers", baos.toByteArray());
+                    System.out.println("solve complete");
+                    if(complete_peer.getStatus().equals("downloading")) {
+                        user.setDownloaded(user.getDownloaded() + (long)params.get("downloaded"));
+                        complete_peer.setStatus("seeding");
+                        peerInfoEntityRepository.save(complete_peer);
+                    }
+                    if(complete_peer.getStatus().equals("seeding")) {
+                        user.setUploaded(user.getUploaded() + (long)params.get("uploaded"));
+                    }
+
+                    user.setShareRatio(user.getUploaded() / (double) Math.max(user.getDownloaded(), 1));
+
+                    userRepository.save(user); // 保存用户信息
+
+                    return BencodeCodec.encode(complete_response);
+                default:
+                    System.out.println(event);
+                    System.out.println("Event: unknown or not specified");
+
+                    PeerInfoEntity other_peer = peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).get(0);
+
+                    Map<String, Object> other_response = new HashMap<>();
+
+                    // 添加基本信息
+                    other_response.put("interval", 1800);
+                    // 客户端应该多久再次请求
+                    other_response.put("min interval", 900);
+
+                    other_response.put("complete", peerInfoEntityRepository.findByInfoHash(infoHash).size()); // 种子数
+                    other_response.put("incomplete", peerInfoEntityRepository.findDownloadingPeersByInfoHash(infoHash).size()); // 下载者数
+
+                    ByteArrayOutputStream other_baos = new ByteArrayOutputStream();
+                    for (PeerInfoEntity tmpPeer : peerInfoEntityRepository.findSeedingPeersByInfoHash(infoHash)) {
+                        try {
+                            // 转换IP地址
+                            String[] ipParts = tmpPeer.getIp().split("\\.");
+                            for (String part : ipParts) {
+                                other_baos.write(Integer.parseInt(part));
+                            }
+                            // 转换端口(大端序)
+                            int tmpPeerPort = tmpPeer.getPort();
+                            other_baos.write((tmpPeerPort >> 8) & 0xFF);
+                            other_baos.write(tmpPeerPort & 0xFF);
+                        } catch (Exception e) {
+                            System.out.println(e.getMessage());
+                        }
+                    }
+                    other_response.put("peers", other_baos.toByteArray());
+                    if(other_peer.getStatus().equals("downloading")) {
+                        user.setDownloaded(user.getDownloaded() + (long)params.get("downloaded"));
+                    }
+                    if(other_peer.getStatus().equals("seeding")) {
+                        user.setUploaded(user.getUploaded() + (long)params.get("uploaded"));
+                    }
+
+                    user.setShareRatio(user.getUploaded() / (double) Math.max(user.getDownloaded(), 1));
+
+                    userRepository.save(user); // 保存用户信息
+                    return BencodeCodec.encode(other_response);
             }
 
-            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);
+            return BencodeCodec.encode(Map.of("failure reason", "Event not handled"));
         } catch (Exception e) {
             e.printStackTrace();  // 打印异常堆栈,方便定位错误
             return BencodeCodec.encode(Map.of("failure reason", "Internal server error"));
         }
     }
 
-    // 辅助函数:打印字节转成16进制字符串
-    private String bytesToHex(byte[] bytes) {
-        StringBuilder sb = new StringBuilder();
-        for (byte b : bytes) {
-            sb.append(String.format("%02x", b));
-        }
-        return sb.toString();
-    }
-
-    // decodeParam 建议用ISO-8859-1解码
-    private String decodeParam(String param) throws UnsupportedEncodingException {
-        return URLDecoder.decode(param, "ISO-8859-1");
-    }
 
 
-    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;
-        }
-    }
 }