Merge "添加更新用户流量的方法,并定时跟新到所有用户"

Change-Id: I558ee7de6767ed1b78685883310a268ea51b198a
diff --git a/src/main/java/com/pt/controller/ResourceController.java b/src/main/java/com/pt/controller/ResourceController.java
index 306851a..2f75af6 100644
--- a/src/main/java/com/pt/controller/ResourceController.java
+++ b/src/main/java/com/pt/controller/ResourceController.java
@@ -77,13 +77,13 @@
         Map<String, Object> ans = new HashMap<>();
 
         if (!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
-            ans.put("message", "Invalid token");
+            ans.put("result", "Invalid token");
             return ResponseEntity.badRequest().body(ans);
         }
 
         User user = userService.findByUsername(username);
         if (user == null || user.getLevel() < 2) {
-            ans.put("message", "Insufficient permissions to publish resources");
+            ans.put("result", "Insufficient permissions to publish resources");
             return ResponseEntity.status(403).body(ans);
         }
 
@@ -91,11 +91,11 @@
             // 传入种子文件字节,同时传入资源其他信息
             resourceService.publishResource(name, description, username, size, torrentFile.getBytes());
         } catch (Exception e) {
-            ans.put("message", "Failed to publish resource: " + e.getMessage());
+            ans.put("result", "Failed to publish resource: " + e.getMessage());
             return ResponseEntity.status(500).body(ans);
         }
 
-        ans.put("message", "Resource published successfully");
+        ans.put("result", "Resource published successfully");
         return ResponseEntity.ok(ans);
     }
 
diff --git a/src/main/java/com/pt/controller/TrackerController.java b/src/main/java/com/pt/controller/TrackerController.java
index edae09f..56c0867 100644
--- a/src/main/java/com/pt/controller/TrackerController.java
+++ b/src/main/java/com/pt/controller/TrackerController.java
@@ -7,22 +7,34 @@
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.Map;
 
 @RestController
-@CrossOrigin(origins = "*")
 @RequestMapping("/api/tracker")
+@CrossOrigin(origins = "*")
 public class TrackerController {
 
     @Autowired
     private TrackerService trackerService;
 
-    @GetMapping("/announce")
-    public void announce(HttpServletRequest request, HttpServletResponse response) throws IOException {
+    // tracker相应bt客户端的announce请求
+    @PostMapping("/announce")
+    public void announceByPost(
+            @RequestParam("info_hash") String infoHash,
+            @RequestParam("peer_id") String peerId,
+            @RequestParam("port") int port,
+            HttpServletRequest request,
+            HttpServletResponse response
+    ) throws IOException {
         try {
             String ip = request.getRemoteAddr();
-            Map<String, String[]> params = request.getParameterMap();
 
+            // 将参数封装为 Map 传给服务层(也可以直接传对象)
+            Map<String, String[]> params = new HashMap<>();
+            params.put("info_hash", new String[]{infoHash});
+            params.put("peer_id", new String[]{peerId});
+            params.put("port", new String[]{String.valueOf(port)});
             byte[] bencodedResponse = trackerService.handleAnnounce(params, ip);
 
             response.setContentType("application/x-bittorrent");
diff --git a/src/main/java/com/pt/controller/UserController.java b/src/main/java/com/pt/controller/UserController.java
index 3bb05c5..d9f53ab 100644
--- a/src/main/java/com/pt/controller/UserController.java
+++ b/src/main/java/com/pt/controller/UserController.java
@@ -227,4 +227,63 @@
             return ResponseEntity.badRequest().body(ans);
         }
     }
+
+    /**
+     * 获取用户统计信息
+     */
+    @GetMapping("/stats/{username}")
+    public ResponseEntity<?> getUserStats(
+            @RequestHeader("token") String token,
+            @PathVariable String username) {
+        
+        Map<String, Object> ans = new HashMap<>();
+        
+        if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
+            ans.put("message", "Invalid token");
+            return ResponseEntity.badRequest().body(ans);
+        }
+
+        User user = userService.findByUsername(username);
+        if (user == null) {
+            ans.put("message", "User not found");
+            return ResponseEntity.badRequest().body(ans);
+        }
+
+        // 计算分享率
+        double ratio = user.getDownloaded() == 0 ? 
+            (user.getUploaded() > 0 ? Double.MAX_VALUE : 0) : 
+            (double) user.getUploaded() / user.getDownloaded();
+        
+        // 格式化分享率为两位小数
+        ratio = Math.round(ratio * 100.0) / 100.0;
+
+        // 构建返回数据
+        Map<String, Object> stats = new HashMap<>();
+        double uploadSize = user.getUploaded() / (1024.0 * 1024.0 * 1024.0);
+        double downloadSize = user.getDownloaded() / (1024.0 * 1024.0 * 1024.0);
+        
+        stats.put("uploadSize", uploadSize); // 转换为GB
+        stats.put("downloadSize", downloadSize); // 转换为GB
+        stats.put("ratio", ratio);
+        stats.put("points", user.getPoints());
+        stats.put("userClass", getUserClass(user.getLevel()));
+        stats.put("level", user.getLevel());
+
+        ans.put("message", "User stats retrieved successfully");
+        ans.put("data", stats);
+        return ResponseEntity.ok(ans);
+    }
+
+    /**
+     * 根据用户等级返回对应的用户类别名称
+     */
+    private String getUserClass(int level) {
+        switch (level) {
+            case 5: return "大佬";
+            case 4: return "专家";
+            case 3: return "熟练";
+            case 2: return "入门";
+            default: return "新用户";
+        }
+    }
 }