📄 startstoprulesdefaultplugin.java
字号:
/*
* File : StartStopRulesDefaultPlugin.java
* Created : 12-Jan-2004
* By : TuxPaper
*
* Azureus - a Java Bittorrent client
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details ( see the LICENSE file ).
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.aelitis.azureus.plugins.startstoprules.defaultplugin;
import java.util.*;
import org.gudy.azureus2.core3.config.COConfigurationListener;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.plugins.Plugin;
import org.gudy.azureus2.plugins.PluginConfig;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.PluginListener;
import org.gudy.azureus2.plugins.disk.DiskManagerFileInfo;
import org.gudy.azureus2.plugins.download.*;
import org.gudy.azureus2.plugins.logging.LoggerChannel;
import org.gudy.azureus2.plugins.ui.UIInstance;
import org.gudy.azureus2.plugins.ui.UIManagerListener;
import org.gudy.azureus2.plugins.ui.menus.MenuItem;
import org.gudy.azureus2.plugins.ui.menus.MenuItemListener;
import org.gudy.azureus2.plugins.ui.tables.TableColumn;
import org.gudy.azureus2.plugins.ui.tables.TableContextMenuItem;
import org.gudy.azureus2.plugins.ui.tables.TableManager;
import org.gudy.azureus2.plugins.ui.tables.TableRow;
import org.gudy.azureus2.ui.swt.plugins.UISWTInstance;
import com.aelitis.azureus.plugins.startstoprules.defaultplugin.ui.swt.StartStopRulesDefaultPluginSWTUI;
/** Handles Starting and Stopping of torrents.
*
* TODO: RANK_TIMED is quite a hack and is spread all over. It needs to be
* redone, probably with a timer on each seeding torrent which triggers
* when time is up and it needs to stop.
*
* BUG: When "AutoStart 0 Peers" is on, and minSpeedForActivelySeeding is
* enabled, the 0 peer torrents will continuously switch from seeding to
* queued, probably due to the connection attempt registering speed.
* This might be fixed by the "wait XX ms before switching active state"
* code.
*
* Other Notes:
* "CD" is often used to refer to "Seed" or "Seeding", because "C" sounds like
* "See"
*/
public class StartStopRulesDefaultPlugin
implements Plugin, COConfigurationListener
{
// for debugging
private static final String sStates = " WPRDS.XEQ";
/** Do not rank completed torrents */
public static final int RANK_NONE = 0;
/** Rank completed torrents using Seeds:Peer Ratio */
public static final int RANK_SPRATIO = 1;
/** Rank completed torrents using Seed Count method */
public static final int RANK_SEEDCOUNT = 2;
/** Rank completed torrents using a timed rotation of minTimeAlive */
public static final int RANK_TIMED = 3;
/**
* Force at least one check every period of time (in ms).
* Used in ChangeFlagCheckerTask
*/
private static final int FORCE_CHECK_PERIOD = 30000;
/**
* Check for non triggerable changes ever period of time (in ms)
*/
private static final int CHECK_FOR_GROSS_CHANGE_PERIOD= 30000;
/**
* Interval in ms between checks to see if the {@link #somethingChanged}
* flag changed
*/
private static final int PROCESS_CHECK_PERIOD = 500;
/** Wait xx ms before starting completed torrents (so scrapes can come in) */
private static final int MIN_SEEDING_STARTUP_WAIT = 20000;
/** Wait at least xx ms for first scrape, before starting completed torrents */
private static final int MIN_FIRST_SCRAPE_WAIT = 90000;
// Core/Plugin classes
private AEMonitor this_mon = new AEMonitor( "StartStopRules" );
private PluginInterface plugin_interface;
protected PluginConfig plugin_config;
private DownloadManager download_manager;
protected LoggerChannel log;
private Timer changeCheckerTimer;
/** Used only for RANK_TIMED. Recalculate ranks on a timer */
private TimerTask recalcSeedingRanksTask;
/** Map to relate downloadData to a Download */
private static Map downloadDataMap = AEMonitor.getSynchronisedMap(new HashMap());
private volatile boolean closingDown;
private volatile boolean somethingChanged;
/** When rules class started. Used for initial waiting logic */
private long startedOn;
// Config Settings
/** Whether Debug Info is written to the log and tooltip */
protected boolean bDebugLog;
/** Ranking System to use. One of RANK_* constants */
private int iRankType = -1;
private int minSpeedForActiveSeeding;
// count x peers as a full copy, but..
private int numPeersAsFullCopy;
// don't count x peers as a full copy if seeds below
private int iFakeFullCopySeedStart;
private int _maxActive;
private boolean _maxActiveWhenSeedingEnabled;
private int _maxActiveWhenSeeding;
private int maxDownloads;
private boolean bAutoReposition;
private long minTimeAlive;
private boolean bAutoStart0Peers;
private int iMaxUploadSpeed;
private static boolean bAlreadyInitialized = false;
// UI
private TableColumn seedingRankColumn;
// UI
private TableContextMenuItem debugMenuItem = null;
private boolean bSWTUI = false;
public void initialize(PluginInterface _plugin_interface) {
if (bAlreadyInitialized) {
System.err.println("StartStopRulesDefaultPlugin Already initialized!!");
} else {
bAlreadyInitialized = true;
}
startedOn = SystemTime.getCurrentTime();
changeCheckerTimer = new Timer(true);
plugin_interface = _plugin_interface;
plugin_interface.getPluginProperties().setProperty( "plugin.version", "1.0" );
plugin_interface.getPluginProperties().setProperty( "plugin.name", "Start/Stop Rules" );
plugin_interface.addListener(new PluginListener() {
public void initializationComplete() { /* not implemented */ }
public void
closedownInitiated()
{
closingDown = true;
// we don't want to go off recalculating stuff when config is saved on closedown
COConfigurationManager.removeListener(StartStopRulesDefaultPlugin.this);
}
public void closedownComplete() { /* not implemented */ }
});
log = plugin_interface.getLogger().getChannel("StartStopRules");
log.log( LoggerChannel.LT_INFORMATION, "Default StartStopRules Plugin Initialisation" );
COConfigurationManager.addListener(this);
plugin_config = plugin_interface.getPluginconfig();
try {
TableManager tm = plugin_interface.getUIManager().getTableManager();
seedingRankColumn = tm.createColumn(TableManager.TABLE_MYTORRENTS_COMPLETE,
"SeedingRank");
seedingRankColumn.initialize(TableColumn.ALIGN_TRAIL, TableColumn.POSITION_LAST,
80, TableColumn.INTERVAL_LIVE);
SeedingRankColumnListener columnListener = new SeedingRankColumnListener(downloadDataMap, plugin_config);
seedingRankColumn.addCellRefreshListener(columnListener);
tm.addColumn(seedingRankColumn);
plugin_interface.getUIManager().addUIListener(
new UIManagerListener()
{
public void
UIAttached(
UIInstance instance )
{
if ( instance instanceof UISWTInstance ){
bSWTUI = true;
new StartStopRulesDefaultPluginSWTUI( plugin_interface );
}
}
public void
UIDetached(
UIInstance instance )
{
}
});
} catch( Throwable e ){
Debug.printStackTrace( e );
}
reloadConfigParams();
download_manager = plugin_interface.getDownloadManager();
download_manager.addListener(new StartStopDMListener());
changeCheckerTimer.schedule(new ChangeCheckerTimerTask(), 10000, CHECK_FOR_GROSS_CHANGE_PERIOD );
changeCheckerTimer.schedule(new ChangeFlagCheckerTask(), 10000, PROCESS_CHECK_PERIOD );
}
public static DefaultRankCalculator getRankCalculator(Download dl) {
return (DefaultRankCalculator)downloadDataMap.get(dl);
}
private void recalcAllSeedingRanks(boolean force) {
if ( closingDown ){
return;
}
try{
this_mon.enter();
DefaultRankCalculator[] dlDataArray =
(DefaultRankCalculator[])downloadDataMap.values().toArray(new DefaultRankCalculator[0]);
// Check Group #1: Ones that always should run since they set things
for (int i = 0; i < dlDataArray.length; i++) {
if (force)
dlDataArray[i].getDownloadObject().setSeedingRank(0);
dlDataArray[i].recalcSeedingRank();
}
}finally{
this_mon.exit();
}
}
/** A simple timer task to recalculate all seeding ranks.
*/
private class RecalcSeedingRanksTask extends TimerTask
{
public void run() {
// System.out.println("RecalcAllSeedingRanks");
recalcAllSeedingRanks(false);
}
}
/** This class check if the somethingChanged flag and call process() when
* its set. This allows pooling of changes, thus cutting down on the number
* of sucessive process() calls.
*/
private class ChangeFlagCheckerTask extends TimerTask
{
long last_process_time = 0;
public void run() {
if (closingDown)
return;
long now = SystemTime.getCurrentTime();
if ( now < last_process_time ||
now - last_process_time >= FORCE_CHECK_PERIOD ){
somethingChanged = true;
}
if (somethingChanged) {
try {
last_process_time = now;
process();
} catch( Exception e ) {
Debug.printStackTrace( e );
}
}
}
}
/** Listen to Download changes and recalc SR if needed
*/
private class StartStopDownloadListener implements DownloadListener
{
public void stateChanged(Download download, int old_state, int new_state) {
DefaultRankCalculator dlData = (DefaultRankCalculator)downloadDataMap.get(download);
if (dlData != null) {
// force a SR recalc, so that it gets positiong properly next process()
dlData.recalcSeedingRank();
somethingChanged = true;
if (bDebugLog)
log.log(dlData.dl.getTorrent(), LoggerChannel.LT_INFORMATION,
"somethingChanged: stateChange from " + sStates.charAt(old_state)
+ " (" + old_state + ") to " + sStates.charAt(new_state)
+ " (" + new_state + ")");
}
}
public void positionChanged(Download download,
int oldPosition, int newPosition) {
DefaultRankCalculator dlData = (DefaultRankCalculator)downloadDataMap.get(download);
if (dlData != null) {
dlData.recalcSeedingRank();
somethingChanged = true;
if (bDebugLog)
log.log(dlData.dl.getTorrent(), LoggerChannel.LT_INFORMATION,
"somethingChanged: positionChanged from " + oldPosition + " to "
+ newPosition);
}
}
}
/** Update SeedingRank when a new scrape result comes in.
*/
private class StartStopDMTrackerListener implements DownloadTrackerListener
{
public void scrapeResult( DownloadScrapeResult result ) {
Download dl = result.getDownload();
// Skip if error (which happens when listener is first added and the
// torrent isn't scraped yet)
if (result.getResponseType() == DownloadScrapeResult.RT_ERROR) {
if (bDebugLog)
log.log(dl.getTorrent(), LoggerChannel.LT_INFORMATION,
"Ignored somethingChanged: new scrapeResult (RT_ERROR)");
return;
}
DefaultRankCalculator dlData = (DefaultRankCalculator)downloadDataMap.get(dl);
if (dlData != null) {
dlData.recalcSeedingRank();
somethingChanged = true;
if (bDebugLog)
log.log(dl.getTorrent(), LoggerChannel.LT_INFORMATION,
"somethingChanged: new scrapeResult S:" + result.getSeedCount()
+ ";P:" + result.getNonSeedCount());
}
}
public void announceResult( DownloadAnnounceResult result ) {
// Announces are useless to us. Even if the announce contains seed/peer
// count, they are not stored in the DownloadAnnounceResult. Instead,
// they are passed off to the DownloadScrapeResult, and a scrapeResult
// is triggered
}
}
/* Create/Remove downloadData object when download gets added/removed.
* RecalcSeedingRank & process if necessary.
*/
private class StartStopDMListener implements DownloadManagerListener
{
private DownloadTrackerListener download_tracker_listener;
private DownloadListener download_listener;
public StartStopDMListener() {
download_tracker_listener = new StartStopDMTrackerListener();
download_listener = new StartStopDownloadListener();
}
public void downloadAdded( Download download )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -