| package com.pt.controller; |
| |
| import com.pt.constant.Constants; |
| import com.pt.entity.Resource; |
| 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; |
| import java.io.File; |
| |
| @RestController |
| @RequestMapping("/api/resource") |
| @CrossOrigin(origins = "*") |
| public class ResourceController { |
| |
| @Autowired |
| private ResourceService resourceService; |
| |
| @Autowired |
| private UserService userService; |
| |
| @GetMapping("/list/all") |
| public ResponseEntity<?> getAllResources(@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); |
| } |
| |
| List<Resource> resources = resourceService.getAllResources(); |
| if (resources.isEmpty()) { |
| return ResponseEntity.noContent().build(); |
| } |
| ans.put("message", "Resources found"); |
| ans.put("data", Map.of( |
| "resources", resources |
| )); |
| return ResponseEntity.ok().body(ans); |
| } |
| |
| @GetMapping("/list/user") |
| public ResponseEntity<?> getUserResources(@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); |
| } |
| |
| List<Resource> resources = resourceService.getResourcesByAuthor(username); |
| if (resources.isEmpty()) { |
| return ResponseEntity.noContent().build(); |
| } |
| ans.put("message", "User resources found"); |
| ans.put("data", Map.of( |
| "resources", resources |
| )); |
| return ResponseEntity.ok().body(ans); |
| } |
| |
| @PostMapping("/publish") |
| public ResponseEntity<?> publishResource( |
| @RequestHeader("token") String token, |
| @RequestParam("username") String username, |
| @RequestParam("description") String description, |
| @RequestParam("torrent") MultipartFile torrentFile |
| ) |
| { |
| |
| 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 || user.getLevel() < 2) { |
| ans.put("message", "Insufficient permissions to publish resources"); |
| return ResponseEntity.status(403).body(ans); |
| } |
| |
| try { |
| // 传入种子文件字节,同时传入资源其他信息 |
| resourceService.publishResource(torrentFile.getOriginalFilename(), description, username, torrentFile.getBytes(), username); |
| } catch (Exception e) { |
| ans.put("message", "Failed to publish resource: " + e.getMessage()); |
| return ResponseEntity.status(500).body(ans); |
| } |
| |
| ans.put("message", "Resource published successfully"); |
| return ResponseEntity.ok(ans); |
| } |
| |
| @GetMapping("/get/{resourceId}") |
| public ResponseEntity<?> getResourceById(@PathVariable("resourceId") int resourceId, |
| @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); |
| } |
| |
| Resource resource = resourceService.getResourceById(resourceId); |
| if (resource == null) { |
| ans.put("message", "Resource not found"); |
| return ResponseEntity.badRequest().body(ans); |
| } |
| |
| 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, |
| @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); |
| } |
| |
| User user = userService.findByUsername(username); |
| if (user == null) { |
| ans.put("message", "User not found"); |
| return ResponseEntity.status(404).body(ans); |
| } |
| |
| long uploaded = user.getUploaded(); |
| long downloaded = user.getDownloaded(); |
| |
| // 如果用户的下载量超过豁免值,则检查其共享率 |
| if (downloaded > Constants.DOWNLOAD_EXEMPTION_BYTES) { |
| // 防止除以零 |
| double shareRatio = (downloaded == 0) ? Double.MAX_VALUE : (double) uploaded / downloaded; |
| 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", Constants.MIN_SHARE_RATIO_THRESHOLD); |
| return ResponseEntity.status(403).body(ans); // 403 Forbidden |
| } |
| } |
| |
| Resource resource = resourceService.getResourceById(resourceId); |
| byte[] file = resourceService.getTorrentFileByResource(resource, username); |
| if (file == null) { |
| 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(modifier.analyzeTorrentFile(file, username)); // 返回修改后的 torrent 文件 |
| } |
| |
| @GetMapping("/search") |
| public ResponseEntity<?> searchResources(@RequestHeader("token") String token, |
| @RequestParam("username") String username, |
| @RequestParam("query") String query) { |
| Map<String, Object> ans = new HashMap<>(); |
| |
| if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)){ |
| ans.put("message", "Invalid token"); |
| return ResponseEntity.badRequest().body(ans); |
| } |
| |
| List<Resource> resources = resourceService.searchByQuery(query); |
| if (resources.isEmpty()) { |
| return ResponseEntity.noContent().build(); |
| } |
| |
| ans.put("message", "Search results found"); |
| ans.put("data", Map.of( |
| "resources", resources |
| )); |
| return ResponseEntity.ok(resources); |
| } |
| |
| @DeleteMapping("/delete") |
| public ResponseEntity<?> deleteResource(@RequestHeader("token") String token, |
| @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) { |
| ans.put("message", "Invalid token or insufficient permissions"); |
| return ResponseEntity.badRequest().body(ans); |
| } |
| |
| try { |
| resourceService.deleteResource(resourceId); |
| } catch (Exception e) { |
| ans.put("message", "Failed to delete resource: " + e.getMessage()); |
| return ResponseEntity.status(500).body(ans); |
| } |
| |
| ans.put("message", "Resource deleted successfully"); |
| return ResponseEntity.ok(ans); |
| } |
| } |