📄 globalmanagerimpl.java
字号:
/*
* File : GlobalManagerImpl.java
* Created : 21-Oct-2003
* By : stuff
*
* 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 org.gudy.azureus2.core3.global.impl;
/*
* Created on 30 juin 2003
*
*/
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.NetworkInterface;
import java.net.URL;
import java.util.*;
import org.gudy.azureus2.core3.category.Category;
import org.gudy.azureus2.core3.category.CategoryManager;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.download.*;
import org.gudy.azureus2.core3.download.impl.DownloadManagerAdapter;
import org.gudy.azureus2.core3.global.*;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.peer.PEPeerManager;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentException;
import org.gudy.azureus2.core3.tracker.client.*;
import org.gudy.azureus2.core3.tracker.util.TRTrackerUtils;
import org.gudy.azureus2.core3.tracker.util.TRTrackerUtilsListener;
import org.gudy.azureus2.core3.util.*;
import com.aelitis.azureus.core.AzureusCore;
import com.aelitis.azureus.core.helpers.TorrentFolderWatcher;
import com.aelitis.azureus.core.util.CopyOnWriteList;
import org.gudy.azureus2.plugins.network.ConnectionManager;
/**
* @author Olivier
*
*/
public class GlobalManagerImpl
extends DownloadManagerAdapter
implements GlobalManager, AEDiagnosticsEvidenceGenerator
{
private static final LogIDs LOGID = LogIDs.CORE;
// GlobalManagerListener support
// Must be an async listener to support the non-synchronised invocation of
// listeners when a new listener is added and existing downloads need to be
// reported
private static final int LDT_MANAGER_ADDED = 1;
private static final int LDT_MANAGER_REMOVED = 2;
private static final int LDT_DESTROY_INITIATED = 3;
private static final int LDT_DESTROYED = 4;
private static final int LDT_SEEDING_ONLY = 5;
private ListenerManager listeners = ListenerManager.createAsyncManager(
"GM:ListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object value )
{
GlobalManagerListener target = (GlobalManagerListener)_listener;
if ( type == LDT_MANAGER_ADDED ){
target.downloadManagerAdded((DownloadManager)value);
}else if ( type == LDT_MANAGER_REMOVED ){
target.downloadManagerRemoved((DownloadManager)value);
}else if ( type == LDT_DESTROY_INITIATED ){
target.destroyInitiated();
}else if ( type == LDT_DESTROYED ){
target.destroyed();
}else if ( type == LDT_SEEDING_ONLY ){
target.seedingStatusChanged( ((Boolean)value).booleanValue() );
}
}
});
// GlobalManagerDownloadWillBeRemovedListener support
// Not async (doesn't need to be and can't be anyway coz it has an exception)
private static final int LDT_MANAGER_WBR = 1;
private ListenerManager removal_listeners = ListenerManager.createManager(
"GM:DLWBRMListenDispatcher",
new ListenerManagerDispatcherWithException()
{
public void
dispatchWithException(
Object _listener,
int type,
Object value )
throws GlobalManagerDownloadRemovalVetoException
{
GlobalManagerDownloadWillBeRemovedListener target = (GlobalManagerDownloadWillBeRemovedListener)_listener;
target.downloadWillBeRemoved((DownloadManager)value);
}
});
private List managers_cow = new ArrayList();
private AEMonitor managers_mon = new AEMonitor( "GM:Managers" );
private Map manager_map = new HashMap();
private Checker checker;
private GlobalManagerStatsImpl stats;
private long last_swarm_stats_calc_time = 0;
private long last_swarm_stats = 0;
private TRTrackerScraper trackerScraper;
private GlobalManagerStatsWriter stats_writer;
private GlobalManagerHostSupport host_support;
private Map saved_download_manager_state = new HashMap();
private int next_seed_piece_recheck_index;
private TorrentFolderWatcher torrent_folder_watcher;
private ArrayList paused_list = new ArrayList();
private final AEMonitor paused_list_mon = new AEMonitor( "GlobalManager:PL" );
/* Whether the GlobalManager is active (false) or stopped (true) */
private volatile boolean isStopping;
private volatile boolean destroyed;
private volatile boolean needsSaving = false;
private boolean seeding_only_mode = false;
private FrequencyLimitedDispatcher check_seeding_only_state_dispatcher =
new FrequencyLimitedDispatcher(
new AERunnable(){ public void runSupport(){ checkSeedingOnlyStateSupport(); }}, 5000 );
private int nat_status = ConnectionManager.NAT_UNKNOWN;
private boolean nat_status_probably_ok;
private Set old_network_interfaces;
private long last_network_change;
private CopyOnWriteList dm_adapters = new CopyOnWriteList();
/** delay loading of torrents */
DelayedEvent loadTorrentsDelay = null;
/** Whether loading of existing torrents is done */
boolean loadingComplete = false;
/** Monitor to block adding torrents while loading existing torrent list */
AESemaphore loadingSem = new AESemaphore("Loading Torrents");
public class Checker extends AEThread {
int loopFactor;
private static final int waitTime = 10*1000;
// 5 minutes save resume data interval (default)
private int saveResumeLoopCount = 5*60*1000 / waitTime;
private int netCheckLoopCount = 60*1000 / waitTime;
private int natCheckLoopCount = 30*1000 / waitTime;
private int seedPieceCheckCount = 30*1000 / waitTime;
private AESemaphore run_sem = new AESemaphore( "GM:Checker:run");
public Checker() {
super("Global Status Checker");
loopFactor = 0;
setPriority(Thread.MIN_PRIORITY);
//determineSaveResumeDataInterval();
}
private void determineSaveResumeDataInterval() {
int saveResumeInterval = COConfigurationManager.getIntParameter("Save Resume Interval", 5);
if (saveResumeInterval >= 1 && saveResumeInterval <= 90)
saveResumeLoopCount = saveResumeInterval * 60000 / waitTime;
}
public void
runSupport()
{
while ( true ){
try{
loopFactor++;
determineSaveResumeDataInterval();
if ((loopFactor % saveResumeLoopCount == 0) || needsSaving) {
saveDownloads( true );
}
if ((loopFactor % netCheckLoopCount == 0)) {
checkNetwork();
}
if ((loopFactor % natCheckLoopCount == 0)) {
computeNATStatus();
// we need this periodic check to pick up on DND file state changes (someone changes
// a file from DND to normal and consequentially changes to a non-seeding mode).
// Doing this via listeners is too much effort
checkSeedingOnlyState();
}
if ((loopFactor % seedPieceCheckCount == 0)) {
seedPieceRecheck();
}
for (Iterator it=managers_cow.iterator();it.hasNext();) {
DownloadManager manager = (DownloadManager)it.next();
if ( loopFactor % saveResumeLoopCount == 0 ) {
manager.saveResumeData();
}
/*
* seeding rules have been moved to StartStopRulesDefaultPlugin
*/
// Handle forced starts here
if ( manager.getState() == DownloadManager.STATE_READY &&
manager.isForceStart()) {
manager.startDownload();
}
}
}catch( Throwable e ){
Debug.printStackTrace( e );
}
try {
run_sem.reserve(waitTime);
if ( run_sem.isReleasedForever()){
break;
}
}
catch (Exception e) {
Debug.printStackTrace( e );
}
}
}
public void stopIt() {
run_sem.releaseForever();
}
}
public
GlobalManagerImpl(
AzureusCore core,
final GlobalMangerProgressListener listener,
long existingTorrentLoadDelay)
{
//Debug.dumpThreadsLoop("Active threads");
AEDiagnostics.addEvidenceGenerator( this );
stats = new GlobalManagerStatsImpl( this );
try{
stats_writer = new GlobalManagerStatsWriter( core );
}catch( Throwable e ){
Logger.log(new LogEvent(LOGID, "Stats unavailable", e ));
}
// Wait at least a few seconds before loading existing torrents.
// typically the UI will call loadExistingTorrents before this runs
// This is here in case the UI is stupid or forgets
if (existingTorrentLoadDelay > 0) {
loadTorrentsDelay = new DelayedEvent("GM:tld", existingTorrentLoadDelay,
new AERunnable() {
public void runSupport() {
loadExistingTorrentsNow(listener, false); // already async
}
});
} else {
// run sync
loadDownloads(listener);
}
if (listener != null)
listener.reportCurrentTask(MessageText.getString("splash.initializeGM"));
// Initialize scraper after loadDownloads so that we can merge scrapes
// into one request per tracker
trackerScraper = TRTrackerScraperFactory.getSingleton();
trackerScraper.setClientResolver(
new TRTrackerScraperClientResolver()
{
public int
getStatus(
HashWrapper torrent_hash )
{
DownloadManager dm = getDownloadManager(torrent_hash);
if ( dm == null ){
return( TRTrackerScraperClientResolver.ST_NOT_FOUND );
}
int dm_state = dm.getState();
if ( dm_state == DownloadManager.STATE_QUEUED ){
return( TRTrackerScraperClientResolver.ST_QUEUED );
}else if ( dm_state == DownloadManager.STATE_DOWNLOADING ||
dm_state == DownloadManager.STATE_SEEDING ){
return( TRTrackerScraperClientResolver.ST_RUNNING );
}
return( TRTrackerScraperClientResolver.ST_OTHER );
}
public boolean
isNetworkEnabled(
HashWrapper hash,
URL url )
{
DownloadManager dm = getDownloadManager(hash);
if ( dm == null ){
return( false );
}
String nw = AENetworkClassifier.categoriseAddress( url.getHost());
String[] networks = dm.getDownloadState().getNetworks();
for (int i=0;i<networks.length;i++){
if ( networks[i] == nw ){
return( true );
}
}
return( false );
}
public Object[]
getExtensions(
HashWrapper hash )
{
DownloadManager dm = getDownloadManager(hash);
Character state;
String ext;
if ( dm == null ){
ext = "";
state = TRTrackerScraperClientResolver.FL_NONE;
}else{
ext = dm.getDownloadState().getTrackerClientExtensions();
if ( ext == null ){
ext = "";
}
boolean comp = dm.isDownloadComplete( false );
int dm_state = dm.getState();
// treat anything not stopped or running as queued as we need to be "optimistic"
// for torrents at the start-of-day
if ( dm_state == DownloadManager.STATE_ERROR ||
dm_state == DownloadManager.STATE_STOPPED ||
( dm_state == DownloadManager.STATE_STOPPING && dm.getSubState() != DownloadManager.STATE_QUEUED )){
state = comp?TRTrackerScraperClientResolver.FL_COMPLETE_STOPPED:TRTrackerScraperClientResolver.FL_INCOMPLETE_STOPPED;
}else if ( dm_state == DownloadManager.STATE_DOWNLOADING ||
dm_state == DownloadManager.STATE_SEEDING ){
state = comp?TRTrackerScraperClientResolver.FL_COMPLETE_RUNNING:TRTrackerScraperClientResolver.FL_INCOMPLETE_RUNNING;
}else{
state = comp?TRTrackerScraperClientResolver.FL_COMPLETE_QUEUED:TRTrackerScraperClientResolver.FL_INCOMPLETE_QUEUED;
}
}
return( new Object[]{ ext, state });
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -