ystx | dfd42b3 | 2025-06-07 13:26:52 +0800 | [diff] [blame] | 1 | package com.pt.service; |
| 2 | |
| 3 | import com.pt.entity.PeerInfoEntity; |
22301102 | ca0fb2f | 2025-06-09 18:40:42 +0800 | [diff] [blame] | 4 | import com.pt.entity.TorrentMeta; |
ystx | dfd42b3 | 2025-06-07 13:26:52 +0800 | [diff] [blame] | 5 | import com.pt.entity.TorrentStats; |
| 6 | import com.pt.exception.ResourceNotFoundException; |
| 7 | import com.pt.repository.PeerInfoRepository; |
| 8 | import com.pt.repository.TorrentMetaRepository; |
| 9 | import com.pt.repository.TorrentStatsRepository; |
| 10 | import org.springframework.beans.factory.annotation.Autowired; |
| 11 | import org.springframework.stereotype.Service; |
| 12 | import org.springframework.stereotype.Repository; |
| 13 | import org.springframework.transaction.annotation.Transactional; |
| 14 | |
| 15 | import java.time.LocalDateTime; |
| 16 | import java.util.List; |
22301102 | ca0fb2f | 2025-06-09 18:40:42 +0800 | [diff] [blame] | 17 | import java.util.Optional; |
ystx | dfd42b3 | 2025-06-07 13:26:52 +0800 | [diff] [blame] | 18 | |
| 19 | @Service |
| 20 | public class TorrentStatsService { |
| 21 | |
| 22 | @Autowired |
| 23 | private PeerInfoRepository peerInfoRepository; |
| 24 | |
| 25 | @Autowired |
| 26 | private TorrentStatsRepository statsRepository; |
| 27 | |
| 28 | @Autowired |
| 29 | private TorrentMetaRepository torrentMetaRepository; |
| 30 | |
| 31 | @Autowired |
| 32 | public TorrentStatsService(TorrentStatsRepository statsRepository) { |
| 33 | this.statsRepository = statsRepository; |
| 34 | } |
| 35 | |
| 36 | /** |
| 37 | * 增加种子完成次数 |
| 38 | * |
| 39 | * @param torrentId 种子ID |
| 40 | */ |
| 41 | @Transactional |
| 42 | public void incrementCompletedCount(Long torrentId) { |
| 43 | // 1. 检查统计记录是否存在 |
| 44 | if (!statsRepository.findByTorrentId(torrentId).isPresent()) { |
| 45 | // 创建新的统计记录 |
| 46 | TorrentStats newStats = new TorrentStats(); |
| 47 | newStats.setTorrentId(torrentId); |
| 48 | newStats.setCompletedCount(1); |
| 49 | newStats.setLastUpdated(LocalDateTime.now()); |
| 50 | statsRepository.save(newStats); |
| 51 | return; |
| 52 | } |
| 53 | |
| 54 | // 2. 原子操作增加完成次数 |
| 55 | statsRepository.incrementCompletedCount(torrentId); |
| 56 | |
| 57 | // 3. 更新最后更新时间 |
| 58 | statsRepository.updateLastUpdatedToNow(torrentId); |
| 59 | } |
| 60 | /** |
| 61 | * 创建新的统计记录 |
| 62 | */ |
| 63 | private TorrentStats createNewStats(Long torrentId) { |
| 64 | TorrentStats stats = new TorrentStats(); |
| 65 | stats.setTorrentId(torrentId); |
| 66 | stats.setSeederCount(0); |
| 67 | stats.setLeecherCount(0); |
| 68 | stats.setCompletedCount(0); |
| 69 | return statsRepository.save(stats); |
| 70 | } |
| 71 | |
| 72 | // 每次客户端上报状态时调用 |
| 73 | @Transactional |
| 74 | public void updateTorrentStats(String infoHash) { |
| 75 | // 1. 获取当前种子的peer信息 |
| 76 | List<PeerInfoEntity> peers = peerInfoRepository.findByInfoHash(infoHash); |
| 77 | |
| 78 | // 2. 统计各类人数 |
| 79 | int seeders = 0; |
| 80 | int leechers = 0; |
| 81 | int completed = 0; |
| 82 | |
| 83 | for (PeerInfoEntity peer : peers) { |
| 84 | if ("seeding".equals(peer.getStatus()) && peer.isActive()) { |
| 85 | seeders++; |
| 86 | } else if ("downloading".equals(peer.getStatus()) && peer.isActive()) { |
| 87 | leechers++; |
| 88 | } |
| 89 | |
| 90 | if ("completed".equals(peer.getStatus())) { |
| 91 | completed++; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | // 3. 更新统计记录 |
22301102 | ca0fb2f | 2025-06-09 18:40:42 +0800 | [diff] [blame] | 96 | Optional<TorrentMeta> optionalMeta = torrentMetaRepository.findByInfoHash(infoHash); |
| 97 | if (optionalMeta.isEmpty()) { |
| 98 | // 处理找不到 info_hash 的情况 |
| 99 | throw new IllegalArgumentException("Invalid info_hash: not found in database"); |
| 100 | } |
ystx | dfd42b3 | 2025-06-07 13:26:52 +0800 | [diff] [blame] | 101 | |
22301102 | ca0fb2f | 2025-06-09 18:40:42 +0800 | [diff] [blame] | 102 | TorrentMeta meta = optionalMeta.get(); |
| 103 | |
| 104 | TorrentStats stats = statsRepository.findByTorrentId(meta.getId()) |
| 105 | .orElse(new TorrentStats()); |
| 106 | |
| 107 | stats.setTorrentId(meta.getId()); |
ystx | dfd42b3 | 2025-06-07 13:26:52 +0800 | [diff] [blame] | 108 | stats.setSeederCount(seeders); |
| 109 | stats.setLeecherCount(leechers); |
| 110 | stats.setCompletedCount(completed); |
| 111 | stats.setLastUpdated(LocalDateTime.now()); |
| 112 | |
| 113 | statsRepository.save(stats); |
| 114 | } |
| 115 | |
| 116 | // 获取种子统计信息 |
| 117 | public TorrentStats getTorrentStats(Long torrentId) { |
| 118 | return statsRepository.findByTorrentId(torrentId) |
| 119 | .orElseThrow(() -> new ResourceNotFoundException("Stats not found")); |
| 120 | } |
ystx | 89bd544 | 2025-06-07 19:35:27 +0800 | [diff] [blame] | 121 | |
| 122 | // 新增方法 |
| 123 | public List<TorrentStats> getTopSeededTorrents(int limit) { |
| 124 | return statsRepository.findTopBySeederCount(limit); |
| 125 | } |
| 126 | |
| 127 | public List<TorrentStats> getRecentActiveTorrents(int limit) { |
| 128 | return statsRepository.findRecentActiveTorrents(limit); |
| 129 | } |
| 130 | |
| 131 | public List<TorrentStats> getBatchStats(List<Long> torrentIds) { |
| 132 | return statsRepository.findByTorrentIds(torrentIds); |
| 133 | } |
ystx | dfd42b3 | 2025-06-07 13:26:52 +0800 | [diff] [blame] | 134 | } |