调试交互
Change-Id: Ib9d7b8432cb622c7e28c842ab4dc4e156fcd6414
diff --git a/src/main/java/com/example/myproject/config/WebConfig.java b/src/main/java/com/example/myproject/config/WebConfig.java
index 6f9322d..900553e 100644
--- a/src/main/java/com/example/myproject/config/WebConfig.java
+++ b/src/main/java/com/example/myproject/config/WebConfig.java
@@ -1,3 +1,20 @@
+// package com.example.myproject.config;
+
+// import org.springframework.context.annotation.Configuration;
+// import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+// import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+// @Configuration
+// public class WebConfig implements WebMvcConfigurer {
+// @Override
+// public void addResourceHandlers(ResourceHandlerRegistry registry) {
+// // 访问 /uploads/** 映射到本地 D:/Desktop/echo/echo-backend/uploads/
+// registry.addResourceHandler("/uploads/**")
+// .addResourceLocations("file:D:/PT/echo-backend/uploads/");
+// registry.addResourceHandler("/torrent-images/**")
+// .addResourceLocations("file:./uploads/torrents/");
+// }
+// }
package com.example.myproject.config;
import org.springframework.context.annotation.Configuration;
@@ -8,10 +25,13 @@
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
- // 访问 /uploads/** 映射到本地 D:/Desktop/echo/echo-backend/uploads/
+ // 这里相对路径是相对于启动目录,比如在项目根目录启动则是 ./uploads/
registry.addResourceHandler("/uploads/**")
- .addResourceLocations("file:D:/PT/echo-backend/uploads/");
- registry.addResourceHandler("/torrent-images/**")
- .addResourceLocations("file:./uploads/torrents/");
+ .addResourceLocations("file:./uploads/");
+
+// registry.addResourceHandler("/torrent-images/**")
+// .addResourceLocations("file:./uploads/torrents/");
}
}
+
+
diff --git a/src/main/java/com/example/myproject/controller/DynamicController.java b/src/main/java/com/example/myproject/controller/DynamicController.java
index db1d0a2..a988c8f 100644
--- a/src/main/java/com/example/myproject/controller/DynamicController.java
+++ b/src/main/java/com/example/myproject/controller/DynamicController.java
@@ -33,19 +33,22 @@
return ResponseEntity.ok("动态删除成功");
}
- //好友动态评论
@PostMapping("/{user_id}/feeds/{dynamic_id}/comments")
public ResponseEntity<Map<String, Object>> addComment(
@PathVariable("user_id") Long userId,
@PathVariable("dynamic_id") Long dynamicId,
- @RequestBody Map<String, String> content) {
+ @RequestBody Map<String, Object> content) {
+ String commentContent = (String) content.get("content");
- String commentContent = content.get("content"); // 获取评论内容
- Map<String, Object> response = dynamicService.addComment(userId, dynamicId, commentContent);
+ Long parentCommentId = content.containsKey("parent_comment_id") && content.get("parent_comment_id") != null ?
+ Long.parseLong(content.get("parent_comment_id").toString()) : null;
+ Map<String, Object> response = dynamicService.addComment(userId, dynamicId, commentContent, parentCommentId);
return ResponseEntity.ok(response);
}
+
+
//获取某个好友的所有动态
@GetMapping("/{user_id}/getAdynamic")
public ResponseEntity<Map<String, Object>> getAllUserDynamics(@PathVariable("user_id") Long userId) {
diff --git a/src/main/java/com/example/myproject/controller/TorrentController.java b/src/main/java/com/example/myproject/controller/TorrentController.java
index 74cb8f9..aecfc64 100644
--- a/src/main/java/com/example/myproject/controller/TorrentController.java
+++ b/src/main/java/com/example/myproject/controller/TorrentController.java
@@ -1,7 +1,331 @@
+// package com.example.myproject.controller;
+
+// import com.example.myproject.common.base.PageUtil;
+// import com.example.myproject.entity.TorrentEntity;
+// import com.example.myproject.service.TorrentService;
+// import com.example.myproject.service.PromotionService;
+// import com.example.myproject.dto.param.TorrentParam;
+// import com.example.myproject.dto.vo.TorrentVO;
+// import com.example.myproject.common.base.Result;
+// import com.example.myproject.dto.param.TorrentUploadParam;
+// import com.example.myproject.dto.TorrentUpdateDTO;
+// import com.example.myproject.dto.PromotionCreateDTO;
+// import com.example.myproject.entity.Promotion;
+// import com.example.myproject.service.UserService;
+
+// import io.swagger.v3.oas.annotations.Operation;
+// import io.swagger.v3.oas.annotations.media.Content;
+// import io.swagger.v3.oas.annotations.media.Schema;
+// import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+// import org.springframework.beans.factory.annotation.Autowired;
+// import org.springframework.http.HttpStatus;
+// import org.springframework.http.ResponseEntity;
+// import org.springframework.validation.annotation.Validated;
+// import org.springframework.web.bind.annotation.*;
+// import org.springframework.web.multipart.MultipartFile;
+
+// import javax.servlet.http.HttpServletRequest;
+// import javax.servlet.http.HttpServletResponse;
+// import java.io.File;
+// import java.io.IOException;
+// import java.util.List;
+
+// import cn.dev33.satoken.annotation.SaCheckLogin;
+// import cn.dev33.satoken.stp.StpUtil;
+
+// @RestController
+// @RequestMapping("/seeds")
+// public class TorrentController {
+
+// @Autowired
+// private TorrentService torrentService;
+
+// @Autowired
+// private PromotionService promotionService;
+
+// @Autowired
+// private UserService userService;
+
+
+// @SaCheckLogin
+// @Operation(summary = "种子列表查询", description = "种子列表条件查询-分页-排序")
+// @ApiResponse(responseCode = "0", description = "操作成功",
+// content = {@Content(mediaType = "application/json",
+// schema = @Schema(implementation = TorrentVO.class))
+// })
+// @PostMapping("/list")
+// public Result list(@RequestBody TorrentParam param) {
+// // 构建排序和模糊查询条件
+// param.validOrder(param.getOrderKey(TorrentEntity.class));
+// param.buildLike();
+
+// PageUtil.startPage(param);
+
+// // 查询数据
+// List<TorrentEntity> list = torrentService.search(param);
+
+// // 返回分页结果
+// return Result.ok(list, PageUtil.getPage(list));
+// }
+
+// @SaCheckLogin
+// @Operation(summary = "种子详情查询")
+// @ApiResponse(responseCode = "0", description = "操作成功", content = {
+// @Content(mediaType = "application/json", schema = @Schema(implementation =
+// TorrentEntity.class))
+// })
+// @PostMapping("/info/{id}")
+// public Result info(@PathVariable("id")Long id) {
+
+// TorrentEntity entity = torrentService.selectBySeedId(id);
+// return Result.ok(entity);
+// }
+
+// @Operation(summary = "上传种子")
+
+// @PostMapping("/upload")
+// public Result uploadTorrent(
+// @RequestParam("file") MultipartFile file,
+// @RequestParam("coverImage") MultipartFile coverImage,
+// @ModelAttribute @Validated TorrentUploadParam param,
+// HttpServletRequest request
+// ) throws IOException {
+// try {
+// // 验证用户权限
+// // Long userId = StpUtil.getLoginIdAsLong();
+// String userId = String.valueOf(param.getUploader());
+// param.setUploader(userId);
+
+// // 验证文件大小和类型
+// if (file.isEmpty() || file.getSize() > 10 * 1024 * 1024) { // 10MB限制
+// return Result.error("文件大小不符合要求");
+// }
+
+// if (!file.getOriginalFilename().toLowerCase().endsWith(".torrent")) {
+// return Result.error("只支持.torrent文件");
+// }
+// if (!coverImage.isEmpty()) {
+// String originalFilename = coverImage.getOriginalFilename();
+// String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
+// String fileName = System.currentTimeMillis() + suffix;
+
+// if (!originalFilename.toLowerCase().matches(".*\\.(jpg|jpeg|png)$")) {
+// return Result.error("仅支持 JPG/PNG 格式的封面图片");
+// }
+
+
+// // 项目根目录下的 /uploads/torrents/
+// String uploadDir = System.getProperty("user.dir") + "/uploads/torrents/";
+// File dir = new File(uploadDir);
+// if (!dir.exists()) dir.mkdirs(); // 自动创建目录
+
+// File dest = new File(uploadDir + fileName);
+// coverImage.transferTo(dest);
+
+
+// String imageUrl = request.getScheme() + "://" + request.getServerName() + ":" +
+// request.getServerPort() + "/torrent-images/" + fileName;
+
+
+// param.setImageUrl(imageUrl);
+// }
+
+// torrentService.uploadTorrent(file, param);
+// return Result.ok();
+// } catch (Exception e) {
+// return Result.error("种子上传失败: " + e.getMessage());
+// }
+// }
+
+// /**
+// * 获取种子文件
+// */
+// @GetMapping("/{seed_id}/download")
+// public void downloadTorrent(
+// @PathVariable("seed_id") Long seedId,
+// @RequestParam("passkey") String passkey,
+// HttpServletResponse response) throws IOException {
+
+// // 获取种子实体
+// TorrentEntity entity = torrentService.selectBySeedId(seedId);
+// if (entity == null) {
+// response.sendError(HttpServletResponse.SC_NOT_FOUND, "种子不存在");
+// return;
+// }
+
+// // 获取并处理种子文件内容(需在service中实现passkey注入)
+// byte[] torrentBytes = torrentService.fetch(seedId, passkey);
+
+// // 设置下载文件名
+// String filename = entity.getFileName();
+// if (filename == null || filename.isBlank()) {
+// filename = seedId + ".torrent";
+// }
+// if (!filename.toLowerCase().endsWith(".torrent")) {
+// filename = filename + ".torrent";
+// }
+// filename = java.net.URLEncoder.encode(filename, java.nio.charset.StandardCharsets.UTF_8).replaceAll("\\+",
+// "%20");
+
+// // 设置响应头
+// response.setCharacterEncoding(java.nio.charset.StandardCharsets.UTF_8.name());
+// response.setContentLength(torrentBytes.length);
+// response.setContentType("application/x-bittorrent");
+// response.setHeader("Content-Disposition", "attachment;filename=" + filename);
+
+// // 写入文件内容
+// response.getOutputStream().write(torrentBytes);
+// response.getOutputStream().flush();
+// }
+
+// /**
+// * 收藏或者取消收藏
+// */
+// @PostMapping("/{seed_id}/favorite-toggle")
+// public Result favorite(
+// @PathVariable("seed_id") Long seedId,
+// @RequestParam("user_id") Long userId) {
+// try {
+
+// return torrentService.favorite(seedId, userId);
+// } catch (Exception e) {
+// return Result.error("失败: ");
+// }
+// }
+
+// @SaCheckLogin
+// @Operation(summary = "删除种子")
+// @DeleteMapping("/{torrentId}")
+// public Result deleteTorrent(@PathVariable Long torrentId) {
+// try {
+// // 验证用户权限
+// Long userId = StpUtil.getLoginIdAsLong();
+// if (!torrentService.canUserDeleteTorrent(torrentId, userId)) {
+// return Result.error("没有权限删除此种子");
+// }
+
+// torrentService.deleteTorrent(torrentId);
+// return Result.ok();
+// } catch (Exception e) {
+// return Result.error("删除失败: " + e.getMessage());
+// }
+// }
+
+// @SaCheckLogin
+// @Operation(summary = "修改种子信息")
+// @PutMapping("/{torrentId}")
+// public Result updateTorrent(
+// @PathVariable Long torrentId,
+// @RequestBody @Validated TorrentUpdateDTO updateDTO) {
+// try {
+// // 验证用户权限
+// Long userId = StpUtil.getLoginIdAsLong();
+// if (!torrentService.canUserUpdateTorrent(torrentId, userId)) {
+// return Result.error("没有权限修改此种子");
+// }
+
+// torrentService.updateTorrent(torrentId, updateDTO);
+// return Result.ok();
+// } catch (Exception e) {
+// return Result.error("更新失败: " + e.getMessage());
+// }
+// }
+
+// @SaCheckLogin
+// @Operation(summary = "创建促销活动")
+// @PostMapping("/promotions")
+// public Result createPromotion(@RequestBody @Validated PromotionCreateDTO promotionDTO) {
+// try {
+// // 验证用户权限(只有管理员可以创建促销)
+// // if (!StpUtil.hasRole("admin")) {
+// // return Result.error("没有权限创建促销活动");
+// // }
+// //
+// Promotion promotion = promotionService.createPromotion(promotionDTO);
+// return Result.ok(promotion);
+// } catch (Exception e) {
+// return Result.error("创建促销失败: " + e.getMessage());
+// }
+// }
+
+// @SaCheckLogin
+// @Operation(summary = "获取促销活动列表")
+// @GetMapping("/promotions")
+// public Result getPromotions() {
+// try {
+// List<Promotion> promotions = promotionService.getAllActivePromotions();
+// return Result.ok(promotions);
+// } catch (Exception e) {
+// return Result.error("获取促销列表失败: " + e.getMessage());
+// }
+// }
+
+// @SaCheckLogin
+// @Operation(summary = "获取促销详情")
+// @GetMapping("/promotions/{promotionId}")
+// public Result getPromotionDetails(@PathVariable Long promotionId) {
+// try {
+// Promotion promotion = promotionService.getPromotionById(promotionId);
+// if (promotion == null) {
+// return Result.error("促销活动不存在");
+// }
+// return Result.ok(promotion);
+// } catch (Exception e) {
+// return Result.error("获取促销详情失败: " + e.getMessage());
+// }
+// }
+
+// @SaCheckLogin
+// @Operation(summary = "删除促销活动")
+// @DeleteMapping("/promotions/{promotionId}")
+// public Result deletePromotion(@PathVariable Long promotionId) {
+// try {
+// // 验证用户权限(只有管理员可以删除促销)
+// if (!StpUtil.hasRole("admin")) {
+// return Result.error("没有权限删除促销活动");
+// }
+
+// promotionService.deletePromotion(promotionId);
+// return Result.ok();
+// } catch (Exception e) {
+// return Result.error("删除促销失败: " + e.getMessage());
+// }
+// }
+
+// // 下载种子(包含反作弊机制)
+// @PostMapping("/{torrentId}/download")
+// public ResponseEntity<?> downloadTorrent(@PathVariable Long torrentId,
+// @RequestParam Long userId) {
+// // // 验证用户身份和权限
+// // if (!userService.validateUser(userId)) {
+// // return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+// // }
+
+// // 检查用户上传量是否足够
+// if (!torrentService.checkUserUploadRatio(userId)) {
+// return ResponseEntity.status(HttpStatus.FORBIDDEN)
+// .body("上传量不足,无法下载");
+// }
+
+// // 应用促销折扣(如果有)
+// double downloadSize = torrentService.calculateDownloadSize(torrentId, userId);
+
+// // 记录下载
+// torrentService.recordDownload(torrentId, userId, downloadSize);
+
+// return ResponseEntity.ok().build();
+// }
+
+// }
package com.example.myproject.controller;
+import cn.hutool.core.util.StrUtil;
import com.example.myproject.common.base.PageUtil;
+import com.example.myproject.dto.TrackerProtocol;
import com.example.myproject.entity.TorrentEntity;
+import com.example.myproject.entity.TorrentReport;
+import com.example.myproject.repository.TorrentReportRepository;
import com.example.myproject.service.TorrentService;
import com.example.myproject.service.PromotionService;
import com.example.myproject.dto.param.TorrentParam;
@@ -13,11 +337,17 @@
import com.example.myproject.entity.Promotion;
import com.example.myproject.service.UserService;
+import com.turn.ttorrent.bcodec.BEValue;
+import com.turn.ttorrent.bcodec.BEncoder;
+import com.turn.ttorrent.common.TorrentUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -29,15 +359,20 @@
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
-import java.util.List;
+import java.net.URLDecoder;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
@RestController
@RequestMapping("/seeds")
+@Slf4j
+@RequiredArgsConstructor
public class TorrentController {
-
+ private final TorrentReportRepository torrentReportRepository;
@Autowired
private TorrentService torrentService;
@@ -46,6 +381,7 @@
@Autowired
private UserService userService;
+ private final List<BEValue> peers = new Vector<>();
@SaCheckLogin
@@ -54,8 +390,8 @@
content = {@Content(mediaType = "application/json",
schema = @Schema(implementation = TorrentVO.class))
})
- @PostMapping("/list")
- public Result list(@RequestBody TorrentParam param) {
+ @GetMapping("/list")
+ public Result list( TorrentParam param) {
// 构建排序和模糊查询条件
param.validOrder(param.getOrderKey(TorrentEntity.class));
param.buildLike();
@@ -82,8 +418,7 @@
return Result.ok(entity);
}
-@Operation(summary = "上传种子")
-
+ @Operation(summary = "上传种子")
@PostMapping("/upload")
public Result uploadTorrent(
@RequestParam("file") MultipartFile file,
@@ -125,7 +460,8 @@
String imageUrl = request.getScheme() + "://" + request.getServerName() + ":" +
- request.getServerPort() + "/torrent-images/" + fileName;
+ request.getServerPort() + "/uploads/torrents/" + fileName;
+// String imageUrl ="/uploads/torrents/" + fileName;
param.setImageUrl(imageUrl);
@@ -292,31 +628,79 @@
return Result.error("删除促销失败: " + e.getMessage());
}
}
-
- // 下载种子(包含反作弊机制)
- @PostMapping("/{torrentId}/download")
- public ResponseEntity<?> downloadTorrent(@PathVariable Long torrentId,
- @RequestParam Long userId) {
-// // 验证用户身份和权限
-// if (!userService.validateUser(userId)) {
-// return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-// }
-
- // 检查用户上传量是否足够
- if (!torrentService.checkUserUploadRatio(userId)) {
- return ResponseEntity.status(HttpStatus.FORBIDDEN)
- .body("上传量不足,无法下载");
+ @GetMapping("/announce")
+ public ResponseEntity<byte[]> announce(TrackerProtocol trackerProtocol, HttpServletRequest request, @RequestParam(value = "info_hash") String encodedInfoHash){
+ HashMap<String, BEValue> map = new HashMap<>();
+ if (StrUtil.isBlank(trackerProtocol.getIp())) {
+ trackerProtocol.setIp(request.getRemoteAddr());
}
- // 应用促销折扣(如果有)
- double downloadSize = torrentService.calculateDownloadSize(torrentId, userId);
+ try {
+ byte[] bytes = URLDecoder.decode(request.getQueryString().split("info_hash=")[1].split("&")[0], StandardCharsets.ISO_8859_1).getBytes(StandardCharsets.ISO_8859_1);
+ String infoHash = TorrentUtils.byteArrayToHexString(bytes);
- // 记录下载
- torrentService.recordDownload(torrentId, userId, downloadSize);
+ trackerProtocol.setInfo_hash(infoHash);
+ TorrentEntity torrent = torrentService.selectByInfoHash(infoHash);
+ if (torrent == null) {
+ throw new RuntimeException("种子不存在");
+ }
+ Integer userId = trackerProtocol.getUserId();
- return ResponseEntity.ok().build();
+ TorrentReport report = TorrentReport.builder()
+ .userId(userId )
+ .torrentId(torrent.getId())
+ .peerId(trackerProtocol.getPeer_id())
+ .infoHash(infoHash)
+ .build();
+ BeanUtils.copyProperties(trackerProtocol, report);
+ torrentReportRepository.save(report);
+synchronized (this){
+
+ boolean isAdded = peers.stream().anyMatch(m -> {
+ try{
+ Map<String, BEValue> map1 = m.getMap();
+ return map1.get("ip").getString().equals(trackerProtocol.getIp()) && map1.get("port").getInt() == trackerProtocol.getPort();
+ }catch (Exception e){
+ return false;
+ }
+ });
+ log.info("client report: {}", trackerProtocol);
+ map.put("interval", new BEValue(30));
+ map.put("peers", new BEValue(peers));
+ peers.forEach(p -> {
+ try {
+ Map<String, BEValue> map1 = p.getMap();
+ log.info("Peer info: ip={}, port={}, id={}", map1.get("ip").getString(), map1.get("port").getInt(), map1.get("peer id").getString());
+ }catch (Exception e){
+ log.error("Print Peer info error", e);
+ }
+
+ });
+ ByteBuffer bencode = BEncoder.bencode(map);
+ if(!isAdded){
+ log.info("New peer added.");
+ Map<String, BEValue> p = new HashMap<>(3);
+ p.put("ip", new BEValue(trackerProtocol.getIp()));
+ p.put("peer id", new BEValue(trackerProtocol.getPeer_id()));
+ p.put("port", new BEValue(trackerProtocol.getPort()));
+ peers.add(new BEValue(p));
+ }
+
+ return ResponseEntity.ok(bencode.array());
+}
+
+ }catch (Exception e){
+ try{
+ String message = e.getMessage();
+ message = message == null ? "" : message;
+ log.error("announce error", e);
+ map.put("failure reason", new BEValue(message , "UTF-8"));
+ return ResponseEntity.ok(BEncoder.bencode(map).array());
+ }catch (Exception ex){
+ log.error("announce error ", ex);
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal Server Error".getBytes());
+ }
+ }
}
-
-
}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/controller/UserController.java b/src/main/java/com/example/myproject/controller/UserController.java
index 6b3d793..41a3350 100644
--- a/src/main/java/com/example/myproject/controller/UserController.java
+++ b/src/main/java/com/example/myproject/controller/UserController.java
@@ -1,21 +1,180 @@
+// package com.example.myproject.controller;
+
+// import com.example.myproject.entity.Users;
+// import com.example.myproject.repository.UserRepository;
+// import com.example.myproject.service.DynamicService;
+// import com.example.myproject.service.TaskService;
+// import com.example.myproject.service.UserService;
+// import org.springframework.beans.factory.annotation.Autowired;
+// import org.springframework.http.ResponseEntity;
+// import org.springframework.web.bind.annotation.*;
+// import org.springframework.web.multipart.MultipartFile;
+
+// import javax.servlet.http.HttpServletRequest;
+// import java.util.Map;
+// import java.util.Optional;
+
+// import java.util.List;
+// import java.util.ArrayList;
+
+
+// @RestController
+// @RequestMapping("/echo/user")
+// public class UserController {
+
+// @Autowired
+// private UserService userService;
+
+// @Autowired
+// private UserRepository userRepository;
+
+// @Autowired
+// private DynamicService dynamicService;
+
+// // 接口:生成邀请码
+// @PostMapping("/getInviteCode")
+// public Map<String, Object> generateInviteCode(@RequestBody Map<String, Object> request) {
+// Long userId = Long.parseLong(request.get("user_id").toString());
+// return userService.generateInviteCode(userId);
+// }
+
+// //注册
+// @PostMapping("/register")
+// public Map<String, Object> register(@RequestBody Map<String, Object> request) {
+// String username = (String) request.get("username");
+// String email = (String) request.get("email");
+// String password = (String) request.get("password");
+// String role = (String) request.get("role");
+// String inviteCode = (String) request.get("inviteCode");
+
+// // 调用服务层的注册方法
+// String resultMessage = userService.registerUser(username, email, password, role, inviteCode);
+
+// // 返回注册结果
+// return Map.of("msg", resultMessage);
+// }
+
+// //登录
+// @PostMapping("/login")
+// public Map<String, Object> login(@RequestBody Map<String, Object> request) {
+// String username = (String) request.get("username");
+// String password = (String) request.get("password");
+
+// // 调用服务层的登录方法
+// String resultMessage = userService.loginUser(username, password);
+
+// // 根据登录结果返回不同的响应
+// if (resultMessage.equals("登录成功")) {
+// // 查询用户信息
+// Optional<Users> user = userRepository.findByUsername(username);
+// if (user.isPresent()) {
+// // 将用户的所有信息作为返回值
+// return Map.of("msg", resultMessage, "user", user.get());
+// } else {
+// return Map.of("msg", "用户信息查询失败");
+// }
+// } else {
+// return Map.of("msg", resultMessage);
+// }
+// }
+
+// //修改密码
+// @PostMapping("/password")
+// public Map<String, Object> changePassword(@RequestBody Map<String, Object> request) {
+// Long userId = Long.parseLong(request.get("user_id").toString());
+// String oldPassword = (String) request.get("old_password");
+// String newPassword = (String) request.get("new_password");
+// String confirmPassword = (String) request.get("confirm_password");
+
+// // 调用服务层的修改密码方法
+// String resultMessage = userService.changePassword(userId, oldPassword, newPassword, confirmPassword);
+
+// // 返回修改结果
+// return Map.of("message", resultMessage, "status", resultMessage.equals("密码修改成功") ? "success" : "error");
+// }
+
+// // 获取用户个人资料
+// @GetMapping("/{userId}/getProfile")
+// public Map<String, Object> getProfile(@PathVariable("userId") Long userId) {
+// return userService.getProfile(userId);
+// }
+
+// // 修改用户个人资料
+// @PutMapping("/{userId}/editProfile")
+// public Map<String, String> editProfile(
+// @PathVariable("userId") Long userId,
+// @RequestBody Map<String, Object> profileData) {
+
+// // 获取请求体中的修改数据
+// String nickname = (String) profileData.get("nickname");
+// String gender = (String) profileData.get("gender");
+// String description = (String) profileData.get("description");
+// String hobbies = (String) profileData.get("hobbies");
+
+// // 调用服务层方法进行修改
+// boolean updated = userService.editProfile(userId, nickname, gender, description, hobbies);
+
+// // 返回操作结果消息
+// if (updated) {
+// return Map.of("message", "用户资料更新成功");
+// } else {
+// return Map.of("message", "用户不存在");
+// }
+// }
+
+// // 计算分享率
+// @GetMapping("/{user_id}/calculate-share-rate")
+// public Map<String, Object> calculateShareRate(@PathVariable("user_id") Long userId) {
+// return userService.calculateShareRate(userId);
+// }
+
+// // 获取用户所有好友的基本信息
+// @GetMapping("/{userId}/friends")
+// public List<Map<String, Object>> getUserFriends(@PathVariable("userId") Long userId) {
+// List<Long> friendIds = dynamicService.getAllFriendIds(userId); // 注意这里用的是实例对象
+// List<Map<String, Object>> friends = new ArrayList<>();
+
+// for (Long friendId : friendIds) {
+// Optional<Users> userOpt = userRepository.findById(friendId);
+// if (userOpt.isPresent()) {
+// Users user = userOpt.get();
+// Map<String, Object> friendInfo = Map.of(
+// "id", user.getUserId(),
+// "avatar", user.getAvatarUrl() != null ? user.getAvatarUrl() : "https://example.com/default-avatar.jpg",
+// "nickname", user.getUsername() != null ? user.getUsername() : "未知用户",
+// "email", user.getEmail() != null ? user.getEmail() : "未填写"
+// );
+// friends.add(friendInfo);
+// }
+// }
+
+// return friends;
+// }
+
+// @PostMapping("/{userId}/uploadAvatar")
+// public Map<String, Object> uploadAvatar(
+// @PathVariable Long userId,
+// @RequestParam("file") MultipartFile file) {
+// return userService.uploadUserAvatar(userId, file);
+// }
+
+
+
+// }
+
package com.example.myproject.controller;
+import com.example.myproject.entity.FriendRelation;
import com.example.myproject.entity.Users;
+import com.example.myproject.repository.FriendRelationRepository;
import com.example.myproject.repository.UserRepository;
import com.example.myproject.service.DynamicService;
-import com.example.myproject.service.TaskService;
import com.example.myproject.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
-import javax.servlet.http.HttpServletRequest;
-import java.util.Map;
-import java.util.Optional;
-
-import java.util.List;
-import java.util.ArrayList;
+import java.util.*;
@RestController
@@ -31,6 +190,41 @@
@Autowired
private DynamicService dynamicService;
+ @Autowired
+ private FriendRelationRepository friendRelationRepository;
+
+
+ @PostMapping ("/addFriend")
+ public Map<String, Object> addFriend(@RequestBody Map<String, Object> request) {
+ //邮箱查用户
+ Optional<Users> userOptional = userRepository.findByEmail(request.get("email").toString());
+ // 如果用户不存在,返回null或者可以抛出异常
+ if (userOptional.isEmpty()) {
+ return Map.of("msg", "没有找到该用户"); // 可以返回 null 或者根据需要返回错误信息
+ }
+ Long userId = Long.parseLong(request.get("userid").toString()); //id查用户
+ Map<String, Object> users = userService.getProfile(userId);
+ // 如果用户不存在,返回null或者可以抛出异常
+ if (users.isEmpty()) {
+ return Map.of("msg", "当前登录账号异常"); // 可以返回 null 或者根据需要返回错误信息
+ }
+
+ FriendRelation newFriendRelation = new FriendRelation();
+ newFriendRelation.setUserId(userId);
+ newFriendRelation.setCreateTime(new Date());
+ newFriendRelation.setFriendId(userOptional.get().getUserId());
+
+ FriendRelation newFriendRelations = new FriendRelation();
+ newFriendRelations.setCreateTime(new Date());
+ newFriendRelations.setUserId(userOptional.get().getUserId());
+ newFriendRelations.setFriendId(userId);
+
+ friendRelationRepository.save(newFriendRelation);
+ friendRelationRepository.save(newFriendRelations);
+
+ return Map.of("msg", "添加成功");
+ }
+
// 接口:生成邀请码
@PostMapping("/getInviteCode")
public Map<String, Object> generateInviteCode(@RequestBody Map<String, Object> request) {
@@ -163,3 +357,7 @@
}
+
+
+
+
diff --git a/src/main/java/com/example/myproject/dto/TrackerProtocol.java b/src/main/java/com/example/myproject/dto/TrackerProtocol.java
new file mode 100644
index 0000000..0d97ab7
--- /dev/null
+++ b/src/main/java/com/example/myproject/dto/TrackerProtocol.java
@@ -0,0 +1,16 @@
+package com.example.myproject.dto;
+
+import lombok.Data;
+
+@Data
+public class TrackerProtocol {
+ private String info_hash;
+ private String peer_id;
+ private Integer userId;
+ private String ip;
+ private int port;
+ private long uploaded;
+ private long downloaded;
+ private long left;
+ private String event;
+}
diff --git a/src/main/java/com/example/myproject/entity/TorrentReport.java b/src/main/java/com/example/myproject/entity/TorrentReport.java
new file mode 100644
index 0000000..a019f9e
--- /dev/null
+++ b/src/main/java/com/example/myproject/entity/TorrentReport.java
@@ -0,0 +1,28 @@
+package com.example.myproject.entity;
+
+import lombok.Builder;
+import lombok.Data;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Data
+@Builder
+@Entity
+public class TorrentReport {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id;
+ private Integer userId;
+ private String peerId;
+ private Long torrentId;
+ private String infoHash;
+ private Long uploaded;
+ private Long downloaded;
+ @Column(name = "`left`")
+ private Long left;
+ private String event;
+ private String ip;
+ private Integer port;
+ private LocalDateTime reportTime;
+}
diff --git a/src/main/java/com/example/myproject/entity/User.java b/src/main/java/com/example/myproject/entity/User.java
index 7574e67..71ccfe1 100644
--- a/src/main/java/com/example/myproject/entity/User.java
+++ b/src/main/java/com/example/myproject/entity/User.java
@@ -1,3 +1,80 @@
+//package com.example.myproject.entity;
+//
+//
+//import com.baomidou.mybatisplus.annotation.IdType;
+//import com.baomidou.mybatisplus.annotation.TableId;
+//import com.baomidou.mybatisplus.annotation.TableName;
+//import com.fasterxml.jackson.annotation.JsonProperty;
+//import io.swagger.annotations.ApiModel;
+//import io.swagger.annotations.ApiModelProperty;
+//import lombok.Data;
+//
+//import java.time.LocalDateTime;
+//
+//@Data
+//@TableName("user") // 指定数据库表名
+//@ApiModel("用户实体类") // 用于描述模型
+//public class User {
+//
+// @TableId(type = IdType.AUTO) // 指定主键策略
+// @ApiModelProperty(value = "用户ID", example = "1")
+// private Long id;
+//
+// @JsonProperty("username")
+// @ApiModelProperty(value = "用户名", example = "22301115")
+// private String username;
+//
+// @JsonProperty("nickname")
+// @ApiModelProperty(value = "昵称", example = "cyl")
+// private String nickname;
+//
+// @JsonProperty("role")
+// @ApiModelProperty(value = "角色", example = "Student")
+// private String role;
+//
+// @JsonProperty("password")
+// @ApiModelProperty(value = "密码", example = "123")
+// private String password;
+//
+// @JsonProperty("status")
+// @ApiModelProperty(value = "用户状态", example = "1")
+// private int status;
+//
+// @JsonProperty("email")
+// @ApiModelProperty(value = "电子邮件地址", example = "john_doe@example.com")
+// private String email;
+//
+// @JsonProperty("email_verified")
+// @ApiModelProperty(value = "邮箱验证状态", example = "true")
+// private boolean emailVerified;
+//
+// @JsonProperty("avatar")
+// @ApiModelProperty(value = "头像")
+// private String avatar;
+//
+// @JsonProperty("uploaded")
+// @ApiModelProperty(value = "上传量", example = "1000")
+// private Long uploaded;
+//
+// @JsonProperty("downloaded")
+// @ApiModelProperty(value = "下载量", example = "500")
+// private Long downloaded;
+//
+// @JsonProperty("create_time")
+// @ApiModelProperty(value = "创建时间", example = "2024-04-01T12:00:00")
+// private LocalDateTime createTime;
+//
+// @JsonProperty("update_time")
+// @ApiModelProperty(value = "更新时间", example = "2024-04-01T12:00:00")
+// private LocalDateTime updateTime;
+//
+// @JsonProperty("is_deleted")
+// @ApiModelProperty(value = "是否删除", example = "false")
+// private Boolean isDeleted;
+//
+// public User() {
+// }
+//}
package com.example.myproject.entity;
diff --git a/src/main/java/com/example/myproject/entity/Users.java b/src/main/java/com/example/myproject/entity/Users.java
index ebe793f..f1d0316 100644
--- a/src/main/java/com/example/myproject/entity/Users.java
+++ b/src/main/java/com/example/myproject/entity/Users.java
@@ -1,246 +1,246 @@
-package com.example.myproject.entity;
+ package com.example.myproject.entity;
-import javax.persistence.*;
-import java.util.Date;
+ import javax.persistence.*;
+ import java.util.Date;
-@Entity
-@Table(name = "user")
-public class Users {
+ @Entity
+ @Table(name = "user")
+ public class Users {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name = "user_id")
- private Long userId;
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "user_id")
+ private Long userId;
- @Column(name = "username", nullable = false,unique = true)
- private String username;
+ @Column(name = "username", nullable = false,unique = true)
+ private String username;
- @Column(name = "avatar_url", nullable = true)
- private String avatarUrl;
+ @Column(name = "avatar_url", nullable = true)
+ private String avatarUrl;
- @Column(name = "email", nullable = false)
- private String email;
+ @Column(name = "email", nullable = false)
+ private String email;
- @Column(name = "password", nullable = false)
- private String password;
+ @Column(name = "password", nullable = false)
+ private String password;
- @Column(name = "role", nullable = false)
- private String role;
+ @Column(name = "role", nullable = false)
+ private String role;
- @Column(name = "invite_count")
- private Integer inviteCount;
+ @Column(name = "invite_count")
+ private Integer inviteCount;
- @Column(name = "level", nullable = false)
- private Long level;
+ @Column(name = "level", nullable = false)
+ private Long level;
- @Column(name = "upload_count")
- private Float uploadCount;
+ @Column(name = "upload_count")
+ private Float uploadCount;
- @Column(name = "download_count")
- private Float downloadCount;
+ @Column(name = "download_count")
+ private Float downloadCount;
- @Column(name = "share_rate")
- private Float shareRate;
+ @Column(name = "share_rate")
+ private Float shareRate;
- @Column(name = "registration_date", nullable = false)
- private Date registrationDate;
+ @Column(name = "registration_date", nullable = false)
+ private Date registrationDate;
- @Column(name = "last_login_time")
- private Date lastLoginTime;
+ @Column(name = "last_login_time")
+ private Date lastLoginTime;
- @Column(name = "user_points")
- private Integer userPoints;
+ @Column(name = "user_points")
+ private Integer userPoints;
- @Column(name = "is_promo")
- private Boolean isPromo;
+ @Column(name = "is_promo")
+ private Boolean isPromo;
- @Column(name = "current_experience", nullable = false)
- private Integer currentExperience; // 当前经验值
+ @Column(name = "current_experience", nullable = false)
+ private Integer currentExperience; // 当前经验值
- @Column(name = "current_seeding_hours", nullable = false)
- private Float currentSeedingHours; // 当前做种时长
+ @Column(name = "current_seeding_hours", nullable = false)
+ private Float currentSeedingHours; // 当前做种时长
- @Column(name = "gender", nullable = true)
- private String gender; // 性别
+ @Column(name = "gender", nullable = true)
+ private String gender; // 性别
- @Column(name = "description", nullable = true)
- private String description; // 个人描述
+ @Column(name = "description", nullable = true)
+ private String description; // 个人描述
- @Column(name = "hobbies", nullable = true)
- private String hobbies;
+ @Column(name = "hobbies", nullable = true)
+ private String hobbies;
- @Column(name = "registration_time", nullable = false, updatable = false)
- @Temporal(TemporalType.TIMESTAMP)
- private Date registrationTime;
+ @Column(name = "registration_time", nullable = false, updatable = false)
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date registrationTime;
- // Getters and Setters
- public Long getUserId() {
- return userId;
- }
+ // Getters and Setters
+ public Long getUserId() {
+ return userId;
+ }
- public void setUserId(Long userId) {
- this.userId = userId;
- }
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
- public String getUsername() {
- return username;
- }
+ public String getUsername() {
+ return username;
+ }
- public void setUsername(String username) {
- this.username = username;
- }
+ public void setUsername(String username) {
+ this.username = username;
+ }
- public String getAvatarUrl() {
- return avatarUrl;
- }
+ public String getAvatarUrl() {
+ return avatarUrl;
+ }
- public void setAvatarUrl(String avatarUrl) {
- this.avatarUrl = avatarUrl;
- }
+ public void setAvatarUrl(String avatarUrl) {
+ this.avatarUrl = avatarUrl;
+ }
- public String getEmail() {
- return email;
- }
+ public String getEmail() {
+ return email;
+ }
- public void setEmail(String email) {
- this.email = email;
- }
+ public void setEmail(String email) {
+ this.email = email;
+ }
- public String getPassword() {
- return password;
- }
+ public String getPassword() {
+ return password;
+ }
- public void setPassword(String password) {
- this.password = password;
- }
+ public void setPassword(String password) {
+ this.password = password;
+ }
- public String getRole() {
- return role;
- }
+ public String getRole() {
+ return role;
+ }
- public void setRole(String role) {
- this.role = role;
- }
+ public void setRole(String role) {
+ this.role = role;
+ }
- public Integer getInviteCount() {
- return inviteCount;
- }
+ public Integer getInviteCount() {
+ return inviteCount;
+ }
- public void setInviteCount(Integer inviteCount) {
- this.inviteCount = inviteCount;
- }
+ public void setInviteCount(Integer inviteCount) {
+ this.inviteCount = inviteCount;
+ }
- public Long getLevel() {
- return level;
- }
+ public Long getLevel() {
+ return level;
+ }
- public void setLevel(Long level) {
- this.level = level;
- }
+ public void setLevel(Long level) {
+ this.level = level;
+ }
- public Float getUploadCount() {
- return uploadCount;
- }
+ public Float getUploadCount() {
+ return uploadCount;
+ }
- public void setUploadCount(Float uploadCount) {
- this.uploadCount = uploadCount;
- }
+ public void setUploadCount(Float uploadCount) {
+ this.uploadCount = uploadCount;
+ }
- public Float getDownloadCount() {
- return downloadCount;
- }
+ public Float getDownloadCount() {
+ return downloadCount;
+ }
- public void setDownloadCount(Float downloadCount) {
- this.downloadCount = downloadCount;
- }
+ public void setDownloadCount(Float downloadCount) {
+ this.downloadCount = downloadCount;
+ }
- public Float getShareRate() {
- return shareRate;
- }
+ public Float getShareRate() {
+ return shareRate;
+ }
- public void setShareRate(Float shareRate) {
- this.shareRate = shareRate;
- }
+ public void setShareRate(Float shareRate) {
+ this.shareRate = shareRate;
+ }
- public Date getRegistrationDate() {
- return registrationDate;
- }
+ public Date getRegistrationDate() {
+ return registrationDate;
+ }
- public void setRegistrationDate(Date registrationDate) {
- this.registrationDate = registrationDate;
- }
+ public void setRegistrationDate(Date registrationDate) {
+ this.registrationDate = registrationDate;
+ }
- public Date getLastLoginTime() {
- return lastLoginTime;
- }
+ public Date getLastLoginTime() {
+ return lastLoginTime;
+ }
- public void setLastLoginTime(Date lastLoginTime) {
- this.lastLoginTime = lastLoginTime;
- }
+ public void setLastLoginTime(Date lastLoginTime) {
+ this.lastLoginTime = lastLoginTime;
+ }
- public Integer getUserPoints() {
- return userPoints;
- }
+ public Integer getUserPoints() {
+ return userPoints;
+ }
- public void setUserPoints(Integer userPoints) {
- this.userPoints = userPoints;
- }
+ public void setUserPoints(Integer userPoints) {
+ this.userPoints = userPoints;
+ }
- public Boolean getIsPromo() {
- return isPromo;
- }
+ public Boolean getIsPromo() {
+ return isPromo;
+ }
- public void setIsPromo(Boolean isPromo) {
- this.isPromo = isPromo;
- }
+ public void setIsPromo(Boolean isPromo) {
+ this.isPromo = isPromo;
+ }
- public Integer getCurrentExperience() {
- return currentExperience;
- }
+ public Integer getCurrentExperience() {
+ return currentExperience;
+ }
- public void setCurrentExperience(Integer currentExperience) {
- this.currentExperience = currentExperience;
- }
+ public void setCurrentExperience(Integer currentExperience) {
+ this.currentExperience = currentExperience;
+ }
- public Float getCurrentSeedingHours() {
- return currentSeedingHours;
- }
+ public Float getCurrentSeedingHours() {
+ return currentSeedingHours;
+ }
- public void setCurrentSeedingHours(Float currentSeedingHours) {
- this.currentSeedingHours = currentSeedingHours;
- }
+ public void setCurrentSeedingHours(Float currentSeedingHours) {
+ this.currentSeedingHours = currentSeedingHours;
+ }
- public String getGender() {
- return gender;
- }
+ public String getGender() {
+ return gender;
+ }
- public void setGender(String gender) {
- this.gender = gender;
- }
+ public void setGender(String gender) {
+ this.gender = gender;
+ }
- public String getDescription() {
- return description;
- }
+ public String getDescription() {
+ return description;
+ }
- public void setDescription(String description) {
- this.description = description;
- }
+ public void setDescription(String description) {
+ this.description = description;
+ }
- public String getHobbies() {
- return hobbies;
- }
+ public String getHobbies() {
+ return hobbies;
+ }
- public void setHobbies(String hobbies) {
- this.hobbies = hobbies;
- }
+ public void setHobbies(String hobbies) {
+ this.hobbies = hobbies;
+ }
- public Date getRegistrationTime() {
- return registrationTime;
- }
+ public Date getRegistrationTime() {
+ return registrationTime;
+ }
- public void setRegistrationTime(Date registrationTime) {
- this.registrationTime = registrationTime;
- }
+ public void setRegistrationTime(Date registrationTime) {
+ this.registrationTime = registrationTime;
+ }
-}
+ }
diff --git a/src/main/java/com/example/myproject/repository/TorrentReportRepository.java b/src/main/java/com/example/myproject/repository/TorrentReportRepository.java
new file mode 100644
index 0000000..9484d20
--- /dev/null
+++ b/src/main/java/com/example/myproject/repository/TorrentReportRepository.java
@@ -0,0 +1,7 @@
+package com.example.myproject.repository;
+
+import com.example.myproject.entity.TorrentReport;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface TorrentReportRepository extends JpaRepository<TorrentReport, Integer> {
+}
diff --git a/src/main/java/com/example/myproject/service/DynamicService.java b/src/main/java/com/example/myproject/service/DynamicService.java
index 853604d..9190d57 100644
--- a/src/main/java/com/example/myproject/service/DynamicService.java
+++ b/src/main/java/com/example/myproject/service/DynamicService.java
@@ -1,3 +1,278 @@
+// package com.example.myproject.service;
+
+// import com.example.myproject.entity.*;
+// import com.example.myproject.repository.*;
+// import org.springframework.beans.factory.annotation.Autowired;
+// import org.springframework.stereotype.Service;
+// import org.springframework.web.multipart.MultipartFile;
+
+// import java.io.IOException;
+// import java.nio.file.Files;
+// import java.nio.file.Path;
+// import java.nio.file.Paths;
+// import java.util.*;
+
+// @Service
+// public class DynamicService {
+
+// @Autowired
+// private UserDynamicRepository userDynamicRepository;
+
+// @Autowired
+// private UserRepository userRepository;
+
+// @Autowired
+// private DynamicCommentRepository dynamicCommentRepository;
+
+// @Autowired
+// private DynamicLikesRepository dynamicLikesRepository;
+
+// @Autowired
+// private FriendRelationRepository friendRelationRepository;
+
+// private static final String IMAGE_DIR = "uploads/post/";
+
+// // 创建好友动态
+// public Map<String, Object> createDynamic(Long userId, String title, String content, MultipartFile[] imageFiles) {
+// // 查找用户信息
+// Users user = userRepository.findById(userId)
+// .orElseThrow(() -> new RuntimeException("User not found"));
+
+// // 创建新的动态
+// UserDynamic userDynamic = new UserDynamic();
+// userDynamic.setUserId(userId);
+// userDynamic.setTitle(title != null ? title : "默认标题");
+// userDynamic.setContent(content);
+// userDynamic.setTime(new Date());
+// userDynamic.setLikesCount(0);
+// userDynamic.setCommentsCount(0);
+
+// // 处理图片上传
+// StringBuilder imageUrlsBuilder = new StringBuilder();
+// if (imageFiles != null && imageFiles.length > 0) {
+// for (int i = 0; i < imageFiles.length; i++) {
+// if (i > 0) {
+// imageUrlsBuilder.append(",");
+// }
+// try {
+// String imageUrl = saveImage(imageFiles[i]);
+// imageUrlsBuilder.append(imageUrl);
+// } catch (IOException e) {
+// throw new RuntimeException("Image upload failed: " + e.getMessage());
+// }
+// }
+// }
+
+// // 将多个图片 URL 拼接
+// userDynamic.setImageUrl(imageUrlsBuilder.toString());
+
+// // 保存数据库
+// UserDynamic savedUserDynamic = userDynamicRepository.save(userDynamic);
+
+// // 返回结果
+// Map<String, Object> response = new HashMap<>();
+// response.put("dynamicId", savedUserDynamic.getDynamicId());
+// response.put("message", "动态创建成功");
+// return response;
+// }
+
+// // 保存图片并返回图片的 URL
+// public String saveImage(MultipartFile imageFile) throws IOException {
+// String fileName = imageFile.getOriginalFilename();
+// Path path = Paths.get(IMAGE_DIR + fileName);
+// Files.createDirectories(path.getParent());
+// Files.write(path, imageFile.getBytes());
+// return "/images/" + fileName;
+// }
+
+// // 删除动态
+// public void deleteDynamic(Long dynamicId) {
+// if (userDynamicRepository.existsById(dynamicId)) {
+// userDynamicRepository.deleteById(dynamicId);
+// } else {
+// throw new RuntimeException("Dynamic with id " + dynamicId + " not found");
+// }
+// }
+
+// //好友动态评论
+// public Map<String, Object> addComment(Long userId, Long dynamicId, String commentContent) {
+// Users user = userRepository.findById(userId)
+// .orElseThrow(() -> new RuntimeException("User not found"));
+
+// UserDynamic dynamic = userDynamicRepository.findById(dynamicId)
+// .orElseThrow(() -> new RuntimeException("Dynamic not found"));
+
+// DynamicComment comment = new DynamicComment();
+// comment.setDynamicId(dynamicId);
+// comment.setUserId(userId);
+// comment.setCommentContent(commentContent);
+// comment.setCommentTime(new Date());
+
+// // 保存评论
+// DynamicComment savedComment = dynamicCommentRepository.save(comment);
+
+// // 返回成功消息
+// Map<String, Object> response = new HashMap<>();
+// response.put("comment_id", savedComment.getCommentId());
+// response.put("message", "评论成功");
+// return response;
+// }
+
+// //返回某个好友的所有动态
+// public Map<String, Object> getAllUserDynamics(Long userId) {
+// // 查找用户的所有动态
+// List<UserDynamic> userDynamics = userDynamicRepository.findByUserId(userId);
+// Map<String, Object> postData = new LinkedHashMap<>();
+// List<Map<String, Object>> dynamicList = new ArrayList<>();
+
+// // 遍历动态,获取点赞和评论
+// for (UserDynamic dynamic : userDynamics) {
+// Map<String, Object> dynamicData = new LinkedHashMap<>();
+// dynamicData.put("dynamic_id", dynamic.getDynamicId());
+// dynamicData.put("user_id", dynamic.getUserId());
+
+// Users user = userRepository.findById(dynamic.getUserId()).orElse(null);
+// if (user != null) {
+// dynamicData.put("username", user.getUsername());
+// dynamicData.put("avatar_url", user.getAvatarUrl());
+// } else {
+// dynamicData.put("username", "Unknown");
+// dynamicData.put("avatar_url", "http://example.com/default-avatar.jpg");
+// }
+
+// dynamicData.put("title", dynamic.getTitle());
+// dynamicData.put("content", dynamic.getContent());
+// dynamicData.put("images", dynamic.getImageUrl());
+// dynamicData.put("time", dynamic.getTime());
+
+// // 获取点赞
+// List<DynamicLikes> likes = dynamicLikesRepository.findByDynamicId(dynamic.getDynamicId());
+// List<Map<String, Object>> likeList = new ArrayList<>();
+// for (DynamicLikes like : likes) {
+// Map<String, Object> likeData = new HashMap<>();
+// likeData.put("user_id", like.getUserId());
+
+// // 获取点赞用户的用户名
+// Users likeUser = userRepository.findById(like.getUserId()).orElse(null);
+// if (likeUser != null) {
+// likeData.put("username", likeUser.getUsername());
+// } else {
+// likeData.put("username", "Unknown");
+// }
+
+// likeList.add(likeData);
+// }
+// dynamicData.put("likes", likeList);
+
+// // 获取评论
+// List<DynamicComment> comments = dynamicCommentRepository.findByDynamicId(dynamic.getDynamicId());
+// List<Map<String, Object>> commentList = new ArrayList<>();
+// for (DynamicComment comment : comments) {
+// Map<String, Object> commentData = new HashMap<>();
+// commentData.put("comment_id", comment.getCommentId());
+// commentData.put("user_id", comment.getUserId());
+
+// // 获取评论用户的用户名
+// Users commentUser = userRepository.findById(comment.getUserId()).orElse(null);
+// if (commentUser != null) {
+// commentData.put("username", commentUser.getUsername());
+// } else {
+// commentData.put("username", "Unknown");
+// }
+
+// commentData.put("content", comment.getCommentContent());
+// commentData.put("time", comment.getCommentTime());
+// commentList.add(commentData);
+// }
+// dynamicData.put("comments", commentList);
+
+// dynamicList.add(dynamicData);
+// }
+
+// Map<String, Object> response = new HashMap<>();
+// response.put("dynamic", dynamicList);
+// return response;
+// }
+
+// //获取当前所有好友的id
+// public List<Long> getAllFriendIds(Long userId) {
+// List<FriendRelation> friendRelations = friendRelationRepository.findByUserId(userId);
+// List<Long> friendIds = new ArrayList<>();
+
+// for (FriendRelation relation : friendRelations) {
+// // 添加好友ID
+// if (!friendIds.contains(relation.getFriendId())) {
+// friendIds.add(relation.getFriendId());
+// }
+// }
+
+// return friendIds;
+// }
+
+// public Map<String, Object> getAllUserAndFriendsDynamics(List<Long> userIds) {
+// List<Map<String, Object>> allDynamics = new ArrayList<>();
+
+// // 遍历所有用户获取他们的动态
+// for (Long userId : userIds) {
+// Map<String, Object> userDynamics = getAllUserDynamics(userId);
+// if (userDynamics != null && !userDynamics.isEmpty()) {
+// allDynamics.addAll((List<Map<String, Object>>) userDynamics.get("dynamic"));
+// }
+// }
+
+// // 返回所有动态的合集
+// Map<String, Object> response = new HashMap<>();
+// response.put("dynamic", allDynamics);
+// return response;
+// }
+
+// //点赞动态
+// public boolean likeDynamic(Long userId, Long dynamicId) {
+// // 检查该用户是否已经点赞过该动态
+// DynamicLikes existingLike = dynamicLikesRepository.findByUserIdAndDynamicId(userId, dynamicId);
+// if (existingLike != null) {
+// return false;
+// }
+
+// // 新增点赞记录
+// DynamicLikes newLike = new DynamicLikes();
+// newLike.setUserId(userId);
+// newLike.setDynamicId(dynamicId);
+// newLike.setLikeTime(new java.util.Date());
+// dynamicLikesRepository.save(newLike);
+
+// // 更新动态表的点赞数
+// UserDynamic dynamic = userDynamicRepository.findById(dynamicId).orElse(null);
+// if (dynamic != null) {
+// dynamic.setLikesCount(dynamic.getLikesCount() + 1);
+// userDynamicRepository.save(dynamic);
+// }
+
+// return true;
+// }
+
+// //取消点赞
+// public boolean unlikeDynamic(Long userId, Long dynamicId) {
+// // 查找该用户的点赞记录
+// DynamicLikes existingLike = dynamicLikesRepository.findByUserIdAndDynamicId(userId, dynamicId);
+// if (existingLike == null) {
+// return false;
+// }
+
+// // 删除点赞记录
+// dynamicLikesRepository.delete(existingLike);
+
+// // 更新动态表的点赞数
+// UserDynamic dynamic = userDynamicRepository.findById(dynamicId).orElse(null);
+// if (dynamic != null) {
+// dynamic.setLikesCount(dynamic.getLikesCount() - 1);
+// userDynamicRepository.save(dynamic);
+// }
+
+// return true;
+// }
+
+// }
package com.example.myproject.service;
import com.example.myproject.entity.*;
@@ -95,7 +370,7 @@
}
//好友动态评论
- public Map<String, Object> addComment(Long userId, Long dynamicId, String commentContent) {
+ public Map<String, Object> addComment(Long userId, Long dynamicId, String commentContent, Long parentCommentId) {
Users user = userRepository.findById(userId)
.orElseThrow(() -> new RuntimeException("User not found"));
@@ -107,6 +382,7 @@
comment.setUserId(userId);
comment.setCommentContent(commentContent);
comment.setCommentTime(new Date());
+ comment.setParentCommentId(parentCommentId); // 设置父评论ID
// 保存评论
DynamicComment savedComment = dynamicCommentRepository.save(comment);
@@ -114,10 +390,12 @@
// 返回成功消息
Map<String, Object> response = new HashMap<>();
response.put("comment_id", savedComment.getCommentId());
+ response.put("parent_comment_id", savedComment.getParentCommentId());
response.put("message", "评论成功");
return response;
}
+
//返回某个好友的所有动态
public Map<String, Object> getAllUserDynamics(Long userId) {
// 查找用户的所有动态
diff --git a/src/main/java/com/example/myproject/service/PostService.java b/src/main/java/com/example/myproject/service/PostService.java
index af032a5..5cacdc5 100644
--- a/src/main/java/com/example/myproject/service/PostService.java
+++ b/src/main/java/com/example/myproject/service/PostService.java
@@ -76,7 +76,7 @@
Path path = Paths.get(IMAGE_DIR + fileName);
Files.createDirectories(path.getParent());
Files.write(path, imageFile.getBytes());
- return "/images/" + fileName;
+ return "/uploads/post/" + fileName;
}
// 编辑帖子 - 添加 @Transactional
diff --git a/src/main/java/com/example/myproject/service/TorrentService.java b/src/main/java/com/example/myproject/service/TorrentService.java
index 941804d..36891d2 100644
--- a/src/main/java/com/example/myproject/service/TorrentService.java
+++ b/src/main/java/com/example/myproject/service/TorrentService.java
@@ -1,3 +1,40 @@
+// package com.example.myproject.service;
+
+// import com.example.myproject.common.base.Result;
+// import com.example.myproject.entity.TorrentEntity;
+// import com.example.myproject.dto.param.TorrentParam;
+// import com.example.myproject.dto.param.TorrentUploadParam;
+// import com.example.myproject.dto.TorrentUpdateDTO;
+// import org.springframework.web.multipart.MultipartFile;
+
+// import java.io.IOException;
+// import java.util.List;
+
+// public interface TorrentService {
+// List<TorrentEntity> search(TorrentParam param);
+
+// TorrentEntity selectBySeedId(Long seedId);
+
+// void uploadTorrent(MultipartFile file, TorrentUploadParam param) throws IOException;
+
+// byte[] fetch(Long seedId, String passkey) throws IOException;
+
+// Result favorite(Long seedId, Long userId);
+
+// void deleteTorrent(Long seedId);
+
+// void updateTorrent(Long seedId, TorrentUpdateDTO updateDTO);
+
+// boolean canUserDeleteTorrent(Long seedId, Long userId);
+
+// boolean canUserUpdateTorrent(Long seedId, Long userId);
+
+// boolean checkUserUploadRatio(Long userId);
+
+// double calculateDownloadSize(Long torrentId, Long userId);
+
+// void recordDownload(Long torrentId, Long userId, double downloadSize);
+// }
package com.example.myproject.service;
import com.example.myproject.common.base.Result;
@@ -34,4 +71,6 @@
double calculateDownloadSize(Long torrentId, Long userId);
void recordDownload(Long torrentId, Long userId, double downloadSize);
+
+ TorrentEntity selectByInfoHash(String infoHash);
}
diff --git a/src/main/java/com/example/myproject/service/UserService.java b/src/main/java/com/example/myproject/service/UserService.java
index 283a85c..de6bf8b 100644
--- a/src/main/java/com/example/myproject/service/UserService.java
+++ b/src/main/java/com/example/myproject/service/UserService.java
@@ -1,8 +1,10 @@
package com.example.myproject.service;
-
+import cn.dev33.satoken.stp.StpUtil;
+import com.example.myproject.entity.FriendRelation;
import com.example.myproject.entity.User;
import com.example.myproject.entity.Users;
import com.example.myproject.entity.UserInviteCode;
+import com.example.myproject.repository.FriendRelationRepository;
import com.example.myproject.repository.UserRepository;
import com.example.myproject.repository.UserInviteCodeRepository;
import org.springframework.beans.factory.annotation.Autowired;
@@ -27,6 +29,9 @@
@Autowired
private UserInviteCodeRepository userInviteCodeRepository;
+ @Autowired
+ private FriendRelationRepository friendRelationRepository;
+
// 生成邀请码
public Map<String, Object> generateInviteCode(Long userId) {
// 获取用户信息
@@ -135,6 +140,17 @@
// 保存用户信息
userRepository.save(newUser);
+ FriendRelation newFriendRelation = new FriendRelation();
+ newFriendRelation.setUserId(newUser.getUserId());
+ newFriendRelation.setCreateTime(new Date());
+ newFriendRelation.setFriendId(inviteUserId);
+
+ FriendRelation newFriendRelations = new FriendRelation();
+ newFriendRelations.setUserId(inviteUserId);
+ newFriendRelations.setCreateTime(new Date());
+ newFriendRelations.setFriendId(newUser.getUserId());
+ friendRelationRepository.save(newFriendRelation);
+ friendRelationRepository.save(newFriendRelations);
// 更新邀请码的使用状态
inviteEntity.setIsUsed(true);
userInviteCodeRepository.save(inviteEntity);
@@ -156,7 +172,8 @@
if (!user.getPassword().equals(password)) {
return "密码错误";
}
-
+ StpUtil.login(user.getUserId());
+
// 登录成功
return "登录成功";
}
diff --git a/src/main/java/com/example/myproject/service/serviceImpl/TorrentServiceImpl.java b/src/main/java/com/example/myproject/service/serviceImpl/TorrentServiceImpl.java
index cb26f7a..4870fd5 100644
--- a/src/main/java/com/example/myproject/service/serviceImpl/TorrentServiceImpl.java
+++ b/src/main/java/com/example/myproject/service/serviceImpl/TorrentServiceImpl.java
@@ -1,5 +1,305 @@
+// package com.example.myproject.service.serviceImpl;
+
+// import com.example.myproject.entity.TorrentEntity;
+// import com.example.myproject.entity.User;
+// import com.example.myproject.mapper.TorrentMapper;
+// import com.example.myproject.mapper.UserMapper;
+// import com.example.myproject.service.TorrentService;
+// import com.example.myproject.service.PromotionService;
+// import com.example.myproject.dto.param.TorrentParam;
+// import com.example.myproject.dto.param.TorrentUploadParam;
+// import com.example.myproject.dto.TorrentUpdateDTO;
+// import com.turn.ttorrent.bcodec.BDecoder;
+// import com.turn.ttorrent.bcodec.BEValue;
+// import com.turn.ttorrent.bcodec.BEncoder;
+// import com.turn.ttorrent.client.SimpleClient;
+// import com.turn.ttorrent.common.creation.MetadataBuilder;
+// import com.turn.ttorrent.tracker.Tracker;
+// import com.turn.ttorrent.tracker.TrackedTorrent;
+// import com.example.myproject.common.base.Result;
+
+// import com.turn.ttorrent.tracker.TrackedTorrent;
+// import org.apache.commons.codec.binary.Hex;
+// import org.springframework.beans.factory.annotation.Autowired;
+// import org.springframework.stereotype.Service;
+// import org.springframework.transaction.annotation.Transactional;
+// import org.springframework.web.multipart.MultipartFile;
+
+// import java.io.ByteArrayInputStream;
+// import java.io.ByteArrayOutputStream;
+// import java.io.IOException;
+// import java.net.InetAddress;
+// import java.nio.file.Files;
+// import java.nio.file.Path;
+// import java.nio.file.Paths;
+// import java.nio.file.StandardCopyOption;
+// import java.security.MessageDigest;
+// import java.security.NoSuchAlgorithmException;
+// import java.time.LocalTime;
+// import java.util.HashMap;
+// import java.util.List;
+// import java.util.Map;
+// import java.util.concurrent.ExecutorService;
+// import java.util.concurrent.Executors;
+
+// @Service
+// public class TorrentServiceImpl implements TorrentService {
+// @Autowired
+// private Tracker tracker;
+
+// @Autowired
+// private TorrentMapper torrentMapper;
+
+// private final Map<String, TrackedTorrent> torrentRegistry = new HashMap<>();
+
+
+// @Autowired
+// private UserMapper userMapper;
+
+// @Autowired
+// private PromotionService promotionService;
+
+// private static final double MIN_UPLOAD_RATIO = 0.5; // 最小上传比例要求
+
+// @Override
+// public List<TorrentEntity> search(TorrentParam param) {
+// return torrentMapper.search(param);
+// }
+
+// @Override
+// public TorrentEntity selectBySeedId(Long seedId) {
+// return torrentMapper.selectById(seedId);
+// }
+// private final ExecutorService seederExecutor = Executors.newCachedThreadPool();
+
+// @Override
+// @Transactional
+// public void uploadTorrent(MultipartFile file, TorrentUploadParam param) throws IOException {
+// // 验证用户权限
+// User user = userMapper.selectByUserId(Long.valueOf(param.getUploader()));
+// if (user == null) {
+// throw new RuntimeException("用户不存在");
+// }
+// String workingDir = System.getProperty("user.dir");
+// Path originalDir = Paths.get(workingDir, "data", "files");
+// Files.createDirectories(originalDir);
+// Path originalFilePath = originalDir.resolve(file.getOriginalFilename());
+// Files.copy(file.getInputStream(), originalFilePath, StandardCopyOption.REPLACE_EXISTING);
+
+// MetadataBuilder builder = new MetadataBuilder()
+// .addFile(originalFilePath.toFile(), file.getOriginalFilename()) // 添加原始文件
+// .setTracker(" ") // 设置Tracker地址
+// .setPieceLength(512 * 1024) // 分片大小512KB
+// .setComment("Generated by PT站")
+// .setCreatedBy("PT-Server");
+
+// // 处理种子文件
+// byte[] torrentBytes = file.getBytes();
+// String infoHash = null;
+// try {
+// infoHash = calculateInfoHash(torrentBytes);
+// } catch (NoSuchAlgorithmException e) {
+// throw new RuntimeException(e);
+// }
+
+// // 保存种子文件到data/torrents目录
+// Path torrentDir = Paths.get(workingDir, "data", "torrents");
+// Files.createDirectories(torrentDir);
+// Path torrentPath = torrentDir.resolve(infoHash + ".torrent");
+// Files.copy(new ByteArrayInputStream(torrentBytes), torrentPath, StandardCopyOption.REPLACE_EXISTING);
+
+// // 注册到Tracker
+// TrackedTorrent torrent = TrackedTorrent.load(torrentPath.toFile());
+// tracker.announce(torrent);
+
+
+// // 异步启动做种客户端
+// seederExecutor.submit(() -> {
+// try {
+// startSeeding(torrentPath, originalDir);
+// } catch (Exception e) {
+// Result.error("做种失败: " + e.getMessage());
+// }
+// });
+
+
+
+
+// // 保存种子信息
+// TorrentEntity entity= new TorrentEntity();
+// entity.setUploader(param.getUploader());
+// entity.setFileName(file.getOriginalFilename());
+// entity.setSize(file.getSize());
+// entity.setCategory(param.getCategory());
+// entity.setTags(param.getTags());
+// entity.setTitle(param.getTitle());
+// entity.setImageUrl(param.getImageUrl());
+// entity.setTorrentFile(torrentBytes);
+// entity.setInfoHash(infoHash);
+
+// torrentMapper.insert(entity);
+// }
+
+// @Override
+// public byte[] fetch(Long seedId, String passkey) {
+// TorrentEntity torrent = selectBySeedId(seedId);
+// if (torrent == null) {
+// throw new RuntimeException("种子不存在");
+// }
+
+// byte[] torrentBytes = torrent.getTorrentFile();
+
+// try {
+// // 1. 解码 .torrent 文件为 Map
+// Map<String, BEValue> decoded = BDecoder.bdecode(new ByteArrayInputStream(torrentBytes)).getMap();
+
+// // 2. 获取原始 announce 字段
+// String announce = decoded.get("announce").getString();
+
+// // 3. 注入 passkey 到 announce URL
+// if (!announce.contains("passkey=")) {
+// announce = announce + "?passkey=" + passkey;
+// decoded.put("announce", new BEValue(announce));
+// }
+
+// // 4. 编码成新的 .torrent 文件字节数组
+// ByteArrayOutputStream out = new ByteArrayOutputStream();
+// BEncoder.bencode(decoded, out);
+// return out.toByteArray();
+
+// } catch (Exception e) {
+// throw new RuntimeException("处理 torrent 文件失败", e);
+// }
+// }
+
+// @Override
+// @Transactional
+// public Result favorite(Long seedId, Long userId) {
+// try {
+// boolean exists = torrentMapper.checkFavorite(seedId, userId);
+// if (exists) {
+// torrentMapper.removeFavorite(seedId, userId);
+// return Result.success("取消收藏成功");
+// } else {
+// torrentMapper.addFavorite(seedId, userId);
+// return Result.success("收藏成功");
+// }
+// } catch (Exception e) {
+// return Result.error("失败: " + e.getMessage());
+// }
+// }
+
+// @Override
+// @Transactional
+// public void deleteTorrent(Long seedId) {
+// torrentMapper.deleteById(seedId);
+// }
+
+// @Override
+// @Transactional
+// public void updateTorrent(Long seedId, TorrentUpdateDTO updateDTO) {
+// TorrentEntity torrent = selectBySeedId(seedId);
+// if (torrent == null) {
+// throw new RuntimeException("种子不存在");
+// }
+
+
+// torrent.setDescription(updateDTO.getDescription());
+// torrent.setCategory(updateDTO.getCategory());
+// torrent.setTitle(updateDTO.getTitle());
+// torrent.setTags(updateDTO.getTags());
+// torrent.setImageUrl(updateDTO.getImageUrl());
+
+// torrentMapper.updateById(torrent);
+// }
+
+// @Override
+// public boolean canUserDeleteTorrent(Long seedId, Long userId) {
+// TorrentEntity torrent = selectBySeedId(seedId);
+// if (torrent == null) {
+// return false;
+// }
+
+// // 检查是否是种子发布者或管理员
+// return torrent.getUploader().equals(userId) ||
+// userMapper.hasRole(userId, "admin");
+// }
+
+// @Override
+// public boolean canUserUpdateTorrent(Long seedId, Long userId) {
+// return canUserDeleteTorrent(seedId, userId);
+// }
+
+// @Override
+// public boolean checkUserUploadRatio(Long userId) {
+// User user = userMapper.selectById(userId);
+// if (user == null) {
+// return false;
+// }
+
+// // 防止除以零
+// if (user.getDownloaded() == 0) {
+// return true;
+// }
+
+// double uploadRatio = user.getUploaded() / (double) user.getDownloaded();
+// return uploadRatio >= MIN_UPLOAD_RATIO;
+// }
+// /**
+// * 启动做种客户端
+// */
+// private void startSeeding(Path torrentPath, Path dataDir) throws Exception {
+// SimpleClient seederClient = new SimpleClient();
+// seederClient.downloadTorrent(
+// torrentPath.toString(),
+// dataDir.toString(),
+// InetAddress.getLocalHost());
+// // 保持做种状态(阻塞线程)
+// while (true) {
+// Thread.sleep(60000); // 每60秒检查一次
+// }
+// }
+
+
+// @Override
+// public double calculateDownloadSize(Long torrentId, Long userId) {
+// TorrentEntity torrent = selectBySeedId(torrentId);
+// if (torrent == null) {
+// throw new RuntimeException("种子不存在");
+// }
+
+// // 获取当前有效的促销活动
+// double discount = promotionService.getCurrentDiscount(torrentId);
+
+// // 计算实际下载量
+// return torrent.getSize() * (1 - discount / 100.0);
+// }
+
+// @Override
+// @Transactional
+// public void recordDownload(Long torrentId, Long userId, double downloadSize) {
+// // 更新用户下载量
+// userMapper.increaseDownloaded(userId, downloadSize);
+
+// // 更新种子下载次数
+// torrentMapper.increaseDownloads(torrentId);
+// }
+// /**
+// * 计算种子文件的infoHash
+// */
+// private String calculateInfoHash(byte[] torrentData) throws NoSuchAlgorithmException {
+// MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+// sha1.update(torrentData);
+// byte[] hashBytes = sha1.digest();
+// return Hex.encodeHexString(hashBytes);
+// }
+// }
+
package com.example.myproject.service.serviceImpl;
+import cn.dev33.satoken.stp.StpUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.myproject.entity.TorrentEntity;
import com.example.myproject.entity.User;
import com.example.myproject.mapper.TorrentMapper;
@@ -13,6 +313,8 @@
import com.turn.ttorrent.bcodec.BEValue;
import com.turn.ttorrent.bcodec.BEncoder;
import com.turn.ttorrent.client.SimpleClient;
+import com.turn.ttorrent.common.TorrentMetadata;
+import com.turn.ttorrent.common.TorrentParser;
import com.turn.ttorrent.common.creation.MetadataBuilder;
import com.turn.ttorrent.tracker.Tracker;
import com.turn.ttorrent.tracker.TrackedTorrent;
@@ -80,66 +382,29 @@
if (user == null) {
throw new RuntimeException("用户不存在");
}
- String workingDir = System.getProperty("user.dir");
- Path originalDir = Paths.get(workingDir, "data", "files");
- Files.createDirectories(originalDir);
- Path originalFilePath = originalDir.resolve(file.getOriginalFilename());
- Files.copy(file.getInputStream(), originalFilePath, StandardCopyOption.REPLACE_EXISTING);
- MetadataBuilder builder = new MetadataBuilder()
- .addFile(originalFilePath.toFile(), file.getOriginalFilename()) // 添加原始文件
- .setTracker(" ") // 设置Tracker地址
- .setPieceLength(512 * 1024) // 分片大小512KB
- .setComment("Generated by PT站")
- .setCreatedBy("PT-Server");
-
- // 处理种子文件
byte[] torrentBytes = file.getBytes();
- String infoHash = null;
- try {
- infoHash = calculateInfoHash(torrentBytes);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
+ TorrentMetadata metadata = new TorrentParser().parse(torrentBytes);
- // 保存种子文件到data/torrents目录
- Path torrentDir = Paths.get(workingDir, "data", "torrents");
- Files.createDirectories(torrentDir);
- Path torrentPath = torrentDir.resolve(infoHash + ".torrent");
- Files.copy(new ByteArrayInputStream(torrentBytes), torrentPath, StandardCopyOption.REPLACE_EXISTING);
-
- // 注册到Tracker
- TrackedTorrent torrent = TrackedTorrent.load(torrentPath.toFile());
- tracker.announce(torrent);
-
-
- // 异步启动做种客户端
- seederExecutor.submit(() -> {
- try {
- startSeeding(torrentPath, originalDir);
- } catch (Exception e) {
- Result.error("做种失败: " + e.getMessage());
- }
- });
-
-
-
+ Long size = metadata.getFiles().stream().map(f -> f.size).reduce(0L, Long::sum);
// 保存种子信息
TorrentEntity entity= new TorrentEntity();
entity.setUploader(param.getUploader());
entity.setFileName(file.getOriginalFilename());
- entity.setSize(file.getSize());
+ entity.setSize(size);
entity.setCategory(param.getCategory());
entity.setTags(param.getTags());
entity.setTitle(param.getTitle());
entity.setImageUrl(param.getImageUrl());
entity.setTorrentFile(torrentBytes);
- entity.setInfoHash(infoHash);
+ entity.setInfoHash(metadata.getHexInfoHash());
torrentMapper.insert(entity);
}
+
+
@Override
public byte[] fetch(Long seedId, String passkey) {
TorrentEntity torrent = selectBySeedId(seedId);
@@ -154,14 +419,11 @@
Map<String, BEValue> decoded = BDecoder.bdecode(new ByteArrayInputStream(torrentBytes)).getMap();
// 2. 获取原始 announce 字段
- String announce = decoded.get("announce").getString();
+// TODO: 对应本机应用地址
+// String announce = "http://127.0.0.1:5011/seeds/announce?passkey="+passkey +"&userId=" + StpUtil.getLoginIdAsString();
+ String announce = "http://192.168.5.149:5011/seeds/announce?passkey=" + passkey + "&userId=" + StpUtil.getLoginIdAsString();
- // 3. 注入 passkey 到 announce URL
- if (!announce.contains("passkey=")) {
- announce = announce + "?passkey=" + passkey;
- decoded.put("announce", new BEValue(announce));
- }
-
+ decoded.put("announce", new BEValue(announce));
// 4. 编码成新的 .torrent 文件字节数组
ByteArrayOutputStream out = new ByteArrayOutputStream();
BEncoder.bencode(decoded, out);
@@ -284,6 +546,12 @@
// 更新种子下载次数
torrentMapper.increaseDownloads(torrentId);
}
+
+ @Override
+ public TorrentEntity selectByInfoHash(String infoHash) {
+ return torrentMapper.selectByInfoHash(infoHash);
+ }
+
/**
* 计算种子文件的infoHash
*/