blob: 29ac1ad5de3548040dc8d9a1295025feaca14570 [file] [log] [blame]
package com.pt.service;
import com.pt.constant.Constants;
import com.pt.entity.PeerInfoEntity;
import com.pt.entity.TorrentMeta;
import com.pt.entity.User;
import com.pt.repository.PeerInfoRepository;
import com.pt.repository.TorrentMetaRepository;
import com.pt.repository.UserRepository;
import com.pt.utils.BencodeCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayOutputStream;
import java.util.*;
@Service
public class TrackerService {
@Autowired
private TorrentMetaRepository torrentMetaRepository;
@Autowired
private PeerInfoRepository peerInfoEntityRepository;
@Autowired
private TorrentMetaService torrentMetaService;
@Autowired
private UserRepository userRepository;
@Transactional
public byte[] handleAnnounce(Map<String, Object> params, String ipAddress, String event) {
System.out.println("TrackerService------------------------handle announce");
try {
if (!params.containsKey("info_hash") || !params.containsKey("peer_id") || !params.containsKey("port")) {
return BencodeCodec.encode(Map.of("failure reason", "Missing required parameters"));
}
System.out.println("Received announce params: " + params);
System.out.println("Client IP: " + ipAddress);
String username = (String) params.get("passkey");
User user = null;
if(username != null){
user = userRepository.findByUsername(username);
if (user == null) {
System.out.println("User not found: " + username);
return BencodeCodec.encode(Map.of("failure reason", "User not found"));
}
}
int compact = params.containsKey("compact") ? (int) params.get("compact") : 1;
System.out.println("left" + (long)params.get("left"));
String infoHash = (String)params.get("info_hash");
switch(event){
case "started":
String status = (long)params.get("left") == (long)0 ? "seeding" : "downloading"; // 默认状态为下载中
System.out.println("Event: started");
Optional<TorrentMeta> meta = torrentMetaRepository.findByInfoHash(infoHash);
if(status.equals("seeding")) {
if(meta.isEmpty()){
torrentMetaService.save(infoHash, "", 123456789L);
}
String peerId = (String) params.get("peer_id");
System.out.println("Decoded peer_id: " + peerId);
int port = (int) params.get("port");
System.out.println("Port: " + port);
if(peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).isEmpty()) {
PeerInfoEntity peer = new PeerInfoEntity(ipAddress, port, peerId);
peer.setInfoHash(infoHash);
peer.setStatus(status);
peer.setIsActive(1); // 默认活跃状态
peer.setUploaded(0);
peer.setDownloaded(0);
peer.setPeerId((String) params.get("peer_id"));
peerInfoEntityRepository.save(peer);
}
else {
System.out.println("Peer already exists for info_hash: " + infoHash);
peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).get(0).setStatus("seeding");
}
// 返回成功响应
Map<String, Object> response = new HashMap<>();
response.put("interval", 1800); // 客户端应该多久再次请求
response.put("min interval", 900); // 最小请求间隔
response.put("complete", peerInfoEntityRepository.findByInfoHash(infoHash).size()); // 种子数
response.put("incomplete", peerInfoEntityRepository.findDownloadingPeersByInfoHash(infoHash).size()); // 下载者数
// 紧凑格式 - 返回当前种子的信息
if(compact == 1) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// 转换IP地址
String[] ipParts = ipAddress.split("\\.");
for(String part : ipParts) {
baos.write(Integer.parseInt(part));
}
// 转换端口(大端序)
baos.write((port >> 8) & 0xFF);
baos.write(port & 0xFF);
} catch(Exception e) {
System.out.println("Error encoding peer info: " + e.getMessage());
}
response.put("peers", baos.toByteArray());
} else {
// 非紧凑格式
List<Map<String, Object>> peerList = new ArrayList<>();
Map<String, Object> peerMap = new HashMap<>();
peerMap.put("peer id", peerId);
peerMap.put("ip", ipAddress);
peerMap.put("port", port);
peerList.add(peerMap);
response.put("peers", peerList);
}
return BencodeCodec.encode(response);
}
if(status.equals("downloading")) {
System.out.println("Torrent is being downloaded, checking for existing peers...");
if(user.getDownloaded() > Constants.DOWNLOAD_EXEMPTION_BYTES){
if(user.getShareRatio() < Constants.MIN_SHARE_RATIO_THRESHOLD) {
return BencodeCodec.encode(Map.of("failure reason", "Share ratio too low"));
}
}
List<PeerInfoEntity> peers = peerInfoEntityRepository.findSeedingPeersByInfoHash(infoHash);
for(PeerInfoEntity peer : peers) {
System.out.println("Peer: " + peer.getPeerId() + ", IP: " + peer.getIp() + ", Port: " + peer.getPort());
}
String peerId = (String)params.get("peer_id");
System.out.println("Decoded peer_id: " + peerId);
int port = (int) params.get("port");
System.out.println("Port: " + port);
if(peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).isEmpty()) {
PeerInfoEntity peer = new PeerInfoEntity(ipAddress, port, peerId);
peer.setInfoHash(infoHash);
peer.setStatus(status);
peer.setIsActive(1); // 默认活跃状态
peer.setUploaded(0);
peer.setDownloaded(0);
peer.setPeerId((String) params.get("peer_id"));
peer.setLeft((long)params.get("left"));
peerInfoEntityRepository.save(peer);
}
else {
System.out.println("Peer already exists for info_hash: " + infoHash);
peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).get(0).setStatus("seeding");
}
if (peers.isEmpty()) {
return BencodeCodec.encode(Map.of("failure reason", "Torrent is not being seeded yet"));
}
System.out.println("solve download, compact = " + compact);
// 构建正确的响应
Map<String, Object> response = new HashMap<>();
// 添加基本信息
response.put("interval", 1800);
// 客户端应该多久再次请求
response.put("min interval", 900);
// 最小请求间隔
response.put("complete", peers.size());
// 种子数response.put("incomplete", 0);
// 下载者数(这里只返回种子)
// 构建peers列表
if (compact == 1) {
// 紧凑格式 - 每个peer用6字节表示 (4字节IP + 2字节端口)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (PeerInfoEntity tmpPeer : peers) {
try {
// 转换IP地址
String[] ipParts = tmpPeer.getIp().split("\\.");
for (String part : ipParts) {
baos.write(Integer.parseInt(part));
}
// 转换端口(大端序)
int tmpPeerPort = tmpPeer.getPort();
baos.write((tmpPeerPort >> 8) & 0xFF);
baos.write(tmpPeerPort & 0xFF);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
response.put("peers", baos.toByteArray());
System.out.println(response);
} else {
// 非紧凑格式 - 每个peer是一个字典
List<Map<String, Object>> peerList = new ArrayList<>();
for (PeerInfoEntity tmpPeer : peers) {
Map<String, Object> peerMap = new HashMap<>();
peerMap.put("peer id", tmpPeer.getPeerId());
peerMap.put("ip", tmpPeer.getIp());
peerMap.put("port", tmpPeer.getPort());
peerList.add(peerMap);
}
response.put("peers", peerList);
}
System.out.println(BencodeCodec.encode(response));
return BencodeCodec.encode(response);
}
break;
case "stopped":
System.out.println("Event: stopped");
String peerId = (String) params.get("peer_id");
PeerInfoEntity peer = peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, peerId).get(0);
peerInfoEntityRepository.delete(peer); // 删除该peer信息
if(peerInfoEntityRepository.findByInfoHash(infoHash).isEmpty()) {
torrentMetaRepository.deleteByInfoHash(infoHash); // 如果没有其他peer,删除种子信息
}
// 停止事件,通常不需要返回数据
Map<String, Object> response = new HashMap<>();
// 添加基本信息
response.put("interval", 1800);
// 客户端应该多久再次请求
response.put("min interval", 900);
System.out.println("solve stop");
return BencodeCodec.encode(response);
case "completed":
System.out.println("Event: completed");
PeerInfoEntity complete_peer = peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).get(0);
Map<String, Object> complete_response = new HashMap<>();
// 添加基本信息
complete_response.put("interval", 1800);
// 客户端应该多久再次请求
complete_response.put("min interval", 900);
complete_response.put("complete", peerInfoEntityRepository.findByInfoHash(infoHash).size()); // 种子数
complete_response.put("incomplete", peerInfoEntityRepository.findDownloadingPeersByInfoHash(infoHash).size()); // 下载者数
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (PeerInfoEntity tmpPeer : peerInfoEntityRepository.findSeedingPeersByInfoHash(infoHash)) {
try {
// 转换IP地址
String[] ipParts = tmpPeer.getIp().split("\\.");
for (String part : ipParts) {
baos.write(Integer.parseInt(part));
}
// 转换端口(大端序)
int tmpPeerPort = tmpPeer.getPort();
baos.write((tmpPeerPort >> 8) & 0xFF);
baos.write(tmpPeerPort & 0xFF);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
complete_response.put("peers", baos.toByteArray());
System.out.println("solve complete");
if(complete_peer.getStatus().equals("downloading")) {
user.setDownloaded(user.getDownloaded() + (long)params.get("downloaded"));
complete_peer.setStatus("seeding");
peerInfoEntityRepository.save(complete_peer);
}
if(complete_peer.getStatus().equals("seeding")) {
user.setUploaded(user.getUploaded() + (long)params.get("uploaded"));
}
user.setShareRatio(user.getUploaded() / (double) Math.max(user.getDownloaded(), 1));
userRepository.save(user); // 保存用户信息
return BencodeCodec.encode(complete_response);
default:
System.out.println(event);
System.out.println("Event: unknown or not specified");
PeerInfoEntity other_peer = peerInfoEntityRepository.findByInfoHashAndPeerId(infoHash, (String) params.get("peer_id")).get(0);
Map<String, Object> other_response = new HashMap<>();
// 添加基本信息
other_response.put("interval", 1800);
// 客户端应该多久再次请求
other_response.put("min interval", 900);
other_response.put("complete", peerInfoEntityRepository.findByInfoHash(infoHash).size()); // 种子数
other_response.put("incomplete", peerInfoEntityRepository.findDownloadingPeersByInfoHash(infoHash).size()); // 下载者数
ByteArrayOutputStream other_baos = new ByteArrayOutputStream();
for (PeerInfoEntity tmpPeer : peerInfoEntityRepository.findSeedingPeersByInfoHash(infoHash)) {
try {
// 转换IP地址
String[] ipParts = tmpPeer.getIp().split("\\.");
for (String part : ipParts) {
other_baos.write(Integer.parseInt(part));
}
// 转换端口(大端序)
int tmpPeerPort = tmpPeer.getPort();
other_baos.write((tmpPeerPort >> 8) & 0xFF);
other_baos.write(tmpPeerPort & 0xFF);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
other_response.put("peers", other_baos.toByteArray());
if(other_peer.getStatus().equals("downloading")) {
user.setDownloaded(user.getDownloaded() + (long)params.get("downloaded"));
}
if(other_peer.getStatus().equals("seeding")) {
user.setUploaded(user.getUploaded() + (long)params.get("uploaded"));
}
user.setShareRatio(user.getUploaded() / (double) Math.max(user.getDownloaded(), 1));
userRepository.save(user); // 保存用户信息
return BencodeCodec.encode(other_response);
}
return BencodeCodec.encode(Map.of("failure reason", "Event not handled"));
} catch (Exception e) {
e.printStackTrace(); // 打印异常堆栈,方便定位错误
return BencodeCodec.encode(Map.of("failure reason", "Internal server error"));
}
}
}