完成Tracker.java接口开发,update path

Change-Id: I8b1096af3aa3c7ebdf623905c5d47cfe72b86da2
diff --git a/src/main/java/entity/SeedDownload.java b/src/main/java/entity/SeedDownload.java
new file mode 100644
index 0000000..caafda8
--- /dev/null
+++ b/src/main/java/entity/SeedDownload.java
@@ -0,0 +1,119 @@
+package entity;
+
+import java.time.LocalDateTime;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "SeedDownload")
+public class SeedDownload {
+
+    @Id
+    @Column(name = "task_id", length = 64, nullable = false)
+    public String taskId;
+
+    @Column(name = "user_id", length = 36, nullable = false)
+    public String userId;
+
+    @Column(name = "seed_id", length = 64, nullable = false)
+    public String seedId;
+
+    @Column(name = "download_start", nullable = false)
+    public LocalDateTime downloadStart;
+
+    @Column(name = "download_end")
+    public LocalDateTime downloadEnd;
+
+    @Column(name = "is_dedicated", nullable = false)
+    public boolean isDedicated;
+
+    @Column(name = "client_ip", length = 45)
+    public String clientIp;
+
+    // Constructors
+    public SeedDownload() {}
+
+    public SeedDownload(String taskId, String userId, String seedId, LocalDateTime downloadStart, LocalDateTime downloadEnd, boolean isDedicated, String clientIp) {
+        this.taskId = taskId;
+        this.userId = userId;
+        this.seedId = seedId;
+        this.downloadStart = downloadStart;
+        this.downloadEnd = downloadEnd;
+        this.isDedicated = isDedicated;
+        this.clientIp = clientIp;
+    }
+
+    // Getters and Setters
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getSeedId() {
+        return seedId;
+    }
+
+    public void setSeedId(String seedId) {
+        this.seedId = seedId;
+    }
+
+    public LocalDateTime getDownloadStart() {
+        return downloadStart;
+    }
+
+    public void setDownloadStart(LocalDateTime downloadStart) {
+        this.downloadStart = downloadStart;
+    }
+
+    public LocalDateTime getDownloadEnd() {
+        return downloadEnd;
+    }
+
+    public void setDownloadEnd(LocalDateTime downloadEnd) {
+        this.downloadEnd = downloadEnd;
+    }
+
+    public boolean isDedicated() {
+        return isDedicated;
+    }
+
+    public void setDedicated(boolean dedicated) {
+        isDedicated = dedicated;
+    }
+
+    public String getClientIp() {
+        return clientIp;
+    }
+
+    public void setClientIp(String clientIp) {
+        this.clientIp = clientIp;
+    }
+
+    // equals and hashCode based on taskId
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SeedDownload)) return false;
+        SeedDownload that = (SeedDownload) o;
+        return taskId != null && taskId.equals(that.taskId);
+    }
+
+    @Override
+    public int hashCode() {
+        return 31 + (taskId != null ? taskId.hashCode() : 0);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/entity/config.java b/src/main/java/entity/config.java
index 0cf39c1..71f3b4f 100644
--- a/src/main/java/entity/config.java
+++ b/src/main/java/entity/config.java
@@ -1,14 +1,15 @@
 package entity;
 
 public class config {
-    public String TrackerURL;
-    public int FarmNumber;
-    public int FakeTime;
-    public int BegVote;
+    public static final String TrackerURL="";
+    public static final int FarmNumber=3;
+    public static final int FakeTime=3;
+    public static final int BegVote=3;
     // 请根据实际环境修改为可达的地址
-    public String SqlURL = "192.168.5.9:3306";
-    public String Database = "pt_database";
-    public String TestDatabase = "pt_database_test";
-    public String SqlPassword = "123456";
-    public String SqlUsername = "root";
+    public static final String SqlURL = "192.168.5.9:3306";
+    public static final String Database = "pt_database";
+    public static final String TestDatabase = "pt_database_test";
+    public static final String SqlPassword = "123456";
+    public static final String SqlUsername = "root";
+    public static final String TORRENT_STORAGE_DIR = "torrents";
 }
diff --git a/src/main/java/tracker/Tracker.java b/src/main/java/tracker/Tracker.java
index 6334ebb..210b9bf 100644
--- a/src/main/java/tracker/Tracker.java
+++ b/src/main/java/tracker/Tracker.java
@@ -1,20 +1,24 @@
 package tracker;
 
 import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
 import java.util.HashMap;
 import java.util.Map;
-
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.EntityTransaction;
 import javax.persistence.Persistence;
-
 import com.querydsl.jpa.impl.JPAUpdateClause;
-
 import entity.QUserPT;
-import entity.TTorent;
+import entity.Seed;
+import entity.SeedDownload;
 import entity.TransRecord;
 import entity.config;
+import entity.TTorent;
+import java.time.LocalDateTime;
 
 public class Tracker implements TrackerInterface {
     private final EntityManagerFactory emf;
@@ -163,17 +167,69 @@
         }
     }
 
+    @Override
+    public int SaveTorrent(String seedid, File TTorent){
+        try {
+            Path storageDir = Paths.get(config.TORRENT_STORAGE_DIR);
+            if (!Files.exists(storageDir)) {
+                Files.createDirectories(storageDir);
+            }
+            String filename = TTorent.getName();
+            Path target = storageDir.resolve(seedid + "_" + filename);
+            Files.copy(TTorent.toPath(), target, StandardCopyOption.REPLACE_EXISTING);
+
+            EntityManager em = emf.createEntityManager();
+            EntityTransaction tx = em.getTransaction();
+            try {
+                tx.begin();
+                Seed seed = em.find(Seed.class, seedid);
+                seed.url = target.toString();
+                em.merge(seed);
+                tx.commit();
+                return 0;
+            } catch (Exception e) {
+                if (tx.isActive()) tx.rollback();
+                return 1;
+            } finally {
+                em.close();
+            }
+        } catch (Exception e) {
+            return 1;
+        }
+    }
 
     @Override
-    public int SaveTorrent(File TTorent){
-        return 0;
-    };//保存seedid对应的ttorent信息
-
-    @Override
-    public File GetTTorent(String seedid,String userid){
-        return null;
-    };//根据种子id获得ttorent信息然后构建Ttorent文件并返回,同时记录用户的下载行为
-
+    public File GetTTorent(String seedid, String userid, String ip) {
+        EntityManager em = emf.createEntityManager();
+        EntityTransaction tx = em.getTransaction();
+        File file = null;
+        try {
+            Seed seed = em.find(Seed.class, seedid);
+            if (seed == null || seed.url == null) {
+                return null;
+            }
+            file = new File(seed.url);
+            if (!file.exists()) {
+                return null;
+            }
+            tx.begin();
+            SeedDownload sd = new SeedDownload();
+            sd.seedId = seedid;
+            sd.userId = userid;
+            sd.clientIp = ip;
+            LocalDateTime now = LocalDateTime.now();
+            sd.downloadStart = now;
+            sd.downloadEnd = now;
+            em.persist(sd);
+            tx.commit();
+        } catch (Exception e) {
+            if (tx.isActive()) tx.rollback();
+            // ignore persistence errors and still return the file
+        } finally {
+            em.close();
+        }
+        return file;
+    }
 
     @Override
     public int AddRecord(TransRecord rd){
diff --git a/src/main/java/tracker/TrackerInterface.java b/src/main/java/tracker/TrackerInterface.java
index 1496a26..4776d11 100644
--- a/src/main/java/tracker/TrackerInterface.java
+++ b/src/main/java/tracker/TrackerInterface.java
@@ -11,8 +11,8 @@
     public boolean AddMagic(String userid,int magic);//给用户增加魔力值,返回0成功,返回1失败;
     public boolean ReduceMagic(String userid,int magic);//给用户减少魔力值,返回0成功,返回1失败;
 
-    public int SaveTorrent(File TTorent);//保存seedid对应的ttorent信息
-    public File GetTTorent(String seedid,String userid);//根据种子id获得ttorent信息然后构建Ttorent文件并返回,同时记录用户的下载行为
+    public int SaveTorrent(String seedid,File TTorent);//保存seedid对应的ttorent信息
+    public File GetTTorent(String seedid,String userid,String ip);//根据种子id获得ttorent信息然后构建Ttorent文件并返回,同时记录用户的下载行为
     
     public int AddRecord(TransRecord rd);//新增一个seedid对应的种子的传输任务记录
 }
\ No newline at end of file
diff --git a/src/test/java/databasetest/DataManagerTest.java b/src/test/java/databasetest/DataManagerTest.java
new file mode 100644
index 0000000..1256240
--- /dev/null
+++ b/src/test/java/databasetest/DataManagerTest.java
@@ -0,0 +1,5 @@
+package databasetest;
+
+public class DataManagerTest {
+    
+}
diff --git a/src/test/java/trackertest/TrackerTest.java b/src/test/java/trackertest/TrackerTest.java
index 3c4898b..104f017 100644
--- a/src/test/java/trackertest/TrackerTest.java
+++ b/src/test/java/trackertest/TrackerTest.java
@@ -1,4 +1,6 @@
 package trackertest;
+
+import java.io.File;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -19,6 +21,7 @@
 import org.junit.jupiter.api.DynamicTest;
 import org.junit.jupiter.api.TestFactory;
 
+import entity.Seed;
 import entity.TransRecord;
 import entity.TransportId;
 import entity.config;
@@ -66,6 +69,19 @@
 
     @AfterAll
     static void teardown() {
+        // 清理:删除测试过程中保存的所有 torrent 文件
+        File storageDir = new File(config.TORRENT_STORAGE_DIR);
+        if (storageDir.exists() && storageDir.isDirectory()) {
+            File[] files = storageDir.listFiles();
+            if (files != null) {
+                for (File f : files) {
+                    if (f.isFile()) {
+                        f.delete();
+                    }
+                }
+            }
+        }
+
         if (em != null && em.isOpen()) em.close();
         if (emf != null && emf.isOpen()) emf.close();
     }
@@ -298,4 +314,80 @@
             }))
             .collect(Collectors.toList());
     }
+
+    @TestFactory
+    Collection<DynamicTest> testSaveTorrent() {
+        List<String> seedIds = em.createQuery(
+            "select s.seedid from Seed s", String.class
+        ).getResultList();
+        return seedIds.stream()
+            .map(sid -> DynamicTest.dynamicTest("SaveTorrent for seed " + sid, () -> {
+                // 准备一个临时空文件
+                File temp = File.createTempFile(sid + "_test", ".torrent");
+                // 调用 SaveTorrent
+                int ret = tracker.SaveTorrent(sid, temp);
+                Assertions.assertEquals(0, ret, "SaveTorrent 应返回 0");
+
+                // 验证文件已按约定存储
+                File stored = new File(config.TORRENT_STORAGE_DIR,
+                                       sid + "_" + temp.getName());
+                Assertions.assertTrue(stored.exists(), "存储文件应存在");
+
+                // 验证数据库中 url 字段已更新
+                em.clear();
+                Seed seed = em.find(Seed.class, sid);
+                // 将 seed.url 转为 File 再取绝对路径进行比较
+                Assertions.assertEquals(
+                    stored.getAbsolutePath(),
+                    new File(seed.url).getAbsolutePath(),
+                    "Seed.url 应更新为存储路径"
+                );
+
+                // 清理测试文件
+                stored.delete();
+                temp.delete();
+            }))
+            .collect(Collectors.toList());
+    }
+
+    @TestFactory
+    Collection<DynamicTest> testGetTTorent() {
+        // 拿到所有 seedid
+        List<String> seedIds = em.createQuery(
+            "select s.seedid from Seed s", String.class
+        ).getResultList();
+        return seedIds.stream()
+            .map(sid -> DynamicTest.dynamicTest("GetTTorent for seed " + sid, () -> {
+                // 准备一个临时空文件并 SaveTorrent
+                File temp = File.createTempFile(sid + "_test", ".torrent");
+                int saveRet = tracker.SaveTorrent(sid, temp);
+                Assertions.assertEquals(0, saveRet, "SaveTorrent 应返回 0");
+
+                // 刷新上下文并取回更新后的 seed 实体
+                em.clear();
+                Seed seed = em.find(Seed.class, sid);
+                Assertions.assertNotNull(seed.url, "Seed.url 应已被更新");
+
+                // 调用 GetTTorent 并断言路径一致
+                String uid = userIds.get(0), ip = "127.0.0.1";
+                File ret = tracker.GetTTorent(sid, uid, ip);
+                File expected = new File(seed.url);
+                Assertions.assertNotNull(ret, "应返回文件对象");
+                Assertions.assertEquals(
+                    expected.getAbsolutePath(),
+                    ret.getAbsolutePath(),
+                    "返回文件路径应与Seed.url一致"
+                );
+
+                // 清理:删掉本地文件,回滚 DB url 字段,删掉 temp
+                expected.delete();
+                EntityTransaction tx = em.getTransaction();
+                tx.begin();
+                seed.url = null;
+                em.merge(seed);
+                tx.commit();
+                temp.delete();
+            }))
+            .collect(Collectors.toList());
+    }
 }