修改Tracker服务器相关bug
Change-Id: Id3ec61034575bd794724be98f832f8c065448b92
diff --git a/src/main/java/com/pt/controller/ResourceController.java b/src/main/java/com/pt/controller/ResourceController.java
index e405ef2..c663963 100644
--- a/src/main/java/com/pt/controller/ResourceController.java
+++ b/src/main/java/com/pt/controller/ResourceController.java
@@ -5,14 +5,21 @@
import com.pt.entity.User;
import com.pt.service.ResourceService;
import com.pt.service.UserService;
+import com.pt.utils.BencodeCodec;
import com.pt.utils.JWTUtils;
+import com.pt.utils.TorrentPasskeyModifier;
+import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
+import org.springframework.mock.web.MockMultipartFile;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -44,7 +51,11 @@
if (resources.isEmpty()) {
return ResponseEntity.noContent().build();
}
- return ResponseEntity.ok(resources);
+ ans.put("message", "Resources found");
+ ans.put("data", Map.of(
+ "resources", resources
+ ));
+ return ResponseEntity.ok().body(ans);
}
@GetMapping("/list/user")
@@ -62,7 +73,11 @@
if (resources.isEmpty()) {
return ResponseEntity.noContent().build();
}
- return ResponseEntity.ok(resources);
+ ans.put("message", "User resources found");
+ ans.put("data", Map.of(
+ "resources", resources
+ ));
+ return ResponseEntity.ok().body(ans);
}
@PostMapping("/publish")
@@ -70,65 +85,74 @@
@RequestHeader("token") String token,
@RequestParam("username") String username,
@RequestParam("description") String description,
- @RequestParam("torrent") MultipartFile torrentFile) {
+ @RequestParam("torrent") MultipartFile torrentFile
+ )
+ {
Map<String, Object> ans = new HashMap<>();
if (!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
- ans.put("result", "Invalid token");
+ ans.put("message", "Invalid token");
return ResponseEntity.badRequest().body(ans);
}
User user = userService.findByUsername(username);
if (user == null || user.getLevel() < 2) {
- ans.put("result", "Insufficient permissions to publish resources");
+ ans.put("message", "Insufficient permissions to publish resources");
return ResponseEntity.status(403).body(ans);
}
try {
// 传入种子文件字节,同时传入资源其他信息
- System.out.println("name" + torrentFile.getOriginalFilename());
- resourceService.publishResource(torrentFile.getOriginalFilename(), description, username, torrentFile.getSize(), torrentFile.getBytes());
+ resourceService.publishResource(torrentFile.getOriginalFilename(), description, username, torrentFile.getBytes(), username);
} catch (Exception e) {
- ans.put("result", "Failed to publish resource: " + e.getMessage());
+ ans.put("message", "Failed to publish resource: " + e.getMessage());
return ResponseEntity.status(500).body(ans);
}
- ans.put("result", "Resource published successfully");
+ ans.put("message", "Resource published successfully");
return ResponseEntity.ok(ans);
}
-
-
-
@GetMapping("/get/{resourceId}")
public ResponseEntity<?> getResourceById(@PathVariable("resourceId") int resourceId,
-// @RequestHeader("token") String token,
+ @RequestHeader("token") String token,
@RequestParam("username") 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);
-// }
+ if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
+ ans.put("message", "Invalid token");
+ return ResponseEntity.badRequest().body(ans);
+ }
Resource resource = resourceService.getResourceById(resourceId);
if (resource == null) {
- return ResponseEntity.notFound().build();
+ ans.put("message", "Resource not found");
+ return ResponseEntity.badRequest().body(ans);
}
- return ResponseEntity.ok(resource);
+
+ ans.put("message", "Resource found");
+ ans.put("data", Map.of(
+ "resourceId", resource.getResourceId(),
+ "name", resource.getName(),
+ "description", resource.getDescription(),
+ "author", resource.getAuthor(),
+ "publishTime", resource.getPublishTime()
+ ));
+
+ return ResponseEntity.ok().body(ans);
}
@GetMapping("/download/{resourceId}")
public ResponseEntity<?> downloadResource(@PathVariable("resourceId") int resourceId,
-// @RequestHeader("token") String token,
+ @RequestHeader("token") String token,
@RequestParam("username") String username) throws IOException {
Map<String, Object> ans = new HashMap<>();
-// if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
-// ans.put("message", "Invalid token");
-// return ResponseEntity.badRequest().body(ans);
-// }
+ 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) {
@@ -136,20 +160,17 @@
return ResponseEntity.status(404).body(ans);
}
- final double MIN_SHARE_RATIO_THRESHOLD = 0.5; // 最低共享率要求
- final long DOWNLOAD_EXEMPTION_BYTES = 20L * 1024L * 1024L * 1024L; // 20GB下载量豁免
-
long uploaded = user.getUploaded();
long downloaded = user.getDownloaded();
// 如果用户的下载量超过豁免值,则检查其共享率
- if (downloaded > DOWNLOAD_EXEMPTION_BYTES) {
+ if (downloaded > Constants.DOWNLOAD_EXEMPTION_BYTES) {
// 防止除以零
double shareRatio = (downloaded == 0) ? Double.MAX_VALUE : (double) uploaded / downloaded;
- if (shareRatio < MIN_SHARE_RATIO_THRESHOLD) {
+ if (shareRatio < Constants.MIN_SHARE_RATIO_THRESHOLD) {
ans.put("message", "Share ratio is too low. Please seed more to improve your ratio before downloading new resources.");
ans.put("current_share_ratio", String.format("%.2f", shareRatio));
- ans.put("required_share_ratio", MIN_SHARE_RATIO_THRESHOLD);
+ ans.put("required_share_ratio", Constants.MIN_SHARE_RATIO_THRESHOLD);
return ResponseEntity.status(403).body(ans); // 403 Forbidden
}
}
@@ -160,10 +181,12 @@
return ResponseEntity.notFound().build();
}
+ TorrentPasskeyModifier modifier = new TorrentPasskeyModifier();
+
return ResponseEntity.ok()
.header("Content-Type", "application/x-bittorrent")
.header("Content-Disposition", "attachment; filename=\"" + resource.getName() + ".torrent\"")
- .body(file);
+ .body(modifier.analyzeTorrentFile(file, username)); // 返回修改后的 torrent 文件
}
@GetMapping("/search")
@@ -181,17 +204,23 @@
if (resources.isEmpty()) {
return ResponseEntity.noContent().build();
}
+
+ ans.put("message", "Search results found");
+ ans.put("data", Map.of(
+ "resources", resources
+ ));
return ResponseEntity.ok(resources);
}
- @GetMapping("/delete")
+ @DeleteMapping("/delete")
public ResponseEntity<?> deleteResource(@RequestHeader("token") String token,
- @RequestParam("username") String username,
- @RequestParam("resourceId") int resourceId) {
+ @RequestBody Map<String, Object> requestBody) {
+ String username = (String) requestBody.get("username");
+ Integer resourceId = (Integer) requestBody.get("resourceId");
Map<String, Object> ans = new HashMap<>();
Resource resource = resourceService.getResourceById(resourceId);
- if(!JWTUtils.checkToken(token, username, Constants.UserRole.ADMIN) || resource == null || !resource.getAuthor().equals(username)) {
+ if(!JWTUtils.checkToken(token, username, Constants.UserRole.ADMIN) || resource == null) {
ans.put("message", "Invalid token or insufficient permissions");
return ResponseEntity.badRequest().body(ans);
}
@@ -206,5 +235,4 @@
ans.put("message", "Resource deleted 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 f2a75e3..b670f3f 100644
--- a/src/main/java/com/pt/controller/TrackerController.java
+++ b/src/main/java/com/pt/controller/TrackerController.java
@@ -1,12 +1,17 @@
package com.pt.controller;
+import com.pt.service.TorrentMetaService;
import com.pt.service.TrackerService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
@@ -18,36 +23,79 @@
@Autowired
private TrackerService trackerService;
+ @Autowired
+ private TorrentMetaService torrentMetaService;
+
// tracker相应bt客户端的announce请求
- @PostMapping("/announce")
- public void announceByPost(
- @RequestBody Map<String, String> body,
+ @GetMapping("/announce")
+ public void announce(
+ @RequestParam(value = "passkey", required = false) String passkey,
+ @RequestParam(value = "info_hash") String encodedInfoHash,
+ @RequestParam(value = "peer_id") String encodedPeerId,
+ @RequestParam(value = "port") int port,
+ @RequestParam(value = "uploaded") long uploaded,
+ @RequestParam(value = "downloaded") long downloaded,
+ @RequestParam(value = "left") long left,
+ @RequestParam(value = "event", defaultValue = "") String event,
+ @RequestParam(value = "compact", defaultValue = "1") int compact,
+ @RequestParam(value = "numwant", defaultValue = "50") int numwant,
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
try {
- String infoHash = body.get("info_hash");
- String peerId = body.get("peer_id");
- int port = Integer.parseInt(body.get("port"));
+ System.out.println("TrackerController------------------------announce");
+ // 解码 info_hash 和 peer_id(从URL编码的字符串转为字节数组)
+ System.out.println("TrackerController------------------------announce: info_hash=" + encodedInfoHash + ", peer_id=" + encodedPeerId);
+ String decodedInfoHash = URLDecoder.decode(encodedInfoHash, StandardCharsets.ISO_8859_1);
+ String decodedPeerId = URLDecoder.decode(encodedPeerId, StandardCharsets.ISO_8859_1);
+ // 转换为字节数组
+ byte[] infoHashBytes = decodedInfoHash.getBytes(StandardCharsets.ISO_8859_1);
+ byte[] peerIdBytes = decodedPeerId.getBytes(StandardCharsets.ISO_8859_1);
+
+ // 验证 info_hash 长度
+// if (infoHashBytes.length != 20) {
+// throw new IllegalArgumentException("Invalid info_hash length");
+// }
+
+ // 获取客户端IP
String ip = request.getRemoteAddr();
+ System.out.println("Client IP: " + ip);
- // 将参数封装为 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);
+ // 将参数封装为 Map 传给服务层
+ Map<String, Object> params = new HashMap<>();
+ params.put("info_hash", decodedInfoHash);
+ params.put("peer_id", decodedPeerId);
+ params.put("port", port);
+ params.put("uploaded", uploaded);
+ params.put("downloaded", downloaded);
+ params.put("left", left);
+ params.put("event", event);
+ params.put("compact", compact);
+ params.put("numwant", numwant);
+ params.put("ip", ip);
+ params.put("passkey", passkey);
+ byte[] bencodedResponse = trackerService.handleAnnounce(params, ip, event);
response.setContentType("application/x-bittorrent");
response.getOutputStream().write(bencodedResponse);
+
+ } catch (IllegalArgumentException e) {
+ System.out.println("TrackerService-----------------------Error processing announce request111: " + e.getMessage());
+ e.printStackTrace();
+ String errorResponse = "d14:failure reason" + e.getMessage().length() + ":" + e.getMessage() + "e";
+ response.setContentType("application/x-bittorrent");
+ response.getOutputStream().write(errorResponse.getBytes(StandardCharsets.ISO_8859_1));
} catch (Exception e) {
- response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- response.setContentType("text/plain");
- response.getWriter().write("Tracker internal error: " + e.getMessage());
+ e.printStackTrace();
+ System.out.println("TrackerService-----------------------Error processing announce request222: " + e.getMessage());
+ String errorResponse = "d14:failure reason20:Internal server errore";
+ response.setContentType("application/x-bittorrent");
+ response.getOutputStream().write(errorResponse.getBytes(StandardCharsets.ISO_8859_1));
}
}
+
}