完善了服务器配置,实现自动解析oss-url,自定义tracker响应
Change-Id: I2bf0848547427095bf898f2252c5020641764b21
diff --git a/pom.xml b/pom.xml
index 3b58690..af34658 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,6 +127,14 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>4.0.1</version>
+ <scope>provided</scope>
+ </dependency>
+
<dependency>
<groupId>com.turn</groupId>
<artifactId>ttorrent-core</artifactId>
@@ -134,7 +142,6 @@
<classifier>javadoc</classifier>
<type>javadoc</type>
</dependency>
-
<dependency>
<groupId>com.turn</groupId>
<artifactId>ttorrent-core</artifactId>
@@ -147,6 +154,7 @@
<artifactId>ttorrent-core</artifactId>
<version>1.5</version>
</dependency>
+
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/CategoryController.java b/src/main/java/edu/bjtu/groupone/backend/api/CategoryController.java
index a9b7b9d..145703e 100644
--- a/src/main/java/edu/bjtu/groupone/backend/api/CategoryController.java
+++ b/src/main/java/edu/bjtu/groupone/backend/api/CategoryController.java
@@ -55,4 +55,4 @@
public ResponseEntity<Category> getCategory(@PathVariable Long id) {
return ResponseEntity.ok(categoryService.getCategoryById(id));
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/DbTestController.java b/src/main/java/edu/bjtu/groupone/backend/api/DbTestController.java
new file mode 100644
index 0000000..ea24d21
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/api/DbTestController.java
@@ -0,0 +1,26 @@
+package edu.bjtu.groupone.backend.api;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+
+@RestController
+@RequestMapping("/test")
+public class DbTestController {
+
+ @Autowired
+ private DataSource dataSource;
+
+ @GetMapping("/db")
+ public String testDb() {
+ try (Connection conn = dataSource.getConnection()) {
+ return "✅ 成功连接数据库:" + conn.getMetaData().getURL();
+ } catch (Exception e) {
+ return "❌ 无法连接数据库:" + e.getMessage();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/TorrentController.java b/src/main/java/edu/bjtu/groupone/backend/api/TorrentController.java
index e5f1aa4..773c5f6 100644
--- a/src/main/java/edu/bjtu/groupone/backend/api/TorrentController.java
+++ b/src/main/java/edu/bjtu/groupone/backend/api/TorrentController.java
@@ -8,46 +8,49 @@
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
+import java.util.List;
+
@RestController
-@RequestMapping({"/api/torrents"})
+@RequestMapping("/api/torrents")
public class TorrentController {
+
+ private final TorrentService torrentService;
+
+ // 监听器列表应该放在专门的处理类中
@Autowired
- private TorrentService torrentService;
-
- public TorrentController() {
+ public TorrentController(TorrentService torrentService) {
+ this.torrentService = torrentService;
}
- @PostMapping({"/upload"})
- public ResponseEntity<?> uploadTorrent(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
- String uidStr = GetTokenUserId.getUserId(request);
- if (uidStr == null) {
- return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Token无效或缺失");
- } else {
- try {
- Long userId = Long.parseLong(uidStr);
- Torrent saved = this.torrentService.uploadTorrent(file, userId);
- return ResponseEntity.ok(saved);
- } catch (Exception var6) {
- return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("上传失败:" + var6.getMessage());
- }
- }
- }
+ @PostMapping("/upload")
+ public ResponseEntity<?> uploadTorrent(
+ @RequestParam("file") MultipartFile file,
+ @RequestParam("id") Long id ) throws Exception {
- @GetMapping({"/download/{infoHash}"})
+ Torrent saved = torrentService.uploadTorrent(file, id);
+ return ResponseEntity.ok(saved);
+
+ }
+ @GetMapping("/download/{infoHash}")
public ResponseEntity<Resource> downloadTorrent(@PathVariable String infoHash) {
try {
- Resource resource = this.torrentService.downloadTorrent(infoHash);
- return ((ResponseEntity.BodyBuilder)ResponseEntity.ok().header("Content-Disposition", new String[]{"attachment; filename=\"" + infoHash + ".torrent\""})).body(resource);
- } catch (Exception var3) {
+ Resource resource = torrentService.downloadTorrent(infoHash);
+ return ResponseEntity.ok()
+ .header("Content-Disposition", "attachment; filename=\"" + infoHash + ".torrent\"")
+ .body(resource);
+ } catch (Exception ex) {
return ResponseEntity.notFound().build();
}
}
-}
+ @PostMapping("/getTorrentList")
+ public ResponseEntity<?> getTorrentList() throws Exception {
+
+ List<Torrent> list = torrentService.getTorrentList();
+ return ResponseEntity.ok(list);
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/config/TrackerStarter.java b/src/main/java/edu/bjtu/groupone/backend/config/TrackerStarter.java
deleted file mode 100644
index 6ae8be7..0000000
--- a/src/main/java/edu/bjtu/groupone/backend/config/TrackerStarter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package edu.bjtu.groupone.backend.config;
-
-import com.turn.ttorrent.tracker.TrackedTorrent;
-import com.turn.ttorrent.tracker.Tracker;
-import java.io.File;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.security.NoSuchAlgorithmException;
-import java.util.Objects;
-import javax.annotation.PostConstruct;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-@Component
-public class TrackerStarter {
- private Tracker tracker;
-
- public TrackerStarter() {
- }
-
- @PostConstruct
- public void startTracker() throws Exception {
- InetSocketAddress address = new InetSocketAddress("0.0.0.0", 6969);
- this.tracker = new Tracker(address);
- this.tracker.start();
- System.out.println("Tracker started on http://localhost:6969/announce");
- }
-
- @Scheduled(
- fixedRate = 60000L
- )
- public void scanTorrentDirectory() throws IOException, NoSuchAlgorithmException {
- File torrentDir = new File("C:\\Users\\wangy\\Desktop\\GroupOne-Back-End(2)\\GroupOne-Back-End\\torrents");
- if (torrentDir.exists() && torrentDir.isDirectory()) {
- File[] var2 = (File[])Objects.requireNonNull(torrentDir.listFiles());
- int var3 = var2.length;
-
- for(int var4 = 0; var4 < var3; ++var4) {
- File file = var2[var4];
- if (file.getName().endsWith(".torrent")) {
- this.tracker.announce(TrackedTorrent.load(file));
- System.out.println("Loaded torrent: " + file.getName());
- }
- }
- } else {
- System.out.println("Torrent directory not found: " + torrentDir.getAbsolutePath());
- }
-
- }
-}
diff --git a/src/main/java/edu/bjtu/groupone/backend/config/TrafficAwareTracker.java b/src/main/java/edu/bjtu/groupone/backend/config/TrafficAwareTracker.java
new file mode 100644
index 0000000..d7dd987
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/config/TrafficAwareTracker.java
@@ -0,0 +1,36 @@
+package edu.bjtu.groupone.backend.config;
+
+import com.turn.ttorrent.tracker.TrackedPeer;
+import com.turn.ttorrent.tracker.TrackedTorrent;
+import com.turn.ttorrent.tracker.Tracker;
+import edu.bjtu.groupone.backend.domain.entity.AnnounceEvent;
+import edu.bjtu.groupone.backend.service.PeerTrafficService;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+public class TrafficAwareTracker extends Tracker {
+ private final PeerTrafficService trafficService;
+
+ public TrafficAwareTracker(InetSocketAddress address, PeerTrafficService trafficService)
+ throws IOException {
+ super(address);
+ this.trafficService = trafficService;
+ }
+
+ public void peerAnnounce(TrackedTorrent torrent, TrackedPeer peer,
+ AnnounceEvent event) throws IOException {
+ // 先记录流量(必须在super调用前执行)
+ if (peer.getUploaded() > 0 || peer.getDownloaded() > 0) {
+ trafficService.recordPeerTraffic(
+ torrent.getHexInfoHash(),
+ peer.getIp(),
+ peer.getPeerId(),
+ peer.getUploaded(),
+ peer.getDownloaded(),
+ System.currentTimeMillis() / 1000,
+ event
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/entity/AnnounceEvent.java b/src/main/java/edu/bjtu/groupone/backend/domain/entity/AnnounceEvent.java
new file mode 100644
index 0000000..8758465
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/entity/AnnounceEvent.java
@@ -0,0 +1,9 @@
+package edu.bjtu.groupone.backend.domain.entity;
+
+public enum AnnounceEvent {
+ STARTED, // 开始下载
+ STOPPED, // 停止
+ COMPLETED, // 完成
+ PAUSED, // 新增:暂停
+ RESUMED // 新增:恢复
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/entity/Torrent.java b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Torrent.java
index 0564b50..ec9d123 100644
--- a/src/main/java/edu/bjtu/groupone/backend/domain/entity/Torrent.java
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Torrent.java
@@ -1,5 +1,11 @@
package edu.bjtu.groupone.backend.domain.entity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
public class Torrent {
private Long id;
private String name;
@@ -11,6 +17,8 @@
private Double uploadMultiplier;
private String uploadedAt;
+ private String url;
+
public Long getId() {
return this.id;
}
diff --git a/src/main/java/edu/bjtu/groupone/backend/mapper/TorrentMapper.java b/src/main/java/edu/bjtu/groupone/backend/mapper/TorrentMapper.java
index a00d3cf..3977ea4 100644
--- a/src/main/java/edu/bjtu/groupone/backend/mapper/TorrentMapper.java
+++ b/src/main/java/edu/bjtu/groupone/backend/mapper/TorrentMapper.java
@@ -1,9 +1,17 @@
package edu.bjtu.groupone.backend.mapper;
import edu.bjtu.groupone.backend.domain.entity.Torrent;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
public interface TorrentMapper {
+ @Insert("insert into torrents (name,info_hash,size,uploader_id,url) values (#{name},#{infoHash},#{size},#{uploaderId},#{url})")
void insertTorrent(Torrent torrent);
Torrent selectByInfoHash(String infoHash);
+
+ @Select("select * from torrents")
+ List<Torrent> getTorrentList();
}
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/PeerTrafficService.java b/src/main/java/edu/bjtu/groupone/backend/service/PeerTrafficService.java
new file mode 100644
index 0000000..bb50b99
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/service/PeerTrafficService.java
@@ -0,0 +1,18 @@
+package edu.bjtu.groupone.backend.service;
+
+import edu.bjtu.groupone.backend.domain.entity.AnnounceEvent;
+
+import java.nio.ByteBuffer;
+
+public interface PeerTrafficService {
+ // 修改参数类型为ByteBuffer(ttorrent的peer_id实际类型)
+ void recordPeerTraffic(
+ String infoHash,
+ String ip,
+ ByteBuffer peerId, // 原为String
+ long uploaded,
+ long downloaded,
+ long timestamp,
+ AnnounceEvent customEvent
+ );
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/TorrentService.java b/src/main/java/edu/bjtu/groupone/backend/service/TorrentService.java
index 5a00de5..9c51eef 100644
--- a/src/main/java/edu/bjtu/groupone/backend/service/TorrentService.java
+++ b/src/main/java/edu/bjtu/groupone/backend/service/TorrentService.java
@@ -4,8 +4,12 @@
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
+import java.util.List;
+
public interface TorrentService {
Torrent uploadTorrent(MultipartFile file, Long userId) throws Exception;
Resource downloadTorrent(String infoHash) throws Exception;
+
+ List<Torrent> getTorrentList();
}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/TrackerStarter.java b/src/main/java/edu/bjtu/groupone/backend/service/TrackerStarter.java
new file mode 100644
index 0000000..3ef3031
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/service/TrackerStarter.java
@@ -0,0 +1,116 @@
+package edu.bjtu.groupone.backend.service;
+
+import com.turn.ttorrent.tracker.TrackedPeer;
+import com.turn.ttorrent.tracker.TrackedTorrent;
+import com.turn.ttorrent.tracker.Tracker;
+
+import java.io.*;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+import javax.annotation.PostConstruct;
+
+import edu.bjtu.groupone.backend.config.TrafficAwareTracker;
+import edu.bjtu.groupone.backend.domain.entity.AnnounceEvent;
+import edu.bjtu.groupone.backend.domain.entity.Torrent;
+import edu.bjtu.groupone.backend.service.PeerTrafficService;
+import edu.bjtu.groupone.backend.service.TorrentService;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TrackerStarter {
+ private Tracker tracker;
+ private final Set<String> loadedTorrentNames = new HashSet<>();
+
+ @Autowired
+ private PeerTrafficService peerTrafficService;
+ @Autowired
+ private TorrentService torrentService;
+
+ @PostConstruct
+ public void startTracker() throws Exception {
+// InetSocketAddress trackerAddress = new InetSocketAddress("0.0.0.0", 6969);
+// tracker = new Tracker(trackerAddress);
+// tracker.start();
+ InetSocketAddress address = new InetSocketAddress("0.0.0.0", 6969);
+ this.tracker = new TrafficAwareTracker(address, peerTrafficService);
+ this.tracker.start();
+ System.out.println("Tracker started with traffic monitoring");
+ }
+
+ @Scheduled(fixedRate = 10000L)
+ public void scanTorrentDirectory() throws IOException, NoSuchAlgorithmException {
+ List<Torrent> torrents = torrentService.getTorrentList();
+
+ for (Torrent torrent : torrents) {
+ String url = torrent.getUrl();
+ String fileName = extractFileNameFromUrl(url);
+
+ if (!loadedTorrentNames.contains(fileName)) {
+ try {
+ // 创建临时文件(自动带 .torrent 后缀)
+ File tempTorrentFile = File.createTempFile("torrent_", ".torrent");
+ tempTorrentFile.deleteOnExit(); // JVM退出时删除
+
+ // 下载内容到临时文件
+ try (InputStream in = new URL(url).openStream();
+ OutputStream out = new FileOutputStream(tempTorrentFile)) {
+ in.transferTo(out);
+ }
+
+ // 加载并注册种子
+ TrackedTorrent trackedTorrent = TrackedTorrent.load(tempTorrentFile);
+ this.tracker.announce(trackedTorrent);
+ loadedTorrentNames.add(fileName);
+
+ System.out.println("Loaded torrent from OSS (temp file): " + fileName);
+ tempTorrentFile.delete();
+ } catch (Exception e) {
+ System.err.println("Failed to load torrent: " + fileName + ", error: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+ private String extractFileNameFromUrl(String url) {
+ return url.substring(url.lastIndexOf('/') + 1);
+ }
+
+@Scheduled(fixedRate = 15000L)
+public void collectPeerTraffic() {
+ try {
+ // 使用反射获取 Tracker 的 private 字段 torrents
+ java.lang.reflect.Field torrentsField = Tracker.class.getDeclaredField("torrents");
+ torrentsField.setAccessible(true);
+
+ @SuppressWarnings("unchecked")
+ Map<?, TrackedTorrent> torrents = (Map<?, TrackedTorrent>) torrentsField.get(tracker);
+
+ for (TrackedTorrent torrent : torrents.values()) {
+ for (TrackedPeer peer : torrent.getPeers().values()) {
+ if (peer.getUploaded() > 0 || peer.getDownloaded() > 0) {
+ peerTrafficService.recordPeerTraffic(
+ torrent.getHexInfoHash(),
+ peer.getIp(),
+ peer.getPeerId(),
+ peer.getUploaded(),
+ peer.getDownloaded(),
+ System.currentTimeMillis() / 1000,
+ AnnounceEvent.COMPLETED // 实际项目中你可以按需要换成 STARTED, STOPPED 等
+ );
+ }
+ }
+ }
+ } catch (Exception e) {
+ System.err.println("Failed to collect peer traffic: " + e.getMessage());
+ e.printStackTrace();
+ }
+}
+}
+
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java b/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
index eaff2e2..7aeebf1 100644
--- a/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
+++ b/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
@@ -1,35 +1,30 @@
package edu.bjtu.groupone.backend.service;
+//import edu.bjtu.groupone.backend.model.Work;
import edu.bjtu.groupone.backend.domain.dto.WorkResponse;
import edu.bjtu.groupone.backend.domain.entity.Work;
import edu.bjtu.groupone.backend.mapper.WorkMybatisMapper;
-//import edu.bjtu.groupone.backend.model.Work;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
-
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
-
@Service
public class WorkService {
@Autowired
private WorkMybatisMapper workMybatisMapper;
-
@Autowired
private CategoryService categoryService;
-
public Page<WorkResponse> getWorks(Long categoryId, int page, int size) {
List<Long> categoryIds = categoryService.getAllSubcategoryIds(categoryId);
Pageable pageable = PageRequest.of(page-1, size);
return workMybatisMapper.findByCategoryIdIn(categoryIds, pageable)
.map(this::convertToResponse);
}
-
private WorkResponse convertToResponse(Work work) {
return new WorkResponse(
work.getId(),
@@ -41,16 +36,13 @@
work.getCreateTime()
);
}
-
public void addWork(Work work) {
work.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
workMybatisMapper.save(work);
}
-
public void deleteWork(Long id) {
workMybatisMapper.deleteById(id);
}
-
public void updateWork(Work work) {
Work existing = workMybatisMapper.findById(work.getId());
if (existing != null) {
@@ -58,7 +50,6 @@
}
workMybatisMapper.update(work);
}
-
public Work getWorkById(Long id) {
return workMybatisMapper.findById(id);
}
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/impl/PeerTrafficServiceImpl.java b/src/main/java/edu/bjtu/groupone/backend/service/impl/PeerTrafficServiceImpl.java
new file mode 100644
index 0000000..2928398
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/service/impl/PeerTrafficServiceImpl.java
@@ -0,0 +1,25 @@
+package edu.bjtu.groupone.backend.service.impl;
+
+import edu.bjtu.groupone.backend.domain.entity.AnnounceEvent;
+import edu.bjtu.groupone.backend.service.PeerTrafficService;
+import org.springframework.stereotype.Service;
+
+import java.nio.ByteBuffer;
+
+@Service
+public class PeerTrafficServiceImpl implements PeerTrafficService {
+ @Override
+ public void recordPeerTraffic(String infoHash, String ip, ByteBuffer peerId,
+ long uploaded, long downloaded, long timestamp,
+ AnnounceEvent customEvent) {
+ // 在实现层转换peerId为String(如需)
+ String peerIdStr = (peerId != null) ?
+ new String(peerId.array()) : "unknown";
+
+ // 实际存储逻辑...
+ System.out.printf(
+ "Traffic: %s | %s | %s | Up: %d | Down: %d | Event: %s%n",
+ infoHash, ip, peerIdStr, uploaded, downloaded, customEvent
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/impl/TorrentServiceImpl.java b/src/main/java/edu/bjtu/groupone/backend/service/impl/TorrentServiceImpl.java
index a1dac1f..74c8216 100644
--- a/src/main/java/edu/bjtu/groupone/backend/service/impl/TorrentServiceImpl.java
+++ b/src/main/java/edu/bjtu/groupone/backend/service/impl/TorrentServiceImpl.java
@@ -5,9 +5,13 @@
import edu.bjtu.groupone.backend.domain.entity.Torrent;
import edu.bjtu.groupone.backend.domain.entity.User;
import edu.bjtu.groupone.backend.service.TorrentService;
+import edu.bjtu.groupone.backend.utils.AliOSSUtils;
import edu.bjtu.groupone.backend.utils.TorrentParserUtil;
import java.io.File;
+import java.util.List;
import java.util.Map;
+
+import org.hibernate.sql.Alias;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
@@ -24,6 +28,9 @@
@Autowired
private UserMapper userMapper;
+ @Autowired
+ AliOSSUtils aliOSSUtils;
+
public TorrentServiceImpl() {
}
@@ -39,14 +46,14 @@
}
String savePath = pathToUse + File.separator + infoHash + ".torrent";
- File dest = new File(savePath);
- file.transferTo(dest);
+ String upload = aliOSSUtils.upload(file);
User uploader = this.userMapper.selectById(userId);
Torrent torrent = new Torrent();
torrent.setInfoHash(infoHash);
torrent.setName(name);
torrent.setFilePath(savePath);
torrent.setSize(size);
+ torrent.setUrl(upload);
torrent.setUploaderId((long)uploader.getUserId());
this.torrentMapper.insertTorrent(torrent);
return torrent;
@@ -65,4 +72,9 @@
}
}
}
+
+ @Override
+ public List<Torrent> getTorrentList() {
+ return torrentMapper.getTorrentList();
+ }
}
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/impl/UserServImpl.java b/src/main/java/edu/bjtu/groupone/backend/service/impl/UserServImpl.java
index ba2f9e9..19f5d93 100644
--- a/src/main/java/edu/bjtu/groupone/backend/service/impl/UserServImpl.java
+++ b/src/main/java/edu/bjtu/groupone/backend/service/impl/UserServImpl.java
@@ -139,6 +139,7 @@
public List<User> getAllUsers() {
return userMapper.selectAllUsers();
}
+
@Override
public int getRemainingTasks(int userId) {
User user = userMapper.selectUserById(userId);
diff --git a/src/main/java/edu/bjtu/groupone/backend/utils/GetTokenUserId.java b/src/main/java/edu/bjtu/groupone/backend/utils/GetTokenUserId.java
index b798f05..63dda65 100644
--- a/src/main/java/edu/bjtu/groupone/backend/utils/GetTokenUserId.java
+++ b/src/main/java/edu/bjtu/groupone/backend/utils/GetTokenUserId.java
@@ -6,10 +6,7 @@
public class GetTokenUserId {
public static String getUserId(HttpServletRequest request) {
- String token = request.getHeader("Authorization");
- if (token == null || !token.startsWith("Bearer ")) {
- return null;
- }
+ String token = request.getHeader("token");
// 解析 JWT Token,获取用户 ID
String jwt = token.substring(7); // 去掉 'Bearer ' 前缀
Claims claims = JwtUtils.parseJwt(jwt); // 从 JWT 中获取用户 ID
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 165698e..2e95546 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,11 +1,6 @@
# ??MySQL??
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
-spring.datasource.url=jdbc:mysql://rm-cn-qzy4ah2qt0008vfo.rwlb.rds.aliyuncs.com:3306/smart_course_platform\
-?useSSL=false\
-&serverTimezone=Asia/Shanghai\
-&characterEncoding=utf8\
-&allowPublicKeyRetrieval=true
-
+spring.datasource.url=jdbc:mysql://rm-cn-qzy4ah2qt0008vfo.rwlb.rds.aliyuncs.com:3306/smart_course_platform?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8&allowPublicKeyRetrieval=true
spring.datasource.username=wangy
spring.datasource.password=Wyt2005011600
# src/main/resources/application.properties
@@ -27,4 +22,6 @@
# ????????
mybatis.mapper-locations=classpath:mapper/*.xml
-torrent.storage.path=./torrent
\ No newline at end of file
+torrent.storage.path=./torrent
+
+server.address=0.0.0.0
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/DatabaseConnectionTest.java b/src/test/java/edu/bjtu/groupone/backend/DatabaseConnectionTest.java
new file mode 100644
index 0000000..e2e565f
--- /dev/null
+++ b/src/test/java/edu/bjtu/groupone/backend/DatabaseConnectionTest.java
@@ -0,0 +1,28 @@
+package edu.bjtu.groupone.backend;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@SpringBootTest
+public class DatabaseConnectionTest {
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Test
+ public void testDatabaseConnection() {
+ try (Connection connection = dataSource.getConnection()) {
+ assertNotNull(connection);
+ System.out.println("✅ 数据库连接成功: " + connection.getMetaData().getURL());
+ System.out.println("📌 数据库用户: " + connection.getMetaData().getUserName());
+ } catch (Exception e) {
+ fail("❌ 数据库连接失败: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/edu/bjtu/groupone/backend/TorrentControllerTest.java b/src/test/java/edu/bjtu/groupone/backend/TorrentControllerTest.java
deleted file mode 100644
index 86573d8..0000000
--- a/src/test/java/edu/bjtu/groupone/backend/TorrentControllerTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package edu.bjtu.groupone.backend;
-
-import edu.bjtu.groupone.backend.api.TorrentController;
-import edu.bjtu.groupone.backend.domain.entity.Torrent;
-import edu.bjtu.groupone.backend.service.TorrentService;
-import edu.bjtu.groupone.backend.utils.GetTokenUserId;
-import jakarta.servlet.http.HttpServletRequest;
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.MockedStatic;
-import org.mockito.Mockito;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.core.io.ByteArrayResource;
-import org.springframework.core.io.Resource;
-import org.springframework.http.ResponseEntity;
-import org.springframework.mock.web.MockMultipartFile;
-import org.springframework.web.multipart.MultipartFile;
-
-@ExtendWith({MockitoExtension.class})
-public class TorrentControllerTest {
- @Mock
- private TorrentService torrentService;
- @InjectMocks
- private TorrentController torrentController;
- @Mock
- private HttpServletRequest request;
-
- public TorrentControllerTest() {
- }
-
- @Test
- public void uploadTorrent_shouldReturnTorrent_whenUserIdValid() throws Exception {
- MultipartFile file = new MockMultipartFile("file", "test.torrent", "application/x-bittorrent", "dummy data".getBytes());
- MockedStatic<GetTokenUserId> utilities = Mockito.mockStatic(GetTokenUserId.class);
-
- try {
- utilities.when(() -> {
- GetTokenUserId.getUserId(this.request);
- }).thenReturn("123");
- Torrent expectedTorrent = new Torrent();
- expectedTorrent.setId(1L);
- expectedTorrent.setName("testfile");
- expectedTorrent.setInfoHash("fakehash");
- expectedTorrent.setSize(12345L);
- expectedTorrent.setUploaderId(123L);
- Mockito.when(this.torrentService.uploadTorrent(file, 123L)).thenReturn(expectedTorrent);
- ResponseEntity<?> response = this.torrentController.uploadTorrent(file, this.request);
- Assertions.assertThat(response.getStatusCodeValue()).isEqualTo(200);
- Assertions.assertThat(response.getBody()).isEqualTo(expectedTorrent);
- ((TorrentService)Mockito.verify(this.torrentService, Mockito.times(1))).uploadTorrent(file, 123L);
- } catch (Throwable var6) {
- if (utilities != null) {
- try {
- utilities.close();
- } catch (Throwable var5) {
- var6.addSuppressed(var5);
- }
- }
-
- throw var6;
- }
-
- if (utilities != null) {
- utilities.close();
- }
-
- }
-
- @Test
- public void uploadTorrent_shouldReturnUnauthorized_whenUserIdNull() throws Exception {
- MockedStatic<GetTokenUserId> utilities = Mockito.mockStatic(GetTokenUserId.class);
-
- try {
- utilities.when(() -> {
- GetTokenUserId.getUserId(this.request);
- }).thenReturn((Object)null);
- MultipartFile file = new MockMultipartFile("file", "test.torrent", "application/x-bittorrent", "dummy data".getBytes());
- ResponseEntity<?> response = this.torrentController.uploadTorrent(file, this.request);
- Assertions.assertThat(response.getStatusCodeValue()).isEqualTo(401);
- Assertions.assertThat(response.getBody()).isEqualTo("Token无效或缺失");
- Mockito.verifyNoInteractions(new Object[]{this.torrentService});
- } catch (Throwable var5) {
- if (utilities != null) {
- try {
- utilities.close();
- } catch (Throwable var4) {
- var5.addSuppressed(var4);
- }
- }
-
- throw var5;
- }
-
- if (utilities != null) {
- utilities.close();
- }
-
- }
-
- @Test
- public void downloadTorrent_shouldReturnResource_whenFound() throws Exception {
- String infoHash = "fakehash";
- byte[] data = "torrent data".getBytes();
- Resource resource = new ByteArrayResource(data);
- Mockito.when(this.torrentService.downloadTorrent(infoHash)).thenReturn(resource);
- ResponseEntity<Resource> response = this.torrentController.downloadTorrent(infoHash);
- Assertions.assertThat(response.getStatusCodeValue()).isEqualTo(200);
- Assertions.assertThat(response.getHeaders().getFirst("Content-Disposition")).isEqualTo("attachment; filename=\"" + infoHash + ".torrent\"");
- Assertions.assertThat((Resource)response.getBody()).isEqualTo(resource);
- ((TorrentService)Mockito.verify(this.torrentService, Mockito.times(1))).downloadTorrent(infoHash);
- }
-
- @Test
- public void downloadTorrent_shouldReturnNotFound_whenException() throws Exception {
- String infoHash = "notexist";
- Mockito.when(this.torrentService.downloadTorrent(infoHash)).thenThrow(new Throwable[]{new RuntimeException("Not found")});
- ResponseEntity<Resource> response = this.torrentController.downloadTorrent(infoHash);
- Assertions.assertThat(response.getStatusCodeValue()).isEqualTo(404);
- Assertions.assertThat((Resource)response.getBody()).isNull();
- ((TorrentService)Mockito.verify(this.torrentService, Mockito.times(1))).downloadTorrent(infoHash);
- }
-}
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/TorrentServiceImplTest.java b/src/test/java/edu/bjtu/groupone/backend/TorrentServiceImplTest.java
deleted file mode 100644
index f25f7cb..0000000
--- a/src/test/java/edu/bjtu/groupone/backend/TorrentServiceImplTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package edu.bjtu.groupone.backend;
-
-import edu.bjtu.groupone.backend.mapper.TorrentMapper;
-import edu.bjtu.groupone.backend.mapper.UserMapper;
-import edu.bjtu.groupone.backend.domain.entity.Torrent;
-import edu.bjtu.groupone.backend.domain.entity.User;
-import edu.bjtu.groupone.backend.service.impl.TorrentServiceImpl;
-import java.io.File;
-import java.io.FileInputStream;
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.core.io.Resource;
-import org.springframework.mock.web.MockMultipartFile;
-
-@ExtendWith({MockitoExtension.class})
-public class TorrentServiceImplTest {
- @Mock
- private TorrentMapper torrentMapper;
- @Mock
- private UserMapper userMapper;
- @InjectMocks
- private TorrentServiceImpl torrentService;
-
- public TorrentServiceImplTest() {
- }
-
- @BeforeEach
- void setup() {
- }
-
- @Test
- public void uploadTorrent_shouldSaveAndReturnTorrent() throws Exception {
- File file = new File("torrents/22301024-王玉涛.doc.torrent");
- Assertions.assertThat(file.exists()).isTrue();
- FileInputStream inputStream = new FileInputStream(file);
- MockMultipartFile mockFile = new MockMultipartFile("file", "22301024-王玉涛.doc.torrent", "application/x-bittorrent", inputStream);
- ((TorrentMapper)Mockito.doNothing().when(this.torrentMapper)).insertTorrent((Torrent)Mockito.any(Torrent.class));
- User fakeUser = new User();
- fakeUser.setUserId(100);
- Mockito.when(this.userMapper.selectById(100L)).thenReturn(fakeUser);
- Torrent result = this.torrentService.uploadTorrent(mockFile, 100L);
- Assertions.assertThat(result).isNotNull();
- Assertions.assertThat(result.getInfoHash()).isNotBlank();
- Assertions.assertThat(result.getName()).isNotBlank();
- Assertions.assertThat(result.getUploaderId()).isEqualTo(100L);
- ((TorrentMapper)Mockito.verify(this.torrentMapper, Mockito.times(1))).insertTorrent((Torrent)Mockito.any(Torrent.class));
- }
-
- @Test
- public void downloadTorrent_shouldReturnResource_whenTorrentExists() throws Exception {
- File tempFile = File.createTempFile("test-torrent-", ".torrent");
- tempFile.deleteOnExit();
- Torrent fakeTorrent = new Torrent();
- fakeTorrent.setInfoHash("fakeinfohash123");
- fakeTorrent.setFilePath(tempFile.getAbsolutePath());
- Mockito.when(this.torrentMapper.selectByInfoHash("fakeinfohash123")).thenReturn(fakeTorrent);
- Resource resource = this.torrentService.downloadTorrent("fakeinfohash123");
- Assertions.assertThat(resource).isNotNull();
- Assertions.assertThat(resource.exists()).isTrue();
- Assertions.assertThat(resource.getFile().getAbsolutePath()).isEqualTo(tempFile.getAbsolutePath());
- }
-}
diff --git a/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java b/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
index b3871da..44a05b6 100644
--- a/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
+++ b/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
@@ -1,10 +1,13 @@
package edu.bjtu.groupone.backend;
+import com.turn.ttorrent.tracker.Tracker;
+import edu.bjtu.groupone.backend.config.TrafficAwareTracker;
import edu.bjtu.groupone.backend.domain.dto.WorkResponse;
import edu.bjtu.groupone.backend.domain.entity.Category;
import edu.bjtu.groupone.backend.domain.entity.Work;
import edu.bjtu.groupone.backend.mapper.WorkMybatisMapper;
import edu.bjtu.groupone.backend.service.CategoryService;
+import edu.bjtu.groupone.backend.service.PeerTrafficService;
import edu.bjtu.groupone.backend.service.WorkService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -12,10 +15,14 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
+import java.io.IOException;
+import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.List;
@@ -23,6 +30,7 @@
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
+@SpringBootTest
@ExtendWith(MockitoExtension.class)
class WorkServiceTest {
@@ -117,4 +125,14 @@
List<WorkResponse> result = workService.getWorksByAuthor("李四");
assertTrue(result.isEmpty());
}
+
+ @Autowired
+ PeerTrafficService peerTrafficService;
+ @Test
+ public void test() throws IOException {
+ Tracker tracker;
+ InetSocketAddress trackerAddress = new InetSocketAddress("0.0.0.0", 6969);
+ tracker = new Tracker(trackerAddress);
+ tracker.start();
+ }
}
\ No newline at end of file
diff --git "a/torrents/22301024-\347\216\213\347\216\211\346\266\233.doc.torrent" "b/torrents/22301024-\347\216\213\347\216\211\346\266\233.doc.torrent"
deleted file mode 100644
index 5786afb..0000000
--- "a/torrents/22301024-\347\216\213\347\216\211\346\266\233.doc.torrent"
+++ /dev/null
Binary files differ
diff --git "a/torrents/\345\275\251\346\216\222.mp4.torrent" "b/torrents/\345\275\251\346\216\222.mp4.torrent"
new file mode 100644
index 0000000..f47670b
--- /dev/null
+++ "b/torrents/\345\275\251\346\216\222.mp4.torrent"
Binary files differ