implement synchronized Tracker structure

This commit is contained in:
mykola2312 2024-10-28 01:12:49 +02:00
parent 534f827afc
commit 7f75a1ac77
4 changed files with 124 additions and 2 deletions

View file

@ -31,7 +31,7 @@ public class Torrent {
}
}
public <T extends Collection<Peer>> void updatePeers(T src) {
public <T extends Collection<Peer>> void putPeers(T src) {
for (Peer peer : src) {
peers.put(peer);
}

View file

@ -0,0 +1,48 @@
package com.mykola2312.retracker.tracker;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
/* Tracker meant to be called from multiple running threads,
* so thread-safety ensured by synchronized methods.
*/
public class Tracker {
private HashMap<InfoHash, Torrent> torrents = new HashMap<InfoHash, Torrent>();
/* Adds peer to torrent's PeerSet. If no such Torrent present,
* creates the Torrent.
*/
public synchronized void announcePeer(InfoHash infoHash, Peer peer) {
Torrent torrent = torrents.get(infoHash);
if (torrent != null) {
torrent.putPeers(List.of(peer));
} else {
// create torrent and initiate PeerSet with first announced peer
torrent = new Torrent(infoHash, peer);
torrents.put(torrent.getInfoHash(), torrent);
}
}
/* Adds multiple peers to torrent. If no such Torrent present,
* creates the torrent.
*/
public synchronized <T extends Collection<Peer>> void announcePeers(InfoHash infoHash, T src) {
Torrent torrent = torrents.get(infoHash);
if (torrent != null) {
torrent.putPeers(src);
} else {
torrent = new Torrent(infoHash);
torrent.putPeers(src);
torrents.put(torrent.getInfoHash(), torrent);
}
}
// Get list of peers at this very moment.
public synchronized <T extends Collection<Peer>> void getPeers(InfoHash infoHash, T dst) {
Torrent torrent = torrents.get(infoHash);
if (torrent != null) {
torrent.copyPeers(dst);
}
}
}

View file

@ -31,7 +31,7 @@ public class TorrentTest {
List<Peer> src = Arrays.asList(new Peer(newAddress("127.0.0.1", 1337)),
new Peer(newAddress("127.0.0.1", 1338)));
torrent.updatePeers(src);
torrent.putPeers(src);
{
ArrayList<Peer> copy = new ArrayList<Peer>();
torrent.copyPeers(copy);

View file

@ -0,0 +1,74 @@
package com.mykola2312.retracker.tracker;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import org.junit.jupiter.api.Test;
public class TrackerTest {
private static InetSocketAddress newAddress(String addr, int port) throws UnknownHostException {
return new InetSocketAddress(InetAddress.getByName(addr), port);
}
class TrackerJob implements Runnable {
private Tracker tracker;
private InfoHash infoHash;
private Peer peer;
public TrackerJob(Tracker tracker, InfoHash infoHash, Peer peer) {
this.tracker = tracker;
this.infoHash = infoHash;
this.peer = peer;
}
@Override
public void run() {
tracker.announcePeer(infoHash, peer);
}
}
@Test
public void testTrackerPutAndGet() throws Exception {
final InfoHash infoHash = new InfoHash();
infoHash.fromString("360775c6629eb06e60d90201aed1b7bc49a1ce16");
Tracker tracker = new Tracker();
ArrayList<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < 32; i++) {
TrackerJob job = new TrackerJob(tracker, infoHash,
new Peer(newAddress("127.0.0.1", 1337 + i)));
Thread thread = new Thread(job);
thread.start();
threads.add(thread);
}
// wait for all threads to finish
for (Thread thread : threads) {
thread.join();
}
ArrayList<Peer> peers = new ArrayList<Peer>(32);
tracker.getPeers(infoHash, peers);
assertEquals(32, peers.size());
// check if every port present
for (int i = 0; i < 32; i++) {
int port = 1337 + i;
boolean peerPortPresent = false;
for (Peer peer : peers) {
if (peer.getAddress().getPort() == port) {
peerPortPresent = true;
}
}
assertEquals(true, peerPortPresent);
}
}
}