package com.limegroup.gnutella;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.limewire.bittorrent.Torrent;
import org.limewire.bittorrent.TorrentManager;
import org.limewire.bittorrent.TorrentStatus;
import org.limewire.core.settings.DownloadSettings;
import org.limewire.core.settings.UploadSettings;
import org.limewire.inject.EagerSingleton;
import org.limewire.statistic.BasicKilobytesStatistic;
import org.limewire.statistic.Statistic;
import org.limewire.statistic.StatisticAccumulator;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;
@EagerSingleton
public class BandwidthCollectorImpl implements BandwidthCollectorDriver {
private final Provider<ConnectionManager> connectionManager;
private final Provider<BandwidthTracker> uploadTracker;
private final Provider<BandwidthTracker> downloadTracker;
private final Provider<TorrentManager> torrentManager;
// these inspections include:
// gnutella downloads and uploads, torrents,
// gnutella messaging and mozilla downloads.
// missing gnutella dht, missing torrent dht, missing other connection types
/**
* 200 measurements are saved, 1 per second.
*/
private final Statistic uploadStat; //
/**
* 200 measurements are saved, 1 per second.
*/
private final Statistic downloadStat;
private final AtomicInteger currentTotalUploadBandwidthKiloBytes = new AtomicInteger(0);
private final AtomicInteger currentTotalDownloadBandwidthKiloBytes = new AtomicInteger(0);
private final AtomicInteger currentUploaderPayloadBandwidthKiloBytes = new AtomicInteger(0);
private final AtomicInteger currentDownloaderPayloadBandwidthKiloBytes = new AtomicInteger(0);
@Inject
public BandwidthCollectorImpl(@Named("uploadTracker") Provider<BandwidthTracker> uploadTracker,
@Named("downloadTracker") Provider<BandwidthTracker> downloadTracker,
Provider<ConnectionManager> connectionManager,
StatisticAccumulator statisticAccumulator, Provider<TorrentManager> torrentManager) {
this.uploadTracker = uploadTracker;
this.downloadTracker = downloadTracker;
this.connectionManager = connectionManager;
this.torrentManager = torrentManager;
this.uploadStat = new BandwidthStat(statisticAccumulator);
this.downloadStat = new BandwidthStat(statisticAccumulator);
}
@Override
public int getMaxMeasuredTotalDownloadBandwidth() {
return DownloadSettings.MAX_MEASURED_DOWNLOAD_KBPS.getValue();
}
@Override
public int getMaxMeasuredTotalUploadBandwidth() {
return UploadSettings.MAX_MEASURED_UPLOAD_KBPS.getValue();
}
@Override
public int getCurrentTotalDownloadBandwidth() {
return currentTotalDownloadBandwidthKiloBytes.get();
}
@Override
public int getCurrentTotalUploadBandwidth() {
return currentTotalUploadBandwidthKiloBytes.get();
}
@Override
public int getCurrentDownloaderBandwidth() {
return currentDownloaderPayloadBandwidthKiloBytes.get();
}
@Override
public int getCurrentUploaderBandwidth() {
return currentUploaderPayloadBandwidthKiloBytes.get();
}
/**
* Collects data on the bandwidth that has been used for file uploads and
* downloads.
*/
@Override
public void collectBandwidthData() {
uploadTracker.get().measureBandwidth();
downloadTracker.get().measureBandwidth();
connectionManager.get().measureBandwidth();
float uploadTrackerBandwidth = getUploadTrackerBandwidth();
float downloadTrackerBandwidth = getDownloadTrackerBandwidth();
float connectionManagerUploadBandwidth = connectionManager.get()
.getMeasuredUpstreamBandwidth();
float connectionManagerDownloadBandwidth = connectionManager.get()
.getMeasuredDownstreamBandwidth();
List<Torrent> torrents = torrentManager.get().getTorrents();
float torrentUploadBandwidth = calculateTorrentUpstreamBandwidth(torrents);
float torrentUploadPayloadBandwidth = calculateTorrentUpstreamPayloadBandwidth(torrents);
int newUpstreamKiloBytesPerSec = (int) addPositive(addPositive(uploadTrackerBandwidth, connectionManagerUploadBandwidth), torrentUploadBandwidth);
int newUploaderKiloBytesPerSec = (int) addPositive(uploadTrackerBandwidth, torrentUploadPayloadBandwidth);
uploadStat.addData(newUpstreamKiloBytesPerSec);
// TODO downstream kilobytes per sec is missing non payload torrent
// bandwidth.
int newDownstreamKiloBytesPerSec = (int) addPositive(downloadTrackerBandwidth, connectionManagerDownloadBandwidth);
int newDownloaderKiloBytesPerSec = (int) addPositive(0, downloadTrackerBandwidth);
downloadStat.addData(newDownstreamKiloBytesPerSec);
int maxUpstreamKiloBytesPerSec = getMaxMeasuredTotalUploadBandwidth();
if (newUpstreamKiloBytesPerSec > maxUpstreamKiloBytesPerSec) {
maxUpstreamKiloBytesPerSec = newUpstreamKiloBytesPerSec;
UploadSettings.MAX_MEASURED_UPLOAD_KBPS.setValue(maxUpstreamKiloBytesPerSec);
}
int maxDownstreamKiloBytesPerSec = getMaxMeasuredTotalDownloadBandwidth();
if (newDownstreamKiloBytesPerSec > maxDownstreamKiloBytesPerSec) {
maxDownstreamKiloBytesPerSec = newDownstreamKiloBytesPerSec;
DownloadSettings.MAX_MEASURED_DOWNLOAD_KBPS.setValue(maxDownstreamKiloBytesPerSec);
}
currentDownloaderPayloadBandwidthKiloBytes.set(newDownloaderKiloBytesPerSec);
currentUploaderPayloadBandwidthKiloBytes.set(newUploaderKiloBytesPerSec);
currentTotalDownloadBandwidthKiloBytes.set(newDownstreamKiloBytesPerSec);
currentTotalUploadBandwidthKiloBytes.set(newUpstreamKiloBytesPerSec);
}
private float getDownloadTrackerBandwidth() {
float bandwidth;
try {
// this includes torrents
bandwidth = downloadTracker.get().getMeasuredBandwidth();
} catch (InsufficientDataException ide) {
bandwidth = 0;
}
return bandwidth;
}
private float getUploadTrackerBandwidth() {
float bandwidth;
try {
// this does not include torrents
bandwidth = uploadTracker.get().getMeasuredBandwidth();
} catch (InsufficientDataException ide) {
bandwidth = 0;
}
return bandwidth;
}
/**
* Returns the torrent upstream bandwidth in kilobytes per second.
*/
private float calculateTorrentUpstreamBandwidth(List<Torrent> torrents) {
float rate = 0;
for (Torrent torrent : torrentManager.get().getTorrents()) {
TorrentStatus torrentStatus = torrent.getStatus();
if (torrentStatus != null) {
rate = addPositive(rate, torrentStatus.getUploadRate());
}
}
return rate / 1024;
}
/**
* Returns the torrent upstream payload bandwidth in kilobytes per second.
*/
private float calculateTorrentUpstreamPayloadBandwidth(List<Torrent> torrents) {
float rate = 0;
for (Torrent torrent : torrentManager.get().getTorrents()) {
TorrentStatus torrentStatus = torrent.getStatus();
if (torrentStatus != null) {
// ignoring paused torrents because the rate takes a while to
// cycle down event though the number should be zero.
if (!torrentStatus.isPaused()) {
rate = addPositive(rate, torrentStatus.getUploadPayloadRate());
}
}
}
return rate / 1024;
}
private class BandwidthStat extends BasicKilobytesStatistic {
public BandwidthStat(StatisticAccumulator statisticAccumulator) {
super(statisticAccumulator);
}
}
/**
* Adds positive numbers in the list together returning the sum.
*/
private float addPositive(float one, float two) {
float sum = 0;
if(one > 0) {
sum += one;
}
if(two > 0) {
sum += two;
}
return sum;
}
}