/* * Created on Mar 22, 2013 * Created by Paul Gardner * * Copyright 2013 Azureus Software, Inc. All rights reserved. * * 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; version 2 of the License only. * * 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. * * 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.core.tag.impl; import java.util.List; import java.util.Map; import java.util.Set; import org.gudy.azureus2.core3.download.DownloadManager; import org.gudy.azureus2.core3.download.DownloadManagerState; import org.gudy.azureus2.core3.download.DownloadManagerStats; import org.gudy.azureus2.core3.util.AERunnable; import org.gudy.azureus2.core3.util.AsyncDispatcher; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.SystemTime; import com.aelitis.azureus.core.networkmanager.LimitedRateGroup; import com.aelitis.azureus.core.tag.Tag; import com.aelitis.azureus.core.tag.TagDownload; import com.aelitis.azureus.core.tag.TagFeature; import com.aelitis.azureus.core.tag.TagFeatureProperties; import com.aelitis.azureus.core.tag.TagFeatureRateLimit; import com.aelitis.azureus.core.tag.TagFeatureRunState; import com.aelitis.azureus.core.tag.TagListener; import com.aelitis.azureus.core.tag.Taggable; public class TagDownloadWithState extends TagWithState implements TagDownload { private int upload_rate_limit; private int download_rate_limit; private int upload_rate = -1; private int download_rate = -1; private long last_rate_update; private Object UPLOAD_PRIORITY_ADDED_KEY = new Object(); private int upload_priority; private int min_share_ratio; private int max_share_ratio; private boolean supports_xcode; private boolean supports_file_location; private LimitedRateGroup upload_limiter = new LimitedRateGroup() { public String getName() { return( "tag_up: " + getTagName( true )); } public int getRateLimitBytesPerSecond() { return( upload_rate_limit ); } public void updateBytesUsed( int used ) { } }; private LimitedRateGroup download_limiter = new LimitedRateGroup() { public String getName() { return( "tag_down: " + getTagName( true )); } public int getRateLimitBytesPerSecond() { return( download_rate_limit ); } public void updateBytesUsed( int used ) { } }; private boolean do_rates; private boolean do_up; private boolean do_down; private int run_states; private static AsyncDispatcher rs_async = new AsyncDispatcher(2000); private TagProperty[] tag_properties = new TagProperty[]{ createTagProperty( TagFeatureProperties.PR_TRACKERS, TagFeatureProperties.PT_STRING_LIST ), createTagProperty( TagFeatureProperties.PR_UNTAGGED, TagFeatureProperties.PT_BOOLEAN ), createTagProperty( TagFeatureProperties.PR_TRACKER_TEMPLATES, TagFeatureProperties.PT_STRING_LIST ), createTagProperty( TagFeatureProperties.PR_CONSTRAINT, TagFeatureProperties.PT_STRING_LIST ) }; public TagDownloadWithState( TagTypeBase tt, int tag_id, String name, boolean do_rates, boolean do_up, boolean do_down, int run_states ) { super( tt, tag_id, name ); init( do_rates, do_up, do_down, run_states ); } protected TagDownloadWithState( TagTypeBase tt, int tag_id, Map details, boolean do_rates, boolean do_up, boolean do_down, int run_states ) { super( tt, tag_id, details ); init( do_rates, do_up, do_down, run_states ); } private void init( boolean _do_rates, boolean _do_up, boolean _do_down, int _run_states ) { do_rates = _do_rates; do_up = _do_up; do_down = _do_down; run_states = _run_states; if ( do_up ){ upload_rate_limit = (int)readLongAttribute( AT_RATELIMIT_UP, 0 ); } if ( do_down ){ download_rate_limit = (int)readLongAttribute( AT_RATELIMIT_DOWN, 0 ); } upload_priority = (int)readLongAttribute( AT_RATELIMIT_UP_PRI, 0 ); min_share_ratio = (int)readLongAttribute( AT_RATELIMIT_MIN_SR, 0 ); max_share_ratio = (int)readLongAttribute( AT_RATELIMIT_MAX_SR, 0 ); addTagListener( new TagListener() { public void taggableAdded( Tag tag, Taggable tagged ) { DownloadManager manager = (DownloadManager)tagged; manager.addRateLimiter( upload_limiter, true ); manager.addRateLimiter( download_limiter, false ); if ( upload_priority > 0 ){ manager.updateAutoUploadPriority( UPLOAD_PRIORITY_ADDED_KEY, true ); } if ( min_share_ratio > 0 ){ updateMinShareRatio( manager, min_share_ratio ); } if ( max_share_ratio > 0 ){ updateMaxShareRatio( manager, max_share_ratio ); } } public void taggableSync( Tag tag ) { } public void taggableRemoved( Tag tag, Taggable tagged ) { DownloadManager manager = (DownloadManager)tagged; manager.removeRateLimiter( upload_limiter, true ); manager.removeRateLimiter( download_limiter, false ); if ( upload_priority > 0 ){ manager.updateAutoUploadPriority( UPLOAD_PRIORITY_ADDED_KEY, false ); } if ( min_share_ratio > 0 ){ updateMinShareRatio( manager, 0 ); } if ( max_share_ratio > 0 ){ updateMaxShareRatio( manager, 0 ); } } private void updateMinShareRatio( DownloadManager manager, int sr ) { List<Tag> dm_tags = getTagType().getTagsForTaggable( manager ); for ( Tag t: dm_tags ){ if ( t == TagDownloadWithState.this ){ continue; } if ( t instanceof TagFeatureRateLimit ){ int o_sr = ((TagFeatureRateLimit)t).getTagMinShareRatio(); if ( o_sr > sr ){ sr = o_sr; } } } manager.getDownloadState().setIntParameter( DownloadManagerState.PARAM_MIN_SHARE_RATIO, sr ); } private void updateMaxShareRatio( DownloadManager manager, int sr ) { List<Tag> dm_tags = getTagType().getTagsForTaggable( manager ); for ( Tag t: dm_tags ){ if ( t == TagDownloadWithState.this ){ continue; } if ( t instanceof TagFeatureRateLimit ){ int o_sr = ((TagFeatureRateLimit)t).getTagMaxShareRatio(); if ( o_sr > sr ){ sr = o_sr; } } } manager.getDownloadState().setIntParameter( DownloadManagerState.PARAM_MAX_SHARE_RATIO, sr ); } }, true ); } @Override public void removeTag() { for ( DownloadManager dm: getTaggedDownloads()){ dm.removeRateLimiter( upload_limiter, true ); dm.removeRateLimiter( download_limiter, false ); if ( upload_priority > 0 ){ dm.updateAutoUploadPriority( UPLOAD_PRIORITY_ADDED_KEY, false ); } } super.removeTag(); } @Override public void addTaggable( Taggable t ) { if ( t instanceof DownloadManager ){ DownloadManager dm = (DownloadManager)t; if ( dm.isDestroyed()){ Debug.out( "Invalid Taggable added - download is destroyed: " + dm.getDisplayName()); }else{ super.addTaggable( t ); } }else{ Debug.out( "Invalid Taggable added: " + t ); } } public int getTaggableTypes() { return( Taggable.TT_DOWNLOAD ); } public Set<DownloadManager> getTaggedDownloads() { return((Set<DownloadManager>)(Object)getTagged()); } public boolean supportsTagRates() { return( do_rates ); } public boolean supportsTagUploadLimit() { return( do_up ); } public boolean supportsTagDownloadLimit() { return( do_down ); } public int getTagUploadLimit() { return( upload_rate_limit ); } public void setTagUploadLimit( int bps ) { if ( upload_rate_limit == bps ){ return; } if ( !do_up ){ Debug.out( "Not supported" ); return; } upload_rate_limit = bps; writeLongAttribute( AT_RATELIMIT_UP, upload_rate_limit ); } public int getTagCurrentUploadRate() { updateRates(); return( upload_rate ); } public int getTagDownloadLimit() { return( download_rate_limit ); } public void setTagDownloadLimit( int bps ) { if ( download_rate_limit == bps ){ return; } if ( !do_down ){ Debug.out( "Not supported" ); return; } download_rate_limit = bps; writeLongAttribute( AT_RATELIMIT_DOWN, download_rate_limit ); } public int getTagCurrentDownloadRate() { updateRates(); return( download_rate ); } public int getTagUploadPriority() { return( upload_priority ); } public void setTagUploadPriority( int priority ) { if ( priority < 0 ){ priority = 0; } if ( priority == upload_priority ){ return; } int old_up = upload_priority; upload_priority = priority; writeLongAttribute( AT_RATELIMIT_UP_PRI, priority ); if ( old_up == 0 || priority == 0 ){ Set<DownloadManager> dms = getTaggedDownloads(); for ( DownloadManager dm: dms ){ dm.updateAutoUploadPriority( UPLOAD_PRIORITY_ADDED_KEY, priority>0 ); } } } public int getTagMinShareRatio() { return( min_share_ratio ); } public void setTagMinShareRatio( int sr ) { if ( sr < 0 ){ sr = 0; } if ( sr == min_share_ratio ){ return; } min_share_ratio = sr; writeLongAttribute( AT_RATELIMIT_MIN_SR, sr ); Set<DownloadManager> dms = getTaggedDownloads(); for ( DownloadManager dm: dms ){ List<Tag> dm_tags = getTagType().getTagsForTaggable( dm ); for ( Tag t: dm_tags ){ if ( t == this ){ continue; } if ( t instanceof TagFeatureRateLimit ){ int o_sr = ((TagFeatureRateLimit)t).getTagMinShareRatio(); if ( o_sr > sr ){ sr = o_sr; } } } dm.getDownloadState().setIntParameter( DownloadManagerState.PARAM_MIN_SHARE_RATIO, sr ); } } public int getTagMaxShareRatio() { return( max_share_ratio ); } public void setTagMaxShareRatio( int sr ) { if ( sr < 0 ){ sr = 0; } if ( sr == max_share_ratio ){ return; } max_share_ratio = sr; writeLongAttribute( AT_RATELIMIT_MAX_SR, sr ); Set<DownloadManager> dms = getTaggedDownloads(); for ( DownloadManager dm: dms ){ List<Tag> dm_tags = getTagType().getTagsForTaggable( dm ); for ( Tag t: dm_tags ){ if ( t == this ){ continue; } if ( t instanceof TagFeatureRateLimit ){ int o_sr = ((TagFeatureRateLimit)t).getTagMaxShareRatio(); if ( o_sr > sr ){ sr = o_sr; } } } dm.getDownloadState().setIntParameter( DownloadManagerState.PARAM_MAX_SHARE_RATIO, sr ); } } private void updateRates() { long now = SystemTime.getCurrentTime(); if ( now - last_rate_update > 2500 ){ int new_up = 0; int new_down = 0; Set<DownloadManager> dms = getTaggedDownloads(); if ( dms.size() == 0 ){ new_up = -1; new_down = -1; }else{ new_up = 0; new_down = 0; for ( DownloadManager dm: dms ){ DownloadManagerStats stats = dm.getStats(); new_up += stats.getDataSendRate() + stats.getProtocolSendRate(); new_down += stats.getDataReceiveRate() + stats.getProtocolReceiveRate(); } } upload_rate = new_up; download_rate = new_down; last_rate_update = now; } } public int getRunStateCapabilities() { return( run_states ); } public boolean hasRunStateCapability( int capability ) { return((run_states & capability ) != 0 ); } public boolean[] getPerformableOperations( int[] ops ) { boolean[] result = new boolean[ ops.length]; Set<DownloadManager> dms = getTaggedDownloads(); for ( DownloadManager dm: dms ){ int dm_state = dm.getState(); for ( int i=0;i<ops.length;i++){ if ( result[i]){ continue; } int op = ops[i]; if (( op & TagFeatureRunState.RSC_START ) != 0 ){ if ( dm_state == DownloadManager.STATE_STOPPED || dm_state == DownloadManager.STATE_ERROR ){ result[i] = true; } } if (( op & TagFeatureRunState.RSC_STOP ) != 0 ){ if ( dm_state != DownloadManager.STATE_STOPPED && dm_state != DownloadManager.STATE_STOPPING && dm_state != DownloadManager.STATE_ERROR ){ result[i] = true; } } if (( op & TagFeatureRunState.RSC_PAUSE ) != 0 ){ if ( dm_state != DownloadManager.STATE_STOPPED && dm_state != DownloadManager.STATE_STOPPING && dm_state != DownloadManager.STATE_ERROR ){ if ( !dm.isPaused()){ result[i] = true; } } } if (( op & TagFeatureRunState.RSC_RESUME ) != 0 ){ if ( dm.isPaused()){ result[i] = true; } } } } return( result ); } public void performOperation( int op ) { Set<DownloadManager> dms = getTaggedDownloads(); for ( final DownloadManager dm: dms ){ int dm_state = dm.getState(); if ( op == TagFeatureRunState.RSC_START ){ if ( dm_state == DownloadManager.STATE_STOPPED || dm_state == DownloadManager.STATE_ERROR ){ rs_async.dispatch( new AERunnable() { public void runSupport() { dm.setStateQueued(); } }); } }else if ( op == TagFeatureRunState.RSC_STOP ){ if ( dm_state != DownloadManager.STATE_STOPPED && dm_state != DownloadManager.STATE_STOPPING && dm_state != DownloadManager.STATE_ERROR ){ rs_async.dispatch( new AERunnable() { public void runSupport() { dm.stopIt( DownloadManager.STATE_STOPPED, false, false ); } }); } }else if ( op == TagFeatureRunState.RSC_PAUSE ){ if ( dm_state != DownloadManager.STATE_STOPPED && dm_state != DownloadManager.STATE_STOPPING && dm_state != DownloadManager.STATE_ERROR ){ rs_async.dispatch( new AERunnable() { public void runSupport() { dm.pause(); } }); } }else if ( op == TagFeatureRunState.RSC_RESUME ){ if ( dm.isPaused()){ rs_async.dispatch( new AERunnable() { public void runSupport() { dm.resume(); } }); } } } } protected void setSupportsTagTranscode( boolean sup ) { supports_xcode = sup; } public boolean supportsTagTranscode() { return( supports_xcode ); } public String[] getTagTranscodeTarget() { String temp = readStringAttribute( AT_XCODE_TARGET, null ); if ( temp == null ){ return( null ); } String[] bits = temp.split( "\n" ); if ( bits.length != 2 ){ return( null ); } return( bits ); } public void setTagTranscodeTarget( String uid, String name ) { writeStringAttribute( AT_XCODE_TARGET, uid==null?null:(uid + "\n" + name )); getTagType().fireChanged( this ); getManager().featureChanged( this, TagFeature.TF_XCODE ); } protected void setSupportsFileLocation( boolean sup ) { supports_file_location = sup; } @Override public boolean supportsTagInitialSaveFolder() { return( supports_file_location ); } @Override public boolean supportsTagMoveOnComplete() { return( supports_file_location ); } @Override public boolean supportsTagCopyOnComplete() { return( supports_file_location ); } @Override public TagProperty[] getSupportedProperties() { return( getTagType().isTagTypeAuto()?new TagProperty[0]:tag_properties ); } @Override public boolean isTagAuto() { TagProperty[] props = getSupportedProperties(); for ( TagProperty prop: props ){ String name = prop.getName( false ); if ( name.equals( TagFeatureProperties.PR_TRACKER_TEMPLATES )){ continue; } int type = prop.getType(); if ( type == TagFeatureProperties.PT_BOOLEAN ){ Boolean b = prop.getBoolean(); if ( b != null && b ){ return( true ); } }else if ( type == TagFeatureProperties.PT_STRING_LIST ){ String[] val = prop.getStringList(); if ( val != null && val.length > 0 ){ return( true ); } } } return( false ); } }