blob: 306851a9b1eba9efe8f7159b12176b703a384e82 [file] [log] [blame]
22301102b1084372025-06-01 16:44:23 +08001package com.pt.controller;
2
3import com.pt.constant.Constants;
4import com.pt.entity.Resource;
5import com.pt.entity.User;
6import com.pt.service.ResourceService;
7import com.pt.service.UserService;
8import com.pt.utils.JWTUtils;
9import org.springframework.beans.factory.annotation.Autowired;
22301102f69709e2025-06-08 14:10:02 +080010import org.springframework.context.annotation.Bean;
22301102b1084372025-06-01 16:44:23 +080011import org.springframework.http.ResponseEntity;
12import org.springframework.web.bind.annotation.*;
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080013import org.springframework.web.multipart.MultipartFile;
22301102b1084372025-06-01 16:44:23 +080014
22301102bc6da0a2025-06-02 17:47:29 +080015import java.io.IOException;
22301102b1084372025-06-01 16:44:23 +080016import java.util.HashMap;
17import java.util.List;
18import java.util.Map;
22301102bc6da0a2025-06-02 17:47:29 +080019import java.io.File;
22301102b1084372025-06-01 16:44:23 +080020
21@RestController
22@RequestMapping("/api/resource")
23@CrossOrigin(origins = "*")
24public class ResourceController {
25
26 @Autowired
27 private ResourceService resourceService;
yyyangf786cfa2025-06-08 15:13:34 +080028
29 @Autowired
22301102b1084372025-06-01 16:44:23 +080030 private UserService userService;
31
32 @GetMapping("/list/all")
33 public ResponseEntity<?> getAllResources(@RequestHeader("token") String token,
34 @RequestParam("username") String username) {
22301102f69709e2025-06-08 14:10:02 +080035
22301102b1084372025-06-01 16:44:23 +080036 Map<String, Object> ans = new HashMap<>();
37
38 if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)){
22301102f69709e2025-06-08 14:10:02 +080039 ans.put("message", "Invalid token");
22301102b1084372025-06-01 16:44:23 +080040 return ResponseEntity.badRequest().body(ans);
41 }
42
43 List<Resource> resources = resourceService.getAllResources();
44 if (resources.isEmpty()) {
45 return ResponseEntity.noContent().build();
46 }
22301102bc6da0a2025-06-02 17:47:29 +080047 return ResponseEntity.ok(resources);
22301102b1084372025-06-01 16:44:23 +080048 }
49
50 @GetMapping("/list/user")
51 public ResponseEntity<?> getUserResources(@RequestHeader("token") String token,
52 @RequestParam("username") String username) {
22301102f69709e2025-06-08 14:10:02 +080053
22301102b1084372025-06-01 16:44:23 +080054 Map<String, Object> ans = new HashMap<>();
55
56 if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)){
22301102f69709e2025-06-08 14:10:02 +080057 ans.put("message", "Invalid token");
22301102b1084372025-06-01 16:44:23 +080058 return ResponseEntity.badRequest().body(ans);
59 }
60
61 List<Resource> resources = resourceService.getResourcesByAuthor(username);
62 if (resources.isEmpty()) {
63 return ResponseEntity.noContent().build();
64 }
65 return ResponseEntity.ok(resources);
66 }
67
68 @PostMapping("/publish")
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080069 public ResponseEntity<?> publishResource(
70 @RequestHeader("token") String token,
71 @RequestParam("username") String username,
72 @RequestParam("size") double size,
73 @RequestParam("name") String name,
74 @RequestParam("description") String description,
75 @RequestParam("torrent") MultipartFile torrentFile) {
76
22301102b1084372025-06-01 16:44:23 +080077 Map<String, Object> ans = new HashMap<>();
78
22301102bc6da0a2025-06-02 17:47:29 +080079 if (!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
22301102f69709e2025-06-08 14:10:02 +080080 ans.put("message", "Invalid token");
22301102b1084372025-06-01 16:44:23 +080081 return ResponseEntity.badRequest().body(ans);
82 }
83
84 User user = userService.findByUsername(username);
22301102bc6da0a2025-06-02 17:47:29 +080085 if (user == null || user.getLevel() < 2) {
22301102f69709e2025-06-08 14:10:02 +080086 ans.put("message", "Insufficient permissions to publish resources");
22301102b1084372025-06-01 16:44:23 +080087 return ResponseEntity.status(403).body(ans);
88 }
89
22301102bc6da0a2025-06-02 17:47:29 +080090 try {
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +080091 // 传入种子文件字节,同时传入资源其他信息
92 resourceService.publishResource(name, description, username, size, torrentFile.getBytes());
22301102bc6da0a2025-06-02 17:47:29 +080093 } catch (Exception e) {
22301102f69709e2025-06-08 14:10:02 +080094 ans.put("message", "Failed to publish resource: " + e.getMessage());
22301102bc6da0a2025-06-02 17:47:29 +080095 return ResponseEntity.status(500).body(ans);
96 }
22301102fe5f8412025-06-01 17:25:51 +080097
22301102f69709e2025-06-08 14:10:02 +080098 ans.put("message", "Resource published successfully");
22301102b1084372025-06-01 16:44:23 +080099 return ResponseEntity.ok(ans);
100 }
101
22301102bc6da0a2025-06-02 17:47:29 +0800102
103
Edwardsamaxlf1bf7ad2025-06-03 23:52:16 +0800104
22301102b1084372025-06-01 16:44:23 +0800105 @GetMapping("/get/{resourceId}")
106 public ResponseEntity<?> getResourceById(@PathVariable("resourceId") int resourceId,
107 @RequestHeader("token") String token,
108 @RequestParam("username") String username) {
109
110 Map<String, Object> ans = new HashMap<>();
111 if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
22301102f69709e2025-06-08 14:10:02 +0800112 ans.put("message", "Invalid token");
22301102b1084372025-06-01 16:44:23 +0800113 return ResponseEntity.badRequest().body(ans);
114 }
115
116 Resource resource = resourceService.getResourceById(resourceId);
117 if (resource == null) {
118 return ResponseEntity.notFound().build();
119 }
120 return ResponseEntity.ok(resource);
121 }
122
123 @GetMapping("/download/{resourceId}")
124 public ResponseEntity<?> downloadResource(@PathVariable("resourceId") int resourceId,
125 @RequestHeader("token") String token,
22301102bc6da0a2025-06-02 17:47:29 +0800126 @RequestParam("username") String username) throws IOException {
22301102b1084372025-06-01 16:44:23 +0800127
128 Map<String, Object> ans = new HashMap<>();
129 if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)) {
22301102f69709e2025-06-08 14:10:02 +0800130 ans.put("message", "Invalid token");
22301102b1084372025-06-01 16:44:23 +0800131 return ResponseEntity.badRequest().body(ans);
132 }
133
yyyangf786cfa2025-06-08 15:13:34 +0800134 User user = userService.findByUsername(username);
135 if (user == null) {
136 ans.put("message", "User not found");
137 return ResponseEntity.status(404).body(ans);
138 }
139
140 final double MIN_SHARE_RATIO_THRESHOLD = 0.5; // 最低共享率要求
141 final long DOWNLOAD_EXEMPTION_BYTES = 20L * 1024L * 1024L * 1024L; // 20GB下载量豁免
142
143 long uploaded = user.getUploaded();
144 long downloaded = user.getDownloaded();
145
146 // 如果用户的下载量超过豁免值,则检查其共享率
147 if (downloaded > DOWNLOAD_EXEMPTION_BYTES) {
148 // 防止除以零
149 double shareRatio = (downloaded == 0) ? Double.MAX_VALUE : (double) uploaded / downloaded;
150 if (shareRatio < MIN_SHARE_RATIO_THRESHOLD) {
151 ans.put("message", "Share ratio is too low. Please seed more to improve your ratio before downloading new resources.");
152 ans.put("current_share_ratio", String.format("%.2f", shareRatio));
153 ans.put("required_share_ratio", MIN_SHARE_RATIO_THRESHOLD);
154 return ResponseEntity.status(403).body(ans); // 403 Forbidden
155 }
156 }
157
22301102bc6da0a2025-06-02 17:47:29 +0800158 Resource resource = resourceService.getResourceById(resourceId);
159 byte[] file = resourceService.getTorrentFileByResource(resource, username);
160 if (file == null) {
161 return ResponseEntity.notFound().build();
162 }
22301102b1084372025-06-01 16:44:23 +0800163
22301102bc6da0a2025-06-02 17:47:29 +0800164 return ResponseEntity.ok()
165 .header("Content-Type", "application/x-bittorrent")
166 .header("Content-Disposition", "attachment; filename=\"" + resource.getName() + ".torrent\"")
167 .body(file);
22301102b1084372025-06-01 16:44:23 +0800168 }
169
170 @GetMapping("/search")
171 public ResponseEntity<?> searchResources(@RequestHeader("token") String token,
172 @RequestParam("username") String username,
173 @RequestParam("query") String query) {
174 Map<String, Object> ans = new HashMap<>();
175
176 if(!JWTUtils.checkToken(token, username, Constants.UserRole.USER)){
22301102f69709e2025-06-08 14:10:02 +0800177 ans.put("message", "Invalid token");
22301102b1084372025-06-01 16:44:23 +0800178 return ResponseEntity.badRequest().body(ans);
179 }
180
181 List<Resource> resources = resourceService.searchByQuery(query);
182 if (resources.isEmpty()) {
183 return ResponseEntity.noContent().build();
184 }
185 return ResponseEntity.ok(resources);
186 }
187
188 @GetMapping("/delete")
189 public ResponseEntity<?> deleteResource(@RequestHeader("token") String token,
190 @RequestParam("username") String username,
191 @RequestParam("resourceId") int resourceId) {
192 Map<String, Object> ans = new HashMap<>();
193 Resource resource = resourceService.getResourceById(resourceId);
194
195 if(!JWTUtils.checkToken(token, username, Constants.UserRole.ADMIN) || resource == null || !resource.getAuthor().equals(username)) {
22301102f69709e2025-06-08 14:10:02 +0800196 ans.put("message", "Invalid token or insufficient permissions");
22301102b1084372025-06-01 16:44:23 +0800197 return ResponseEntity.badRequest().body(ans);
198 }
199
22301102bc6da0a2025-06-02 17:47:29 +0800200 try {
201 resourceService.deleteResource(resourceId);
202 } catch (Exception e) {
22301102f69709e2025-06-08 14:10:02 +0800203 ans.put("message", "Failed to delete resource: " + e.getMessage());
22301102bc6da0a2025-06-02 17:47:29 +0800204 return ResponseEntity.status(500).body(ans);
205 }
22301102b1084372025-06-01 16:44:23 +0800206
22301102f69709e2025-06-08 14:10:02 +0800207 ans.put("message", "Resource deleted successfully");
22301102b1084372025-06-01 16:44:23 +0800208 return ResponseEntity.ok(ans);
209 }
22301102bc6da0a2025-06-02 17:47:29 +0800210
22301102b1084372025-06-01 16:44:23 +0800211}