mirror of
https://github.com/anthonyraymond/joal.git
synced 2024-09-20 07:16:26 +08:00
style changes
- remove extraneous isDebugEnabled() checks; - rename some params for better readability; - decrease number of if-else blocks; - fix some typos.
This commit is contained in:
parent
a58ab74db5
commit
7fe610ce6a
|
@ -48,7 +48,7 @@ By default the web-ui is disabled, you can enable it with some more arguments:
|
|||
- `--joal.ui.secret-token="SECRET_TOKEN"`: use your own secret token here (this is some kind of a password, choose a complicated one).
|
||||
|
||||
Once joal is started head to: `http://localhost:port/SECRET_OBFUSCATION_PATH/ui/` (obviously, replace `SECRET_OBFUSCATION_PATH`) by the value you had chosen
|
||||
The `joal.ui.path.prefix` might seems useless but it's actually **crucial** to set it as complex as possible to prevent peoples to know that joal is running on your server.
|
||||
The `joal.ui.path.prefix` might seems useless but it's actually **crucial** to set it as complex as possible to prevent people to know that joal is running on your server.
|
||||
|
||||
If you want to use iframe you may also pass the `joal.iframe.enabled=true` argument. If you don't known what that is just ignore it.
|
||||
|
||||
|
@ -135,7 +135,7 @@ Those projects are maintained by their individual authors, if you have any quest
|
|||
|
||||
# Thanks:
|
||||
This project use a modified version of the awesome [mpetazzoni/ttorrent](http://mpetazzoni.github.com/ttorrent/) library. Thanks to **mpetazzoni** for this.
|
||||
Also this project has benefited from the help of several peoples, see [Thanks.md](THANKS.md)
|
||||
Also this project has benefited from the help of several people, see [Thanks.md](THANKS.md)
|
||||
|
||||
## Supporters
|
||||
[![Thanks for providing Jetbrain license](readme-assets/jetbrains.svg)](https://www.jetbrains.com/?from=joal)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.araymond.joal;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
|
||||
|
@ -15,5 +14,4 @@ public class JackOfAllTradesApplication {
|
|||
public static void main(final String[] args) {
|
||||
SpringApplication.run(JackOfAllTradesApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ public class CoreEventListener {
|
|||
public CoreEventListener() {
|
||||
}
|
||||
|
||||
|
||||
@Async
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@EventListener
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.araymond.joal.core;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.http.config.SocketConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
|
@ -38,10 +37,7 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
|
@ -168,17 +164,11 @@ public class SeedManager {
|
|||
}
|
||||
|
||||
public List<AnnouncerFacade> getCurrentlySeedingAnnouncer() {
|
||||
if (this.client == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return client.getCurrentlySeedingAnnouncer();
|
||||
return this.client == null ? new ArrayList<>() : client.getCurrentlySeedingAnnouncer();
|
||||
}
|
||||
|
||||
public Map<InfoHash, Speed> getSpeedMap() {
|
||||
if (this.bandwidthDispatcher == null) {
|
||||
return Maps.newHashMap();
|
||||
}
|
||||
return bandwidthDispatcher.getSpeedMap();
|
||||
return this.bandwidthDispatcher == null ? new HashMap<>() : bandwidthDispatcher.getSpeedMap();
|
||||
}
|
||||
|
||||
public AppConfiguration getCurrentConfig() {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package org.araymond.joal.core.bandwith;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.araymond.joal.core.bandwith.weight.PeersAwareWeightCalculator;
|
||||
import org.araymond.joal.core.bandwith.weight.WeightHolder;
|
||||
|
@ -10,10 +8,13 @@ import org.araymond.joal.core.torrent.torrent.InfoHash;
|
|||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static org.apache.commons.lang3.ObjectUtils.getIfNull;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable {
|
||||
|
@ -25,8 +26,8 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
private final Map<InfoHash, Speed> speedMap;
|
||||
private SpeedChangedListener speedChangedListener;
|
||||
private final int threadPauseInterval;
|
||||
private int threadLoopCounter = 0;
|
||||
private volatile boolean stop = false;
|
||||
private int threadLoopCounter;
|
||||
private volatile boolean stop;
|
||||
private Thread thread;
|
||||
|
||||
public BandwidthDispatcher(final int threadPauseInterval, final RandomSpeedProvider randomSpeedProvider) {
|
||||
|
@ -35,7 +36,6 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
this.speedMap = new HashMap<>();
|
||||
this.lock = new ReentrantReadWriteLock();
|
||||
|
||||
|
||||
this.weightHolder = new WeightHolder<>(new PeersAwareWeightCalculator());
|
||||
this.randomSpeedProvider = randomSpeedProvider;
|
||||
}
|
||||
|
@ -44,19 +44,18 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
this.speedChangedListener = speedListener;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* This method does not benefit from the lock, because the value will never be accessed in a ambiguous way.
|
||||
* And even if it happens, we returns 0 by default.
|
||||
* And even if it happens, we return 0 by default.
|
||||
*/
|
||||
public TorrentSeedStats getSeedStatForTorrent(final InfoHash infoHash) {
|
||||
final TorrentSeedStats torrentSeedStats = this.torrentsSeedStats.get(infoHash);
|
||||
return torrentSeedStats == null ? new TorrentSeedStats() : torrentSeedStats;
|
||||
return getIfNull(this.torrentsSeedStats.get(infoHash), TorrentSeedStats::new);
|
||||
}
|
||||
|
||||
public Map<InfoHash, Speed> getSpeedMap() {
|
||||
try {
|
||||
this.lock.readLock().lock();
|
||||
return Maps.newHashMap(speedMap);
|
||||
return new HashMap<>(speedMap);
|
||||
} finally {
|
||||
this.lock.readLock().unlock();
|
||||
}
|
||||
|
@ -90,16 +89,17 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
this.threadLoopCounter = 0;
|
||||
}
|
||||
|
||||
// This method as to run as fast as possible to avoid blocking other ones. Because we wan't this loop
|
||||
// to be scheduled as precise as we can. Locking to much will delay the Thread.sleep and cause stats
|
||||
// This method as to run as fast as possible to avoid blocking other ones. Because we wasn't this loop
|
||||
// to be scheduled as precise as we can. Locking too much will delay the Thread.sleep and cause stats
|
||||
// to be undervalued
|
||||
this.lock.readLock().lock();
|
||||
final Set<Map.Entry<InfoHash, TorrentSeedStats>> entrySet = Sets.newHashSet(this.torrentsSeedStats.entrySet());
|
||||
final Set<Map.Entry<InfoHash, TorrentSeedStats>> entrySet = new HashSet<>(this.torrentsSeedStats.entrySet());
|
||||
this.lock.readLock().unlock();
|
||||
|
||||
for (final Map.Entry<InfoHash, TorrentSeedStats> entry : entrySet) {
|
||||
final Speed speed = this.speedMap.get(entry.getKey());
|
||||
final long speedInBytesPerSecond = speed == null ? 0: speed.getBytesPerSeconds(); // avoid Map#getOrDefault as it will trigger a lot of Speed object instantiation for nothing.
|
||||
final long speedInBytesPerSecond = ofNullable(this.speedMap.get(entry.getKey()))
|
||||
.map(Speed::getBytesPerSeconds)
|
||||
.orElse(0L);
|
||||
// Divide by 1000 because of the thread pause interval being in milliseconds
|
||||
// The multiplication HAS to be done before the division, otherwise we're going to have trailing zeroes
|
||||
entry.getValue().addUploaded((speedInBytesPerSecond * this.threadPauseInterval) / 1000);
|
||||
|
@ -110,9 +110,7 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
}
|
||||
|
||||
public void updateTorrentPeers(final InfoHash infoHash, final int seeders, final int leechers) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Updating Peers stats for {}", infoHash.humanReadableValue());
|
||||
}
|
||||
logger.debug("Updating Peers stats for {}", infoHash.humanReadableValue());
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
this.weightHolder.addOrUpdate(infoHash, new Peers(seeders, leechers));
|
||||
|
@ -123,9 +121,7 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
}
|
||||
|
||||
public void registerTorrent(final InfoHash infoHash) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("{} has been added to bandwidth dispatcher.", infoHash.humanReadableValue());
|
||||
}
|
||||
logger.debug("{} has been added to bandwidth dispatcher.", infoHash.humanReadableValue());
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
this.torrentsSeedStats.put(infoHash, new TorrentSeedStats());
|
||||
|
@ -136,9 +132,7 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
}
|
||||
|
||||
public void unregisterTorrent(final InfoHash infoHash) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("{} has been removed from bandwidth dispatcher.", infoHash.humanReadableValue());
|
||||
}
|
||||
logger.debug("{} has been removed from bandwidth dispatcher.", infoHash.humanReadableValue());
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
this.weightHolder.remove(infoHash);
|
||||
|
@ -152,9 +146,7 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
|
||||
@VisibleForTesting
|
||||
void refreshCurrentBandwidth() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Refreshing global bandwidth");
|
||||
}
|
||||
logger.debug("Refreshing global bandwidth");
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
this.randomSpeedProvider.refresh();
|
||||
|
@ -169,25 +161,25 @@ public class BandwidthDispatcher implements BandwidthDispatcherFacade, Runnable
|
|||
|
||||
@VisibleForTesting
|
||||
void recomputeSpeeds() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Refreshing all torrents speeds");
|
||||
}
|
||||
logger.debug("Refreshing all torrents speeds");
|
||||
for (final InfoHash infohash : this.torrentsSeedStats.keySet()) {
|
||||
final double percentOfSpeedAssigned = this.weightHolder.getTotalWeight() == 0.0
|
||||
? 0.0
|
||||
: this.weightHolder.getWeightFor(infohash) / this.weightHolder.getTotalWeight();
|
||||
|
||||
this.speedMap.compute(infohash, (hash, speed) -> {
|
||||
if (speed == null) {
|
||||
return new Speed(0);
|
||||
}
|
||||
double percentOfSpeedAssigned = this.weightHolder.getTotalWeight() == 0.0
|
||||
? 0.0
|
||||
: this.weightHolder.getWeightFor(infohash) / this.weightHolder.getTotalWeight();
|
||||
speed.setBytesPerSeconds((long) (this.randomSpeedProvider.getInBytesPerSeconds() * percentOfSpeedAssigned));
|
||||
|
||||
return speed;
|
||||
});
|
||||
}
|
||||
|
||||
if (speedChangedListener != null) {
|
||||
this.speedChangedListener.speedsHasChanged(Maps.newHashMap(this.speedMap));
|
||||
this.speedChangedListener.speedsHasChanged(new HashMap<>(this.speedMap));
|
||||
}
|
||||
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
final StringBuilder sb = new StringBuilder("All torrents speeds has been refreshed:\n");
|
||||
|
|
|
@ -3,5 +3,5 @@ package org.araymond.joal.core.bandwith;
|
|||
import org.araymond.joal.core.torrent.torrent.InfoHash;
|
||||
|
||||
public interface BandwidthDispatcherFacade {
|
||||
TorrentSeedStats getSeedStatForTorrent(final InfoHash infoHash);
|
||||
TorrentSeedStats getSeedStatForTorrent(InfoHash infoHash);
|
||||
}
|
||||
|
|
|
@ -10,14 +10,13 @@ public class RandomSpeedProvider {
|
|||
|
||||
public RandomSpeedProvider(final AppConfiguration appConfiguration) {
|
||||
this.appConfiguration = appConfiguration;
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
final Long minUploadRateInBytes = appConfiguration.getMinUploadRate() * 1000L;
|
||||
final Long maxUploadRateInBytes = appConfiguration.getMaxUploadRate() * 1000L;
|
||||
this.currentSpeed = (minUploadRateInBytes.equals(maxUploadRateInBytes))
|
||||
final long minUploadRateInBytes = appConfiguration.getMinUploadRate() * 1000L;
|
||||
final long maxUploadRateInBytes = appConfiguration.getMaxUploadRate() * 1000L;
|
||||
this.currentSpeed = (minUploadRateInBytes == maxUploadRateInBytes)
|
||||
? maxUploadRateInBytes
|
||||
: ThreadLocalRandom.current().nextLong(minUploadRateInBytes, maxUploadRateInBytes);
|
||||
}
|
||||
|
|
|
@ -5,5 +5,5 @@ import org.araymond.joal.core.torrent.torrent.InfoHash;
|
|||
import java.util.Map;
|
||||
|
||||
public interface SpeedChangedListener {
|
||||
void speedsHasChanged(final Map<InfoHash, Speed> speeds);
|
||||
void speedsHasChanged(Map<InfoHash, Speed> speeds);
|
||||
}
|
||||
|
|
|
@ -4,15 +4,9 @@ import org.araymond.joal.core.bandwith.Peers;
|
|||
|
||||
public class PeersAwareWeightCalculator {
|
||||
public double calculate(final Peers peers) {
|
||||
if (peers.getSeeders() == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
final double leechersRatio = peers.getLeechersRatio();
|
||||
if (leechersRatio == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
return leechersRatio * 100
|
||||
* (peers.getSeeders() * leechersRatio)
|
||||
* (((double) peers.getLeechers()) / peers.getSeeders());
|
||||
return (peers.getSeeders() == 0 || leechersRatio == 0)
|
||||
? 0.0
|
||||
: leechersRatio * 100 * leechersRatio * peers.getLeechers();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import java.util.Map;
|
|||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
|
||||
public class WeightHolder<E> {
|
||||
|
||||
private final Lock lock;
|
||||
|
@ -24,13 +26,9 @@ public class WeightHolder<E> {
|
|||
final double weight = this.weightCalculator.calculate(peers);
|
||||
lock.lock();
|
||||
try {
|
||||
final Weight previousWeight = this.weightMap.put(item, new Weight(weight));
|
||||
|
||||
if (previousWeight != null) {
|
||||
this.totalWeight = this.totalWeight - previousWeight.getWeight() + weight;
|
||||
} else {
|
||||
this.totalWeight += weight;
|
||||
}
|
||||
ofNullable(this.weightMap.put(item, new Weight(weight))).ifPresentOrElse(
|
||||
previousWeight -> this.totalWeight = this.totalWeight - previousWeight.getWeight() + weight,
|
||||
() -> this.totalWeight += weight);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
@ -39,28 +37,23 @@ public class WeightHolder<E> {
|
|||
public void remove(final E item) {
|
||||
lock.lock();
|
||||
try {
|
||||
final Weight weight = this.weightMap.remove(item);
|
||||
if (weight != null) {
|
||||
this.totalWeight -= weight.getWeight();
|
||||
}
|
||||
ofNullable(this.weightMap.remove(item))
|
||||
.ifPresent(w -> this.totalWeight -= w.getWeight());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* For performance reasons, this method does not benefit from the lock.
|
||||
* That's not a big deal because:
|
||||
* - if a value is not yet added it will return 0.0.
|
||||
* - if a value is still present il will returns the previous value.
|
||||
*
|
||||
* - if a value is still present it will return the previous value.
|
||||
*/
|
||||
public double getWeightFor(final E item) {
|
||||
final Weight weight = this.weightMap.get(item);
|
||||
if (weight == null) {
|
||||
return 0.0;
|
||||
}
|
||||
return weight.getWeight();
|
||||
return ofNullable(weightMap.get(item))
|
||||
.map(Weight::getWeight)
|
||||
.orElse(0.0);
|
||||
}
|
||||
|
||||
public double getTotalWeight() {
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static org.araymond.joal.core.client.emulated.BitTorrentClientConfig.HttpHeader;
|
||||
|
||||
/**
|
||||
|
@ -55,10 +56,8 @@ public class BitTorrentClient {
|
|||
|
||||
@VisibleForTesting
|
||||
Optional<String> getKey(final InfoHash infoHash, final RequestEvent event) {
|
||||
if (keyGenerator == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(keyGenerator.getKey(infoHash, event));
|
||||
return ofNullable(keyGenerator)
|
||||
.map(keyGen -> keyGen.getKey(infoHash, event));
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
|
@ -83,12 +82,9 @@ public class BitTorrentClient {
|
|||
.replaceAll("\\{port}", String.valueOf(connectionHandler.getPort()))
|
||||
.replaceAll("\\{numwant}", String.valueOf(this.getNumwant(event)));
|
||||
|
||||
final String peerId;
|
||||
if (this.peerIdGenerator.getShouldUrlEncoded()) {
|
||||
peerId = urlEncoder.encode(this.getPeerId(torrentInfoHash, event));
|
||||
} else {
|
||||
peerId = this.getPeerId(torrentInfoHash, event);
|
||||
}
|
||||
final String peerId = this.peerIdGenerator.getShouldUrlEncoded()
|
||||
? urlEncoder.encode(this.getPeerId(torrentInfoHash, event))
|
||||
: this.getPeerId(torrentInfoHash, event);
|
||||
emulatedClientQuery = emulatedClientQuery.replaceAll("\\{peerid}", peerId);
|
||||
|
||||
// set ip or ipv6 then remove placeholders that were left empty
|
||||
|
|
|
@ -49,10 +49,8 @@ public class BitTorrentClientConfig {
|
|||
this.numwant = numwant;
|
||||
this.numwantOnStop = numwantOnStop;
|
||||
|
||||
if (this.query.contains("{key}")) {
|
||||
if (this.keyGenerator == null) {
|
||||
throw new TorrentClientConfigIntegrityException("Query string contains {key}, but no keyGenerator was found in .client file.");
|
||||
}
|
||||
if (this.query.contains("{key}") && this.keyGenerator == null) {
|
||||
throw new TorrentClientConfigIntegrityException("Query string contains {key}, but no keyGenerator was found in .client file.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,14 +64,13 @@ public class BitTorrentClientProvider implements Provider<BitTorrentClient> {
|
|||
throw new FileNotFoundException(String.format("BitTorrent client configuration file '%s' not found.", clientConfigPath.toAbsolutePath()));
|
||||
}
|
||||
|
||||
final BitTorrentClientConfig config;
|
||||
try {
|
||||
config = objectMapper.readValue(clientConfigPath.toFile(), BitTorrentClientConfig.class);
|
||||
BitTorrentClientConfig config = objectMapper.readValue(clientConfigPath.toFile(), BitTorrentClientConfig.class);
|
||||
this.bitTorrentClient = config.createClient();
|
||||
logger.debug("New client successfully generated.");
|
||||
} catch (final IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
this.bitTorrentClient = config.createClient();
|
||||
logger.debug("New client successfully generated.");
|
||||
}
|
||||
|
||||
static final class SemanticVersionFilenameComparator implements Comparator<String> {
|
||||
|
|
|
@ -6,7 +6,6 @@ package org.araymond.joal.core.client.emulated;
|
|||
public class TorrentClientConfigIntegrityException extends RuntimeException {
|
||||
private static final long serialVersionUID = -2441989395992766363L;
|
||||
|
||||
|
||||
public TorrentClientConfigIntegrityException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class UrlEncoder {
|
|||
*/
|
||||
public String encode(final String toBeEncoded) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for(final char ch: toBeEncoded.toCharArray()) {
|
||||
for (final char ch : toBeEncoded.toCharArray()) {
|
||||
sb.append(this.urlEncodeChar(ch));
|
||||
}
|
||||
return sb.toString();
|
||||
|
|
|
@ -19,7 +19,6 @@ public class NeverRefreshKeyGenerator extends KeyGenerator {
|
|||
@JsonProperty(value = "keyCase", required = true) final Casing keyCase
|
||||
) {
|
||||
super(algorithm, keyCase);
|
||||
|
||||
this.key = generateKey();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package org.araymond.joal.core.client.emulated.generator.key;
|
|||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.turn.ttorrent.common.protocol.TrackerMessage.AnnounceRequestMessage.RequestEvent;
|
||||
import org.araymond.joal.core.client.emulated.generator.key.algorithm.KeyAlgorithm;
|
||||
import org.araymond.joal.core.client.emulated.utils.Casing;
|
||||
|
@ -11,6 +10,7 @@ import org.araymond.joal.core.torrent.torrent.InfoHash;
|
|||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
@ -41,7 +41,7 @@ public class TorrentPersistentRefreshKeyGenerator extends KeyGenerator {
|
|||
}
|
||||
|
||||
private void evictOldEntries() {
|
||||
Sets.newHashSet(this.keyPerTorrent.entrySet()).stream()
|
||||
new HashSet<>(this.keyPerTorrent.entrySet()).stream()
|
||||
.filter(this::shouldEvictEntry)
|
||||
.forEach(entry -> this.keyPerTorrent.remove(entry.getKey()));
|
||||
}
|
||||
|
|
|
@ -27,5 +27,4 @@ public class NeverRefreshPeerIdGenerator extends PeerIdGenerator {
|
|||
public String getPeerId(final InfoHash infoHash, final RequestEvent event) {
|
||||
return peerId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ package org.araymond.joal.core.client.emulated.generator.peerid;
|
|||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.turn.ttorrent.common.protocol.TrackerMessage.AnnounceRequestMessage.RequestEvent;
|
||||
import org.araymond.joal.core.client.emulated.generator.peerid.generation.PeerIdAlgorithm;
|
||||
import org.araymond.joal.core.torrent.torrent.InfoHash;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class TorrentPersistentRefreshPeerIdGenerator extends PeerIdGenerator {
|
|||
|
||||
@VisibleForTesting
|
||||
void evictOldEntries() {
|
||||
Sets.newHashSet(this.peerIdPerTorrent.entrySet()).stream()
|
||||
new HashSet<>(this.peerIdPerTorrent.entrySet()).stream()
|
||||
.filter(this::shouldEvictEntry)
|
||||
.forEach(entry -> this.peerIdPerTorrent.remove(entry.getKey()));
|
||||
}
|
||||
|
|
|
@ -27,13 +27,8 @@ public class TorrentVolatileRefreshPeerIdGenerator extends PeerIdGenerator {
|
|||
|
||||
@Override
|
||||
public String getPeerId(final InfoHash infoHash, final RequestEvent event) {
|
||||
final String peerId;
|
||||
|
||||
if (!this.peerIdPerTorrent.containsKey(infoHash)) {
|
||||
this.peerIdPerTorrent.put(infoHash, super.generatePeerId());
|
||||
}
|
||||
|
||||
peerId = this.peerIdPerTorrent.get(infoHash);
|
||||
this.peerIdPerTorrent.computeIfAbsent(infoHash, k -> super.generatePeerId());
|
||||
String peerId = this.peerIdPerTorrent.get(infoHash);
|
||||
|
||||
if (event == RequestEvent.STOPPED) {
|
||||
this.peerIdPerTorrent.remove(infoHash);
|
||||
|
|
|
@ -11,5 +11,4 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||
public interface PeerIdAlgorithm {
|
||||
|
||||
String generate();
|
||||
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public class RandomPoolWithChecksumPeerIdAlgorithm implements PeerIdAlgorithm {
|
|||
// Using the current random to generate another random would be completely useless because if the SecureRandom appears to be predictable we will be able to predict the next int as well
|
||||
int randNumber = new SecureRandom(createSecureRandomSeed()).nextInt();
|
||||
randNumber = Math.abs(randNumber % 40);
|
||||
return (randNumber + 10);
|
||||
return randNumber + 10;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
|
@ -58,27 +58,26 @@ public class AppConfiguration {
|
|||
}
|
||||
|
||||
private void validate() {
|
||||
if (java.util.Objects.isNull(minUploadRate)) {
|
||||
if (minUploadRate == null) {
|
||||
throw new AppConfigurationIntegrityException("minUploadRate must not be null");
|
||||
}
|
||||
if (minUploadRate < 0L) {
|
||||
} else if (minUploadRate < 0L) {
|
||||
throw new AppConfigurationIntegrityException("minUploadRate must be at least 0.");
|
||||
}
|
||||
if (java.util.Objects.isNull(maxUploadRate)) {
|
||||
|
||||
if (maxUploadRate == null) {
|
||||
throw new AppConfigurationIntegrityException("maxUploadRate must not be null");
|
||||
}
|
||||
if (maxUploadRate < 0L) {
|
||||
} else if (maxUploadRate < 0L) {
|
||||
throw new AppConfigurationIntegrityException("maxUploadRate must greater or equal to 0.");
|
||||
}
|
||||
if (maxUploadRate < minUploadRate) {
|
||||
} else if (maxUploadRate < minUploadRate) {
|
||||
throw new AppConfigurationIntegrityException("maxUploadRate must be greater or equal to minUploadRate.");
|
||||
}
|
||||
if (java.util.Objects.isNull(simultaneousSeed)) {
|
||||
|
||||
if (simultaneousSeed == null) {
|
||||
throw new AppConfigurationIntegrityException("simultaneousSeed must not be null");
|
||||
}
|
||||
if (simultaneousSeed < 1) {
|
||||
} else if (simultaneousSeed < 1) {
|
||||
throw new AppConfigurationIntegrityException("simultaneousSeed must be greater than 0.");
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(client)) {
|
||||
throw new AppConfigurationIntegrityException("client is required, no file name given.");
|
||||
}
|
||||
|
|
|
@ -36,9 +36,7 @@ public class JoalConfigProvider implements Provider<AppConfiguration> {
|
|||
throw new FileNotFoundException(String.format("App configuration file '%s' not found.", joalConfPath));
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("App configuration file will be searched for in {}", joalConfPath.toAbsolutePath());
|
||||
}
|
||||
logger.debug("App configuration file will be searched for in {}", joalConfPath.toAbsolutePath());
|
||||
}
|
||||
|
||||
public void init() {
|
||||
|
@ -58,15 +56,14 @@ public class JoalConfigProvider implements Provider<AppConfiguration> {
|
|||
AppConfiguration loadConfiguration() {
|
||||
final AppConfiguration configuration;
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reading json configuration from '{}'.", joalConfPath.toAbsolutePath());
|
||||
}
|
||||
logger.debug("Reading json configuration from '{}'.", joalConfPath.toAbsolutePath());
|
||||
configuration = objectMapper.readValue(joalConfPath.toFile(), AppConfiguration.class);
|
||||
logger.debug("Successfully red json configuration.");
|
||||
} catch (final IOException e) {
|
||||
logger.error("Failed to read configuration file", e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
logger.info("App configuration has been successfully loaded.");
|
||||
this.publisher.publishEvent(new ConfigHasBeenLoadedEvent(configuration));
|
||||
return configuration;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package org.araymond.joal.core.events.speed;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.araymond.joal.core.bandwith.Speed;
|
||||
import org.araymond.joal.core.torrent.torrent.InfoHash;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SeedingSpeedsHasChangedEvent {
|
||||
private final Map<InfoHash, Speed> speeds;
|
||||
|
||||
public SeedingSpeedsHasChangedEvent(final Map<InfoHash, Speed> speeds) {
|
||||
this.speeds = Maps.newHashMap(speeds);
|
||||
this.speeds = new HashMap<>(speeds);
|
||||
}
|
||||
|
||||
public Map<InfoHash, Speed> getSpeeds() {
|
||||
|
|
|
@ -4,13 +4,15 @@ import com.google.common.base.Objects;
|
|||
|
||||
public class InfoHash {
|
||||
private final String infoHash;
|
||||
private final String humanReadable;
|
||||
|
||||
public InfoHash(final byte[] bytes) {
|
||||
this.infoHash = new String(bytes, MockedTorrent.BYTE_ENCODING);
|
||||
this.humanReadable = infoHash.replaceAll("\\p{C}", "");
|
||||
}
|
||||
|
||||
public String humanReadableValue() {
|
||||
return infoHash.replaceAll("\\p{C}", "");
|
||||
return humanReadable;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
|
|
|
@ -7,8 +7,8 @@ import org.araymond.joal.core.torrent.torrent.MockedTorrent;
|
|||
*/
|
||||
public interface TorrentFileChangeAware {
|
||||
|
||||
void onTorrentFileAdded(final MockedTorrent torrent);
|
||||
void onTorrentFileAdded(MockedTorrent torrent);
|
||||
|
||||
void onTorrentFileRemoved(final MockedTorrent torrent);
|
||||
void onTorrentFileRemoved(MockedTorrent torrent);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import java.security.NoSuchAlgorithmException;
|
|||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
|
||||
/**
|
||||
* Created by raymo on 28/01/2017.
|
||||
*/
|
||||
|
@ -29,7 +31,6 @@ public class TorrentFileProvider extends FileAlterationListenerAdaptor {
|
|||
private final TorrentFileWatcher watcher;
|
||||
private final Map<File, MockedTorrent> torrentFiles;
|
||||
private final Set<TorrentFileChangeAware> torrentFileChangeListener;
|
||||
private final Path torrentFolder;
|
||||
private final Path archiveFolder;
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -55,7 +56,7 @@ public class TorrentFileProvider extends FileAlterationListenerAdaptor {
|
|||
}
|
||||
|
||||
public TorrentFileProvider(final SeedManager.JoalFoldersPath joalFoldersPath) throws FileNotFoundException {
|
||||
this.torrentFolder = joalFoldersPath.getTorrentFilesPath();
|
||||
Path torrentFolder = joalFoldersPath.getTorrentFilesPath();
|
||||
if (!Files.exists(torrentFolder)) {
|
||||
logger.error("Folder " + torrentFolder.toAbsolutePath() + " does not exists.");
|
||||
throw new FileNotFoundException(String.format("Torrent folder '%s' not found.", torrentFolder.toAbsolutePath()));
|
||||
|
@ -69,18 +70,11 @@ public class TorrentFileProvider extends FileAlterationListenerAdaptor {
|
|||
|
||||
@Override
|
||||
public void onFileDelete(final File file) {
|
||||
if (!this.torrentFiles.containsKey(file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final MockedTorrent torrent = this.torrentFiles.get(file);
|
||||
if (torrent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("Torrent file deleting detected, hot deleted file: {}", file.getAbsolutePath());
|
||||
this.torrentFiles.remove(file);
|
||||
this.torrentFileChangeListener.forEach(listener -> listener.onTorrentFileRemoved(torrent));
|
||||
ofNullable(this.torrentFiles.remove(file))
|
||||
.ifPresent(removedTorrent -> {
|
||||
logger.info("Torrent file deleting detected, hot deleted file: {}", file.getAbsolutePath());
|
||||
this.torrentFileChangeListener.forEach(listener -> listener.onTorrentFileRemoved(removedTorrent));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,15 +138,12 @@ public class TorrentFileProvider extends FileAlterationListenerAdaptor {
|
|||
}
|
||||
|
||||
public void moveToArchiveFolder(final InfoHash infoHash) {
|
||||
final Optional<File> first = this.torrentFiles.entrySet().stream()
|
||||
this.torrentFiles.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().getTorrentInfoHash().equals(infoHash))
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst();
|
||||
if (first.isPresent()) {
|
||||
this.moveToArchiveFolder(first.get());
|
||||
} else {
|
||||
logger.warn("Cannot move torrent {} to archive folder. Torrent file seems not to be registered in TorrentFileProvider.", infoHash);
|
||||
}
|
||||
.findAny()
|
||||
.ifPresentOrElse(this::moveToArchiveFolder,
|
||||
() -> logger.warn("Cannot move torrent {} to archive folder. Torrent file seems not to be registered in TorrentFileProvider.", infoHash));
|
||||
}
|
||||
|
||||
public int getTorrentCount() {
|
||||
|
|
|
@ -17,20 +17,16 @@ import org.araymond.joal.core.ttorrent.client.announcer.AnnouncerFacade;
|
|||
import org.araymond.joal.core.ttorrent.client.announcer.AnnouncerFactory;
|
||||
import org.araymond.joal.core.ttorrent.client.announcer.request.AnnounceRequest;
|
||||
import org.araymond.joal.core.ttorrent.client.announcer.request.AnnouncerExecutor;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class Client implements TorrentFileChangeAware, ClientFacade {
|
||||
private static final Logger logger = getLogger(Client.class);
|
||||
|
||||
private final AppConfiguration appConfiguration;
|
||||
private final TorrentFileProvider torrentFileProvider;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
@ -85,10 +81,10 @@ public class Client implements TorrentFileChangeAware, ClientFacade {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < this.appConfiguration.getSimultaneousSeed(); i++) {
|
||||
try {
|
||||
this.lock.writeLock().lock();
|
||||
|
||||
this.addTorrent();
|
||||
} catch (final NoMoreTorrentsFileAvailableException ignored) {
|
||||
break;
|
||||
|
@ -107,7 +103,7 @@ public class Client implements TorrentFileChangeAware, ClientFacade {
|
|||
final MockedTorrent torrent = this.torrentFileProvider.getTorrentNotIn(
|
||||
this.currentlySeedingAnnouncer.stream()
|
||||
.map(Announcer::getTorrentInfoHash)
|
||||
.collect(Collectors.toList())
|
||||
.collect(toList())
|
||||
);
|
||||
final Announcer announcer = this.announcerFactory.create(torrent);
|
||||
this.currentlySeedingAnnouncer.add(announcer);
|
||||
|
|
|
@ -78,7 +78,7 @@ public class ConnectionHandler {
|
|||
urlConnection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
|
||||
try (final BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), Charsets.UTF_8))) {
|
||||
return InetAddress.getByName(in.readLine());
|
||||
}finally {
|
||||
} finally {
|
||||
// Ensure all streams associated with http connection are closed
|
||||
final InputStream err = ((HttpURLConnection) urlConnection).getErrorStream();
|
||||
try { if (err != null) err.close(); }
|
||||
|
@ -126,7 +126,6 @@ public class ConnectionHandler {
|
|||
for (int port = ConnectionHandler.PORT_RANGE_START; port <= ConnectionHandler.PORT_RANGE_END; port++) {
|
||||
final InetSocketAddress tryAddress = new InetSocketAddress(port);
|
||||
|
||||
|
||||
try {
|
||||
channel = ServerSocketChannel.open();
|
||||
channel.socket().bind(tryAddress);
|
||||
|
|
|
@ -89,7 +89,6 @@ public class DelayQueue<T extends DelayQueue.InfoHashAble> {
|
|||
return item;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Override
|
||||
public int compareTo(final IntervalAware o) {
|
||||
return this.releaseAt.compareTo(o.releaseAt);
|
||||
|
|
|
@ -42,7 +42,7 @@ public class Announcer implements AnnouncerFacade {
|
|||
}
|
||||
|
||||
private TrackerClient buildTrackerClient(final MockedTorrent torrent, HttpClient httpClient) {
|
||||
final List<URI> trackerURIs = torrent.getAnnounceList().stream() // Use a list to keep it ordered
|
||||
final List<URI> trackerURIs = torrent.getAnnounceList().stream() // Use a list to keep it ordered
|
||||
.sequential()
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.araymond.joal.core.ttorrent.client.announcer.request;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import org.araymond.joal.core.torrent.torrent.InfoHash;
|
||||
import org.araymond.joal.core.ttorrent.client.announcer.Announcer;
|
||||
|
@ -72,7 +71,7 @@ public class AnnouncerExecutor {
|
|||
}
|
||||
|
||||
public List<Announcer> denyAll() {
|
||||
final Set<InfoHash> infoHashes = Sets.newHashSet(this.currentlyRunning.keySet());
|
||||
final Set<InfoHash> infoHashes = new HashSet<>(this.currentlyRunning.keySet());
|
||||
final List<Announcer> announcersCanceled = new ArrayList<>();
|
||||
|
||||
for (final InfoHash infoHash: infoHashes) {
|
||||
|
|
|
@ -23,65 +23,49 @@ public class AnnounceEventPublisher implements AnnounceResponseHandlerChainEleme
|
|||
|
||||
@Override
|
||||
public void onAnnouncerWillAnnounce(final Announcer announcer, final RequestEvent event) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publish WillAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Publish WillAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.eventPublisher.publishEvent(new WillAnnounceEvent(announcer, event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceStartSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publish SuccessfullyAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Publish SuccessfullyAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.eventPublisher.publishEvent(new SuccessfullyAnnounceEvent(announcer, RequestEvent.STARTED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceStartFails(final Announcer announcer, final Throwable throwable) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publish FailedToAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Publish FailedToAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.eventPublisher.publishEvent(new FailedToAnnounceEvent(announcer, RequestEvent.STARTED, throwable.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceRegularSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publish SuccessfullyAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Publish SuccessfullyAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.eventPublisher.publishEvent(new SuccessfullyAnnounceEvent(announcer, RequestEvent.NONE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceRegularFails(final Announcer announcer, final Throwable throwable) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publish FailedToAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Publish FailedToAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.eventPublisher.publishEvent(new FailedToAnnounceEvent(announcer, RequestEvent.NONE, throwable.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceStopSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publish SuccessfullyAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Publish SuccessfullyAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.eventPublisher.publishEvent(new SuccessfullyAnnounceEvent(announcer, RequestEvent.STOPPED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceStopFails(final Announcer announcer, final Throwable throwable) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publish FailedToAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Publish FailedToAnnounceEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.eventPublisher.publishEvent(new FailedToAnnounceEvent(announcer, RequestEvent.STOPPED, throwable.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTooManyAnnounceFailedInARaw(final Announcer announcer, final TooMuchAnnouncesFailedInARawException e) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publish TooManyAnnouncesFailedEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Publish TooManyAnnouncesFailedEvent event for {}.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.eventPublisher.publishEvent(new TooManyAnnouncesFailedEvent(announcer));
|
||||
}
|
||||
|
||||
|
|
|
@ -27,33 +27,25 @@ public class AnnounceReEnqueuer implements AnnounceResponseHandlerChainElement {
|
|||
|
||||
@Override
|
||||
public void onAnnounceStartSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Enqueue torrent {} in regular queue.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Enqueue torrent {} in regular queue.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.delayQueue.addOrReplace(AnnounceRequest.createRegular(announcer), result.getInterval(), ChronoUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceStartFails(final Announcer announcer, final Throwable throwable) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Enqueue torrent {} in start queue once again (because it failed).", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Enqueue torrent {} in start queue once again (because it failed).", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.delayQueue.addOrReplace(AnnounceRequest.createStart(announcer), announcer.getLastKnownInterval(), ChronoUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceRegularSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Enqueue torrent {} in regular queue.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Enqueue torrent {} in regular queue.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.delayQueue.addOrReplace(AnnounceRequest.createRegular(announcer), result.getInterval(), ChronoUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnnounceRegularFails(final Announcer announcer, final Throwable throwable) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Enqueue torrent {} in regular queue once again (because it failed).", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Enqueue torrent {} in regular queue once again (because it failed).", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.delayQueue.addOrReplace(AnnounceRequest.createRegular(announcer), announcer.getLastKnownInterval(), ChronoUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
@ -63,9 +55,7 @@ public class AnnounceReEnqueuer implements AnnounceResponseHandlerChainElement {
|
|||
|
||||
@Override
|
||||
public void onAnnounceStopFails(final Announcer announcer, final Throwable throwable) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Enqueue torrent {} in stop queue once again (because it failed).", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Enqueue torrent {} in stop queue once again (because it failed).", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.delayQueue.addOrReplace(AnnounceRequest.createStop(announcer), 0, ChronoUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ import org.araymond.joal.core.ttorrent.client.announcer.exceptions.TooMuchAnnoun
|
|||
import org.araymond.joal.core.ttorrent.client.announcer.request.SuccessAnnounceResponse;
|
||||
|
||||
public interface AnnounceResponseCallback {
|
||||
void onAnnounceWillAnnounce(final RequestEvent event, final Announcer announcer);
|
||||
void onAnnounceSuccess(final RequestEvent event, final Announcer announcer, final SuccessAnnounceResponse result);
|
||||
void onAnnounceFailure(final RequestEvent event, final Announcer announcer, final Throwable throwable);
|
||||
void onTooManyAnnounceFailedInARaw(final RequestEvent event, final Announcer announcer, final TooMuchAnnouncesFailedInARawException e);
|
||||
void onAnnounceWillAnnounce(RequestEvent event, Announcer announcer);
|
||||
void onAnnounceSuccess(RequestEvent event, Announcer announcer, SuccessAnnounceResponse result);
|
||||
void onAnnounceFailure(RequestEvent event, Announcer announcer, Throwable throwable);
|
||||
void onTooManyAnnounceFailedInARaw(RequestEvent event, Announcer announcer, TooMuchAnnouncesFailedInARawException e);
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ import org.araymond.joal.core.ttorrent.client.announcer.exceptions.TooMuchAnnoun
|
|||
import org.araymond.joal.core.ttorrent.client.announcer.request.SuccessAnnounceResponse;
|
||||
|
||||
public interface AnnounceResponseHandlerChainElement {
|
||||
void onAnnouncerWillAnnounce(final Announcer announcer, RequestEvent event);
|
||||
void onAnnounceStartSuccess(final Announcer announcer, final SuccessAnnounceResponse result);
|
||||
void onAnnounceStartFails(final Announcer announcer, final Throwable throwable);
|
||||
void onAnnounceRegularSuccess(final Announcer announcer, final SuccessAnnounceResponse result);
|
||||
void onAnnounceRegularFails(final Announcer announcer, final Throwable throwable);
|
||||
void onAnnounceStopSuccess(final Announcer announcer, final SuccessAnnounceResponse result);
|
||||
void onAnnounceStopFails(final Announcer announcer, final Throwable throwable);
|
||||
void onTooManyAnnounceFailedInARaw(final Announcer announcer, final TooMuchAnnouncesFailedInARawException e);
|
||||
void onAnnouncerWillAnnounce(Announcer announcer, RequestEvent event);
|
||||
void onAnnounceStartSuccess(Announcer announcer, SuccessAnnounceResponse result);
|
||||
void onAnnounceStartFails(Announcer announcer, Throwable throwable);
|
||||
void onAnnounceRegularSuccess(Announcer announcer, SuccessAnnounceResponse result);
|
||||
void onAnnounceRegularFails(Announcer announcer, Throwable throwable);
|
||||
void onAnnounceStopSuccess(Announcer announcer, SuccessAnnounceResponse result);
|
||||
void onAnnounceStopFails(Announcer announcer, Throwable throwable);
|
||||
void onTooManyAnnounceFailedInARaw(Announcer announcer, TooMuchAnnouncesFailedInARawException e);
|
||||
}
|
||||
|
|
|
@ -24,9 +24,7 @@ public class BandwidthDispatcherNotifier implements AnnounceResponseHandlerChain
|
|||
|
||||
@Override
|
||||
public void onAnnounceStartSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Register {} in bandwidth dispatcher and update stats.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Register {} in bandwidth dispatcher and update stats.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
final InfoHash infoHash = announcer.getTorrentInfoHash();
|
||||
this.bandwidthDispatcher.registerTorrent(infoHash);
|
||||
this.bandwidthDispatcher.updateTorrentPeers(infoHash, result.getSeeders(), result.getLeechers());
|
||||
|
@ -38,9 +36,7 @@ public class BandwidthDispatcherNotifier implements AnnounceResponseHandlerChain
|
|||
|
||||
@Override
|
||||
public void onAnnounceRegularSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Update {} stats in bandwidth dispatcher.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Update {} stats in bandwidth dispatcher.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
final InfoHash infoHash = announcer.getTorrentInfoHash();
|
||||
this.bandwidthDispatcher.updateTorrentPeers(infoHash, result.getSeeders(), result.getLeechers());
|
||||
}
|
||||
|
@ -51,9 +47,7 @@ public class BandwidthDispatcherNotifier implements AnnounceResponseHandlerChain
|
|||
|
||||
@Override
|
||||
public void onAnnounceStopSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Unregister {} from bandwidth dispatcher.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Unregister {} from bandwidth dispatcher.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.bandwidthDispatcher.unregisterTorrent(announcer.getTorrentInfoHash());
|
||||
}
|
||||
|
||||
|
@ -63,9 +57,7 @@ public class BandwidthDispatcherNotifier implements AnnounceResponseHandlerChain
|
|||
|
||||
@Override
|
||||
public void onTooManyAnnounceFailedInARaw(final Announcer announcer, final TooMuchAnnouncesFailedInARawException e) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Unregister {} from bandwidth dispatcher.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
}
|
||||
logger.debug("Unregister {} from bandwidth dispatcher.", announcer.getTorrentInfoHash().humanReadableValue());
|
||||
this.bandwidthDispatcher.unregisterTorrent(announcer.getTorrentInfoHash());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,9 +45,7 @@ public class ClientNotifier implements AnnounceResponseHandlerChainElement {
|
|||
|
||||
@Override
|
||||
public void onAnnounceStopSuccess(final Announcer announcer, final SuccessAnnounceResponse result) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Notify client that a torrent has stopped.");
|
||||
}
|
||||
logger.debug("Notify client that a torrent has stopped.");
|
||||
this.client.onTorrentHasStopped(announcer);
|
||||
}
|
||||
|
||||
|
@ -57,9 +55,7 @@ public class ClientNotifier implements AnnounceResponseHandlerChainElement {
|
|||
|
||||
@Override
|
||||
public void onTooManyAnnounceFailedInARaw(final Announcer announcer, final TooMuchAnnouncesFailedInARawException e) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Notify client that a torrent has failed too many times.");
|
||||
}
|
||||
logger.debug("Notify client that a torrent has failed too many times.");
|
||||
this.client.onTooManyFailedInARaw(announcer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,8 +73,7 @@ public class TrackerClient {
|
|||
final AnnounceResponseMessage announceResponseMessage = (AnnounceResponseMessage) responseMessage;
|
||||
|
||||
final int interval = announceResponseMessage.getInterval();
|
||||
// Subtract one to seeders since we are one of them.
|
||||
final int seeders = announceResponseMessage.getComplete() == 0 ? 0 : announceResponseMessage.getComplete() - 1;
|
||||
final int seeders = announceResponseMessage.getComplete() == 0 ? 0 : announceResponseMessage.getComplete() - 1; // Subtract one to seeders since we are one of them
|
||||
final int leechers = announceResponseMessage.getIncomplete();
|
||||
return new SuccessAnnounceResponse(interval, seeders, leechers);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.araymond.joal.core.ttorrent.client.announcer.tracker;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -9,8 +8,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
public class TrackerClientUriProvider {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TrackerClientUriProvider.class);
|
||||
|
||||
private final Iterator<URI> addressIterator;
|
||||
private URI currentURI = null;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public class TrackerResponseHandler implements ResponseHandler<TrackerMessage> {
|
|||
}
|
||||
|
||||
final int contentLength = entity.getContentLength() < 1 ? 1024 : (int) entity.getContentLength();
|
||||
try(final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(contentLength)) {
|
||||
try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(contentLength)) {
|
||||
if (response.getStatusLine().getStatusCode() >= 300) {
|
||||
logger.warn("Tracker response is an error.");
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public class JacksonConfig {
|
|||
/**
|
||||
* Forces the timezone to be added to every LocalDateTime
|
||||
*/
|
||||
public static final class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
|
||||
public static final class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
|
||||
@Override
|
||||
public void serialize(final LocalDateTime value, final JsonGenerator gen, final SerializerProvider serializers) throws IOException {
|
||||
final ZonedDateTime zonedDateTime = value.atZone(ZoneId.systemDefault());
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
package org.araymond.joal.web.config;
|
||||
|
||||
import org.araymond.joal.web.annotations.ConditionalOnWebUi;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.*;
|
||||
|
||||
@ConditionalOnWebUi
|
||||
// Do not use @EnableWebMvc as it will remove all the default springboot config.
|
||||
|
|
|
@ -20,9 +20,9 @@ public class JoalMessageSendingTemplate {
|
|||
this.messageSendingOperations = messageSendingOperations;
|
||||
}
|
||||
|
||||
public void convertAndSend(final String s, final MessagePayload payload) throws MessagingException {
|
||||
public void convertAndSend(final String destination, final MessagePayload payload) throws MessagingException {
|
||||
final StompMessage stompMessage = StompMessage.wrap(payload);
|
||||
messageSendingOperations.convertAndSend(s, stompMessage);
|
||||
messageSendingOperations.convertAndSend(destination, stompMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package org.araymond.joal.core.events.speed;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.araymond.joal.core.bandwith.Speed;
|
||||
import org.araymond.joal.core.torrent.torrent.InfoHash;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -13,7 +13,7 @@ public class SeedingSpeedsHasChangedEventTest {
|
|||
|
||||
@Test
|
||||
public void shouldBuild() {
|
||||
final Map<InfoHash, Speed> speeds = Maps.newHashMap();
|
||||
final Map<InfoHash, Speed> speeds = new HashMap<>();
|
||||
final SeedingSpeedsHasChangedEvent event = new SeedingSpeedsHasChangedEvent(speeds);
|
||||
|
||||
assertThat(event.getSpeeds()).isEqualTo(speeds);
|
||||
|
|
Loading…
Reference in a new issue