(trunk) #1787: add support for seeding ratio limiting in libtransmission
This commit is contained in:
parent
a079c843dc
commit
3f9a1d090b
|
@ -85,6 +85,11 @@ static tr_option opts[] =
|
|||
{ 930, "peers", "Set the current torrent(s)' maximum number of peers each", "pr", 1, "<max>" },
|
||||
{ 931, "global-peers", "Set the global maximum number of peers", "gpr", 1, "<max>" },
|
||||
{ 'R', "remove-and-delete", "Remove the current torrent(s) and delete local data", NULL, 0, NULL },
|
||||
{ 950, "seedratio", "Let the current torrent(s) seed until a specific ratio", "sr", 1, "ratio" },
|
||||
{ 951, "seedratio-default", "Let the current torrent(s) use the global seedratio settings", "srd", 0, NULL },
|
||||
{ 952, "no-seedratio", "Let the current torrent(s) seed regardless of ratio", "SR", 0, NULL },
|
||||
{ 953, "global-seedratio", "All torrents, unless overridden by a per-torrent setting, should seed until a specific ratio", "gsr", 1, "ratio" },
|
||||
{ 954, "no-global-seedratio", "All torrents, unless overridden by a per-torrent setting, should seed regardless of ratio", "GSR", 0, NULL },
|
||||
{ 's', "start", "Start the current torrent(s)", "s", 0, NULL },
|
||||
{ 'S', "stop", "Stop the current torrent(s)", "S", 0, NULL },
|
||||
{ 't', "torrent", "Set the current torrent(s)", "t", 1, "<torrent>" },
|
||||
|
@ -533,6 +538,36 @@ readargs( int argc,
|
|||
tr_bencListAddStr( fields, "peers" );
|
||||
break;
|
||||
|
||||
case 950:
|
||||
tr_bencDictAddStr( &top, "method", "torrent-set" );
|
||||
tr_bencDictAddDouble( args, "ratio-limit", atof(optarg) );
|
||||
tr_bencDictAddInt( args, "ratio-limit-mode", TR_RATIOLIMIT_SINGLE );
|
||||
addIdArg( args, id );
|
||||
break;
|
||||
|
||||
case 951:
|
||||
tr_bencDictAddStr( &top, "method", "torrent-set" );
|
||||
tr_bencDictAddInt( args, "ratio-limit-mode", TR_RATIOLIMIT_GLOBAL );
|
||||
addIdArg( args, id );
|
||||
break;
|
||||
|
||||
case 952:
|
||||
tr_bencDictAddStr( &top, "method", "torrent-set" );
|
||||
tr_bencDictAddInt( args, "ratio-limit-mode", TR_RATIOLIMIT_UNLIMITED );
|
||||
addIdArg( args, id );
|
||||
break;
|
||||
|
||||
case 953:
|
||||
tr_bencDictAddStr( &top, "method", "session-set" );
|
||||
tr_bencDictAddDouble( args, "ratio-limit", atof(optarg) );
|
||||
tr_bencDictAddInt( args, "ratio-limit-enabled", 1 );
|
||||
break;
|
||||
|
||||
case 954:
|
||||
tr_bencDictAddStr( &top, "method", "session-set" );
|
||||
tr_bencDictAddInt( args, "ratio-limit-enabled", 0 );
|
||||
break;
|
||||
|
||||
case TR_OPT_ERR:
|
||||
fprintf( stderr, "invalid option\n" );
|
||||
showUsage( );
|
||||
|
|
|
@ -19,6 +19,8 @@ and
|
|||
.Op Fl g Ar files
|
||||
.Op Fl gpr Ar peers
|
||||
.Op Fl G Ar files
|
||||
.Op Fl gsr Ar ratio
|
||||
.Op Fl GSR
|
||||
.Op Fl h
|
||||
.Op Fl i
|
||||
.Op Fl l
|
||||
|
@ -33,6 +35,9 @@ and
|
|||
.Op Fl r
|
||||
.Op Fl R
|
||||
.Op Fl s | S
|
||||
.Op Fl sr Ar ratio
|
||||
.Op Fl SR
|
||||
.Op Fl srd
|
||||
.Op Fl si
|
||||
.Op Fl t Ar all | Ar id | Ar hash
|
||||
.Op Fl u Ar number | Fl U
|
||||
|
@ -93,6 +98,13 @@ such as "-g1,3-5" to add files #1, #3, #4, and #5 to the download list.
|
|||
.It Fl G Fl -no-get Ar all | file-index | files
|
||||
Mark file(s) for not downloading.
|
||||
|
||||
.It Fl gsr Fl -global-seedratio Ar ratio
|
||||
All torrents, unless overridden by a per-torrent setting, should seed until a specific
|
||||
.Ar ratio
|
||||
|
||||
.It Fl GSR Fl -no-global-seedratio
|
||||
All torrents, unless overridden by a per-torrent setting, should seed regardless of ratio
|
||||
|
||||
.It Fl h Fl -help
|
||||
Print command-line option descriptions.
|
||||
|
||||
|
@ -155,6 +167,16 @@ Remove the current torrent(s). This does not delete the downloaded data.
|
|||
.It Fl -remove-and-delete
|
||||
Remove the current torrent(s) and delete their downloaded data.
|
||||
|
||||
.It Fl sr Fl -seedratio Ar ratio
|
||||
Let the current torrent(s) seed until a specific
|
||||
.Ar ratio
|
||||
|
||||
.It Fl SR Fl -no-seedratio
|
||||
Let the current torrent(s) seed regardless of ratio
|
||||
|
||||
.It Fl srd Fl -seedratio-default
|
||||
Let the current torrent(s) use the global seedratio settings
|
||||
|
||||
.It Fl s Fl -start
|
||||
Start the current torrent(s)
|
||||
|
||||
|
|
24
gtk/conf.c
24
gtk/conf.c
|
@ -200,6 +200,30 @@ pref_int_set_default( const char * key,
|
|||
pref_int_set( key, value );
|
||||
}
|
||||
|
||||
double
|
||||
pref_double_get( const char * key )
|
||||
{
|
||||
double d = 0.0;
|
||||
|
||||
tr_bencDictFindDouble( getPrefs( ), key, &d );
|
||||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
pref_double_set( const char * key,
|
||||
double value )
|
||||
{
|
||||
tr_bencDictAddDouble( getPrefs( ), key, value );
|
||||
}
|
||||
|
||||
void
|
||||
pref_double_set_default( const char * key,
|
||||
double value )
|
||||
{
|
||||
if ( !tr_bencDictFind( getPrefs( ), key ) )
|
||||
pref_double_set( key, value );
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
|
|
@ -32,6 +32,10 @@ int64_t pref_int_get ( const char * key );
|
|||
void pref_int_set ( const char * key, int64_t value );
|
||||
void pref_int_set_default ( const char * key, int64_t value );
|
||||
|
||||
double pref_double_get ( const char * key );
|
||||
void pref_double_set ( const char * key, double value );
|
||||
void pref_double_set_default( const char * key, double value );
|
||||
|
||||
gboolean pref_flag_get ( const char * key );
|
||||
void pref_flag_set ( const char * key, gboolean value );
|
||||
void pref_flag_set_default ( const char * key, gboolean value );
|
||||
|
|
126
gtk/details.c
126
gtk/details.c
|
@ -30,6 +30,13 @@
|
|||
#include "util.h"
|
||||
|
||||
#define UPDATE_INTERVAL_SECONDS 2
|
||||
typedef struct
|
||||
{
|
||||
gpointer gtor;
|
||||
TrCore * core;
|
||||
guint handler;
|
||||
} ResponseData;
|
||||
|
||||
|
||||
/****
|
||||
***** PIECES VIEW
|
||||
|
@ -1170,6 +1177,19 @@ dl_speed_toggled_cb( GtkToggleButton *tb,
|
|||
speed_toggled_cb( tb, gtor, TR_DOWN );
|
||||
}
|
||||
|
||||
#define RATIO_MODE_KEY "ratio-mode"
|
||||
|
||||
static void
|
||||
ratio_mode_changed_cb( GtkToggleButton * tb, gpointer gtor )
|
||||
{
|
||||
if( gtk_toggle_button_get_active( tb ) )
|
||||
{
|
||||
tr_torrent * tor = tr_torrent_handle( gtor );
|
||||
const int mode = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( tb ), RATIO_MODE_KEY ) );
|
||||
tr_torrentSetRatioMode( tor, mode );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sensitize_from_check_cb( GtkToggleButton *toggle,
|
||||
gpointer w )
|
||||
|
@ -1203,6 +1223,16 @@ dl_speed_spun_cb( GtkSpinButton *spin,
|
|||
setSpeedLimit( spin, gtor, TR_DOWN );
|
||||
}
|
||||
|
||||
static void
|
||||
ratio_spun_cb( GtkSpinButton *spin,
|
||||
gpointer gtor )
|
||||
{
|
||||
tr_torrent * tor = tr_torrent_handle ( gtor );
|
||||
float ratio = gtk_spin_button_get_value ( spin );
|
||||
|
||||
tr_torrentSetRatioLimit( tor, ratio );
|
||||
}
|
||||
|
||||
static void
|
||||
max_peers_spun_cb( GtkSpinButton * spin,
|
||||
gpointer gtor )
|
||||
|
@ -1212,13 +1242,45 @@ max_peers_spun_cb( GtkSpinButton * spin,
|
|||
tr_torrentSetPeerLimit( tr_torrent_handle( gtor ), n );
|
||||
}
|
||||
|
||||
static char*
|
||||
get_global_ratio_radiobutton_string( void )
|
||||
{
|
||||
char * s;
|
||||
const gboolean b = pref_flag_get( TR_PREFS_KEY_RATIO_ENABLED );
|
||||
const double d = pref_double_get( TR_PREFS_KEY_RATIO );
|
||||
|
||||
if( b )
|
||||
s = g_strdup_printf( _( "Use _Global setting (currently: stop seeding when a torrent's ratio reaches %.2f)" ), d );
|
||||
else
|
||||
s = g_strdup( _( "Use _Global setting (currently: seed regardless of ratio)" ) );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
prefsChanged( TrCore * core UNUSED, const char * key, gpointer rb )
|
||||
{
|
||||
if( !strcmp( key, TR_PREFS_KEY_RATIO_ENABLED ) || !strcmp( key, TR_PREFS_KEY_RATIO ) )
|
||||
{
|
||||
char * s = get_global_ratio_radiobutton_string( );
|
||||
gtk_button_set_label( GTK_BUTTON( rb ), s );
|
||||
g_free( s );
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget*
|
||||
options_page_new( TrTorrent * gtor )
|
||||
options_page_new( ResponseData * data )
|
||||
{
|
||||
uint16_t maxConnectedPeers;
|
||||
int i, row;
|
||||
double d;
|
||||
gboolean b;
|
||||
GtkWidget * t, *w, *tb;
|
||||
char * s;
|
||||
GSList * group;
|
||||
GtkWidget * t, *w, *tb, *h;
|
||||
tr_ratiolimit mode;
|
||||
TrCore * core = data->core;
|
||||
TrTorrent * gtor = data->gtor;
|
||||
tr_torrent * tor = tr_torrent_handle ( gtor );
|
||||
|
||||
row = 0;
|
||||
|
@ -1263,6 +1325,44 @@ options_page_new( TrTorrent * gtor )
|
|||
sensitize_from_check_cb ( GTK_TOGGLE_BUTTON( tb ), w );
|
||||
hig_workarea_add_row_w ( t, &row, tb, w, NULL );
|
||||
|
||||
hig_workarea_add_section_divider ( t, &row );
|
||||
hig_workarea_add_section_title ( t, &row, _( "Seed-Until Ratio" ) );
|
||||
|
||||
|
||||
group = NULL;
|
||||
mode = tr_torrentGetRatioMode( tor );
|
||||
s = get_global_ratio_radiobutton_string( );
|
||||
w = gtk_radio_button_new_with_mnemonic( group, s );
|
||||
data->handler = g_signal_connect( core, "prefs-changed", G_CALLBACK( prefsChanged ), w );
|
||||
group = gtk_radio_button_get_group( GTK_RADIO_BUTTON( w ) );
|
||||
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON( w ), mode == TR_RATIOLIMIT_GLOBAL);
|
||||
hig_workarea_add_wide_control( t, &row, w );
|
||||
g_free( s );
|
||||
g_object_set_data( G_OBJECT( w ), RATIO_MODE_KEY, GINT_TO_POINTER( TR_RATIOLIMIT_GLOBAL ) );
|
||||
g_signal_connect( w, "toggled", G_CALLBACK( ratio_mode_changed_cb ), gtor );
|
||||
|
||||
w = gtk_radio_button_new_with_mnemonic( group, _( "Seed _regardless of ratio" ) );
|
||||
group = gtk_radio_button_get_group( GTK_RADIO_BUTTON( w ) );
|
||||
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON( w ), mode == TR_RATIOLIMIT_UNLIMITED);
|
||||
hig_workarea_add_wide_control( t, &row, w );
|
||||
g_object_set_data( G_OBJECT( w ), RATIO_MODE_KEY, GINT_TO_POINTER( TR_RATIOLIMIT_UNLIMITED ) );
|
||||
g_signal_connect( w, "toggled", G_CALLBACK( ratio_mode_changed_cb ), gtor );
|
||||
|
||||
h = gtk_hbox_new ( FALSE, GUI_PAD );
|
||||
w = gtk_radio_button_new_with_mnemonic( group, _( "_Stop seeding when a torrent's ratio reaches" ) );
|
||||
g_object_set_data( G_OBJECT( w ), RATIO_MODE_KEY, GINT_TO_POINTER( TR_RATIOLIMIT_SINGLE ) );
|
||||
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON( w ), mode == TR_RATIOLIMIT_SINGLE);
|
||||
g_signal_connect( w, "toggled", G_CALLBACK( ratio_mode_changed_cb ), gtor );
|
||||
group = gtk_radio_button_get_group( GTK_RADIO_BUTTON( w ) );
|
||||
gtk_box_pack_start ( GTK_BOX( h ), w, FALSE, FALSE, 0 );
|
||||
d = tr_torrentGetRatioLimit( tor );
|
||||
w = gtk_spin_button_new_with_range( 0.5, INT_MAX, .05 );
|
||||
gtk_spin_button_set_digits( GTK_SPIN_BUTTON( w ), 2 );
|
||||
gtk_spin_button_set_value( GTK_SPIN_BUTTON( w ), d );
|
||||
g_signal_connect ( w, "value-changed", G_CALLBACK( ratio_spun_cb ), gtor );
|
||||
gtk_box_pack_start ( GTK_BOX( h ), w, FALSE, FALSE, 0 );
|
||||
hig_workarea_add_wide_control( t, &row, h );
|
||||
|
||||
hig_workarea_add_section_divider ( t, &row );
|
||||
hig_workarea_add_section_title ( t, &row, _( "Peer Connections" ) );
|
||||
|
||||
|
@ -1458,10 +1558,17 @@ remove_tag( gpointer tag )
|
|||
static void
|
||||
response_cb( GtkDialog * dialog,
|
||||
int response UNUSED,
|
||||
gpointer gtor )
|
||||
gpointer data )
|
||||
{
|
||||
g_object_weak_unref ( G_OBJECT( gtor ), torrent_destroyed, dialog );
|
||||
ResponseData *rd = data;
|
||||
TrCore * core = rd->core;
|
||||
gulong handler = rd-> handler;
|
||||
|
||||
g_signal_handler_disconnect( core, handler );
|
||||
g_object_weak_unref ( G_OBJECT( rd->gtor ), torrent_destroyed, dialog );
|
||||
gtk_widget_destroy ( GTK_WIDGET( dialog ) );
|
||||
|
||||
g_free ( rd );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -1477,6 +1584,7 @@ periodic_refresh( gpointer data )
|
|||
|
||||
GtkWidget*
|
||||
torrent_inspector_new( GtkWindow * parent,
|
||||
TrCore * core,
|
||||
TrTorrent * gtor )
|
||||
{
|
||||
guint tag;
|
||||
|
@ -1484,14 +1592,18 @@ torrent_inspector_new( GtkWindow * parent,
|
|||
tr_torrent * tor = tr_torrent_handle ( gtor );
|
||||
char title[512];
|
||||
const tr_info * info = tr_torrent_info ( gtor );
|
||||
ResponseData * rd;
|
||||
|
||||
/* create the dialog */
|
||||
rd = g_new0(ResponseData, 1);
|
||||
rd->gtor = gtor;
|
||||
rd->core = core;
|
||||
g_snprintf( title, sizeof( title ), _( "%s Properties" ), info->name );
|
||||
d = gtk_dialog_new_with_buttons ( title, parent, 0,
|
||||
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
|
||||
NULL );
|
||||
gtk_window_set_role ( GTK_WINDOW( d ), "tr-info" );
|
||||
g_signal_connect ( d, "response", G_CALLBACK ( response_cb ), gtor );
|
||||
g_signal_connect ( d, "response", G_CALLBACK ( response_cb ), rd );
|
||||
gtk_dialog_set_has_separator( GTK_DIALOG( d ), FALSE );
|
||||
gtk_container_set_border_width( GTK_CONTAINER( d ), GUI_PAD );
|
||||
g_object_weak_ref ( G_OBJECT( gtor ), torrent_destroyed, d );
|
||||
|
@ -1526,10 +1638,10 @@ torrent_inspector_new( GtkWindow * parent,
|
|||
gtk_notebook_append_page ( GTK_NOTEBOOK( n ), w,
|
||||
gtk_label_new ( _( "Files" ) ) );
|
||||
|
||||
w = options_page_new ( gtor );
|
||||
w = options_page_new ( rd );
|
||||
g_object_set_data ( G_OBJECT( d ), "options-top", w );
|
||||
gtk_notebook_append_page ( GTK_NOTEBOOK( n ), w,
|
||||
gtk_label_new ( _( "Options" ) ) );
|
||||
gtk_label_new ( _( "Options" ) ) );
|
||||
|
||||
gtk_box_pack_start( GTK_BOX( GTK_DIALOG( d )->vbox ), n, TRUE, TRUE, 0 );
|
||||
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
#define GTK_TORRENT_INSPECTOR_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "tr-core.h"
|
||||
#include "tr-torrent.h"
|
||||
|
||||
GtkWidget* torrent_inspector_new( GtkWindow * parent,
|
||||
TrCore * core,
|
||||
TrTorrent * tor );
|
||||
|
||||
#endif /* TG_PREFS_H */
|
||||
|
|
12
gtk/main.c
12
gtk/main.c
|
@ -1082,6 +1082,16 @@ prefschanged( TrCore * core UNUSED,
|
|||
const int limit = pref_int_get( key );
|
||||
tr_sessionSetSpeedLimit( tr, TR_UP, limit );
|
||||
}
|
||||
else if( !strcmp( key, TR_PREFS_KEY_RATIO_ENABLED ) )
|
||||
{
|
||||
const gboolean b = pref_flag_get( key );
|
||||
tr_sessionSetRatioLimited( tr, b );
|
||||
}
|
||||
else if( !strcmp( key, TR_PREFS_KEY_RATIO ) )
|
||||
{
|
||||
const double limit = pref_double_get( key );
|
||||
tr_sessionSetRatioLimit( tr, limit );
|
||||
}
|
||||
else if( !strncmp( key, "sched-", 6 ) )
|
||||
{
|
||||
updateScheduledLimits( tr );
|
||||
|
@ -1316,7 +1326,7 @@ showInfoForeach( GtkTreeModel * model,
|
|||
gtk_window_present( GTK_WINDOW( w ) );
|
||||
else
|
||||
{
|
||||
w = torrent_inspector_new( GTK_WINDOW( data->wind ), tor );
|
||||
w = torrent_inspector_new( GTK_WINDOW( data->wind ), data->core, tor );
|
||||
gtk_widget_show( w );
|
||||
g_hash_table_insert( data->tor2details, (gpointer)hashString, w );
|
||||
g_hash_table_insert( data->details2tor, w, (gpointer)hashString );
|
||||
|
|
|
@ -1270,3 +1270,17 @@ tr_core_set_pref_int( TrCore * self,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_core_set_pref_double( TrCore * self,
|
||||
const char * key,
|
||||
double newval )
|
||||
{
|
||||
const double oldval = pref_double_get( key );
|
||||
|
||||
if( oldval != newval )
|
||||
{
|
||||
pref_double_set( key, newval );
|
||||
commitPrefsChange( self, key );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -204,6 +204,11 @@ void tr_core_set_pref_int( TrCore * self,
|
|||
const char * key,
|
||||
int val );
|
||||
|
||||
/* Set a double preference value, save the prefs file, and emit the
|
||||
"prefs-changed" signal */
|
||||
void tr_core_set_pref_double( TrCore * self,
|
||||
const char * key,
|
||||
double val );
|
||||
|
||||
/**
|
||||
***
|
||||
|
|
|
@ -145,6 +145,7 @@ struct spin_idle_data
|
|||
{
|
||||
gpointer core;
|
||||
GTimer * last_change;
|
||||
gboolean isDouble;
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -168,9 +169,17 @@ spun_cb_idle( gpointer spin )
|
|||
{
|
||||
/* update the core */
|
||||
const char * key = g_object_get_data( o, PREF_KEY );
|
||||
const int value = gtk_spin_button_get_value_as_int(
|
||||
GTK_SPIN_BUTTON( spin ) );
|
||||
tr_core_set_pref_int( TR_CORE( data->core ), key, value );
|
||||
if (data->isDouble)
|
||||
{
|
||||
const double value = gtk_spin_button_get_value( GTK_SPIN_BUTTON( spin ) );
|
||||
tr_core_set_pref_double( TR_CORE( data->core ), key, value );
|
||||
}
|
||||
else
|
||||
{
|
||||
const int value = gtk_spin_button_get_value_as_int(
|
||||
GTK_SPIN_BUTTON( spin ) );
|
||||
tr_core_set_pref_int( TR_CORE( data->core ), key, value );
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
g_object_set_data( o, IDLE_DATA, NULL );
|
||||
|
@ -183,7 +192,8 @@ spun_cb_idle( gpointer spin )
|
|||
|
||||
static void
|
||||
spun_cb( GtkSpinButton * w,
|
||||
gpointer core )
|
||||
gpointer core,
|
||||
gboolean isDouble )
|
||||
{
|
||||
/* user may be spinning through many values, so let's hold off
|
||||
for a moment to keep from flooding the core with changes */
|
||||
|
@ -195,6 +205,7 @@ spun_cb( GtkSpinButton * w,
|
|||
data = g_new( struct spin_idle_data, 1 );
|
||||
data->core = core;
|
||||
data->last_change = g_timer_new( );
|
||||
data->isDouble = isDouble;
|
||||
g_object_set_data_full( o, IDLE_DATA, data, spin_idle_data_free );
|
||||
g_object_ref( G_OBJECT( o ) );
|
||||
g_timeout_add( 100, spun_cb_idle, w );
|
||||
|
@ -202,6 +213,20 @@ spun_cb( GtkSpinButton * w,
|
|||
g_timer_start( data->last_change );
|
||||
}
|
||||
|
||||
static void
|
||||
spun_cb_int( GtkSpinButton * w,
|
||||
gpointer core )
|
||||
{
|
||||
spun_cb( w, core, FALSE );
|
||||
}
|
||||
|
||||
static void
|
||||
spun_cb_double( GtkSpinButton * w,
|
||||
gpointer core )
|
||||
{
|
||||
spun_cb( w, core, TRUE );
|
||||
}
|
||||
|
||||
static GtkWidget*
|
||||
new_spin_button( const char * key,
|
||||
gpointer core,
|
||||
|
@ -215,7 +240,24 @@ new_spin_button( const char * key,
|
|||
key ), g_free );
|
||||
gtk_spin_button_set_digits( GTK_SPIN_BUTTON( w ), 0 );
|
||||
gtk_spin_button_set_value( GTK_SPIN_BUTTON( w ), pref_int_get( key ) );
|
||||
g_signal_connect( w, "value-changed", G_CALLBACK( spun_cb ), core );
|
||||
g_signal_connect( w, "value-changed", G_CALLBACK( spun_cb_int ), core );
|
||||
return w;
|
||||
}
|
||||
|
||||
static GtkWidget*
|
||||
new_spin_button_double( const char * key,
|
||||
gpointer core,
|
||||
double low,
|
||||
double high,
|
||||
double step )
|
||||
{
|
||||
GtkWidget * w = gtk_spin_button_new_with_range( low, high, step );
|
||||
|
||||
g_object_set_data_full( G_OBJECT( w ), PREF_KEY, g_strdup(
|
||||
key ), g_free );
|
||||
gtk_spin_button_set_digits( GTK_SPIN_BUTTON( w ), 2 );
|
||||
gtk_spin_button_set_value( GTK_SPIN_BUTTON( w ), pref_double_get( key ) );
|
||||
g_signal_connect( w, "value-changed", G_CALLBACK( spun_cb_double ), core );
|
||||
return w;
|
||||
}
|
||||
|
||||
|
@ -1120,6 +1162,13 @@ bandwidthPage( GObject * core )
|
|||
g_signal_connect( w, "toggled", G_CALLBACK( target_cb ), w2 );
|
||||
hig_workarea_add_row_w( t, &row, w, w2, NULL );
|
||||
|
||||
s = _( "_Stop seeding when a torrent's ratio reaches:" );
|
||||
w = new_check_button( s, TR_PREFS_KEY_RATIO_ENABLED, core );
|
||||
w2 = new_spin_button_double( TR_PREFS_KEY_RATIO, core, .5, INT_MAX, .05 );
|
||||
gtk_widget_set_sensitive( GTK_WIDGET( w2 ), pref_flag_get( TR_PREFS_KEY_RATIO_ENABLED ) );
|
||||
g_signal_connect( w, "toggled", G_CALLBACK( target_cb ), w2 );
|
||||
hig_workarea_add_row_w( t, &row, w, w2, NULL );
|
||||
|
||||
hig_workarea_add_section_divider( t, &row );
|
||||
hig_workarea_add_section_title( t, &row, _( "Scheduled Limits" ) );
|
||||
|
||||
|
|
|
@ -86,8 +86,8 @@ struct tr_datatype
|
|||
static void
|
||||
didWriteWrapper( tr_peerIo * io, size_t bytes_transferred )
|
||||
{
|
||||
while( bytes_transferred )
|
||||
{
|
||||
while( bytes_transferred && tr_isPeerIo( io ) )
|
||||
{
|
||||
struct tr_datatype * next = __tr_list_entry( io->outbuf_datatypes.next, struct tr_datatype, head );
|
||||
const size_t payload = MIN( next->length, bytes_transferred );
|
||||
const size_t overhead = getPacketOverhead( payload );
|
||||
|
@ -99,13 +99,16 @@ didWriteWrapper( tr_peerIo * io, size_t bytes_transferred )
|
|||
|
||||
if( io->didWrite )
|
||||
io->didWrite( io, payload, next->isPieceData, io->userData );
|
||||
|
||||
bytes_transferred -= payload;
|
||||
next->length -= payload;
|
||||
if( !next->length ) {
|
||||
__tr_list_remove( io->outbuf_datatypes.next );
|
||||
tr_free( next );
|
||||
}
|
||||
|
||||
if( tr_isPeerIo( io ) )
|
||||
{
|
||||
bytes_transferred -= payload;
|
||||
next->length -= payload;
|
||||
if( !next->length ) {
|
||||
__tr_list_remove( io->outbuf_datatypes.next );
|
||||
tr_free( next );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -932,6 +932,15 @@ peerSuggestedPiece( Torrent * t UNUSED,
|
|||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
fireRatioLimitHit( tr_torrent * tor )
|
||||
{
|
||||
assert( tr_isTorrent( tor ) );
|
||||
|
||||
if( tor->ratio_limit_hit_func )
|
||||
tor->ratio_limit_hit_func( tor, tor->ratio_limit_hit_func_user_data );
|
||||
}
|
||||
|
||||
static void
|
||||
peerCallbackFunc( void * vpeer, void * vevent, void * vt )
|
||||
{
|
||||
|
@ -963,6 +972,7 @@ peerCallbackFunc( void * vpeer, void * vevent, void * vt )
|
|||
{
|
||||
const time_t now = time( NULL );
|
||||
tr_torrent * tor = t->tor;
|
||||
double seedRatio;
|
||||
|
||||
tor->activityDate = now;
|
||||
|
||||
|
@ -980,6 +990,17 @@ peerCallbackFunc( void * vpeer, void * vevent, void * vt )
|
|||
a->piece_data_time = now;
|
||||
}
|
||||
|
||||
/* if we're seeding and we've reached our seed ratio limit, stop the torrent */
|
||||
if( tr_torrentIsSeed( tor ) && tr_torrentGetSeedRatio( tor, &seedRatio ) ) {
|
||||
double up = (double)tor->uploadedCur + (double)tor->uploadedPrev;
|
||||
double down = (double)tor->downloadedCur + (double)tor->downloadedPrev;
|
||||
double ratio = tr_getRatio( up, down );
|
||||
if( ratio >= seedRatio ) {
|
||||
tr_torrentStop( tor );
|
||||
fireRatioLimitHit( tor );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1596,7 +1596,9 @@ didWrite( tr_peerIo * io UNUSED, size_t bytesWritten, int wasPieceData, void * v
|
|||
{
|
||||
tr_peermsgs * msgs = vmsgs;
|
||||
firePeerGotData( msgs, bytesWritten, wasPieceData );
|
||||
peerPulse( msgs );
|
||||
|
||||
if ( tr_isPeerIo( io ) && io->userData )
|
||||
peerPulse( msgs );
|
||||
}
|
||||
|
||||
static ReadState
|
||||
|
|
|
@ -39,12 +39,15 @@
|
|||
#define KEY_PRIORITY "priority"
|
||||
#define KEY_PROGRESS "progress"
|
||||
#define KEY_SPEEDLIMIT "speed-limit"
|
||||
#define KEY_RATIOLIMIT "ratio-limit"
|
||||
#define KEY_UPLOADED "uploaded"
|
||||
|
||||
#define KEY_SPEEDLIMIT_DOWN_SPEED "down-speed"
|
||||
#define KEY_SPEEDLIMIT_DOWN_MODE "down-mode"
|
||||
#define KEY_SPEEDLIMIT_UP_SPEED "up-speed"
|
||||
#define KEY_SPEEDLIMIT_UP_MODE "up-mode"
|
||||
#define KEY_RATIOLIMIT_RATIO "ratio-limit"
|
||||
#define KEY_RATIOLIMIT_MODE "ratio-mode"
|
||||
|
||||
#define KEY_PROGRESS_MTIMES "mtimes"
|
||||
#define KEY_PROGRESS_BITFIELD "bitfield"
|
||||
|
@ -255,6 +258,18 @@ saveSpeedLimits( tr_benc * dict,
|
|||
tr_torrentGetSpeedMode( tor, TR_UP ) );
|
||||
}
|
||||
|
||||
static void
|
||||
saveRatioLimits( tr_benc * dict,
|
||||
const tr_torrent * tor )
|
||||
{
|
||||
tr_benc * d = tr_bencDictAddDict( dict, KEY_RATIOLIMIT, 4 );
|
||||
|
||||
tr_bencDictAddDouble( d, KEY_RATIOLIMIT_RATIO,
|
||||
tr_torrentGetRatioLimit( tor ) );
|
||||
tr_bencDictAddInt( d, KEY_RATIOLIMIT_MODE,
|
||||
tr_torrentGetRatioMode( tor ) );
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
loadSpeedLimits( tr_benc * dict,
|
||||
tr_torrent * tor )
|
||||
|
@ -279,6 +294,26 @@ loadSpeedLimits( tr_benc * dict,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
loadRatioLimits( tr_benc * dict,
|
||||
tr_torrent * tor )
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
tr_benc * d;
|
||||
|
||||
if( tr_bencDictFindDict( dict, KEY_RATIOLIMIT, &d ) )
|
||||
{
|
||||
int64_t i;
|
||||
double dratio;
|
||||
if( tr_bencDictFindDouble( d, KEY_RATIOLIMIT_RATIO, &dratio ) )
|
||||
tr_torrentSetRatioLimit( tor, dratio );
|
||||
if( tr_bencDictFindInt( d, KEY_RATIOLIMIT_MODE, &i ) )
|
||||
tr_torrentSetRatioMode( tor, i );
|
||||
ret = TR_FR_RATIOLIMIT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -435,6 +470,7 @@ tr_torrentSaveResume( const tr_torrent * tor )
|
|||
saveDND( &top, tor );
|
||||
saveProgress( &top, tor );
|
||||
saveSpeedLimits( &top, tor );
|
||||
saveRatioLimits( &top, tor );
|
||||
|
||||
filename = getResumeFilename( tor );
|
||||
tr_bencSaveFile( filename, &top );
|
||||
|
@ -553,6 +589,9 @@ loadFromFile( tr_torrent * tor,
|
|||
|
||||
if( fieldsToLoad & TR_FR_SPEEDLIMIT )
|
||||
fieldsLoaded |= loadSpeedLimits( &top, tor );
|
||||
|
||||
if( fieldsToLoad & TR_FR_RATIOLIMIT )
|
||||
fieldsLoaded |= loadRatioLimits( &top, tor );
|
||||
|
||||
tr_bencFree( &top );
|
||||
tr_free( filename );
|
||||
|
|
|
@ -32,7 +32,8 @@ enum
|
|||
TR_FR_MAX_PEERS = ( 1 << 10 ),
|
||||
TR_FR_ADDED_DATE = ( 1 << 11 ),
|
||||
TR_FR_DONE_DATE = ( 1 << 12 ),
|
||||
TR_FR_ACTIVITY_DATE = ( 1 << 13 )
|
||||
TR_FR_ACTIVITY_DATE = ( 1 << 13 ),
|
||||
TR_FR_RATIOLIMIT = ( 1 << 14 )
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -603,6 +603,7 @@ torrentSet( tr_session * session,
|
|||
for( i = 0; i < torrentCount; ++i )
|
||||
{
|
||||
int64_t tmp;
|
||||
double d;
|
||||
tr_benc * files;
|
||||
tr_torrent * tor = torrents[i];
|
||||
|
||||
|
@ -629,7 +630,10 @@ torrentSet( tr_session * session,
|
|||
if( tr_bencDictFindInt( args_in, "speed-limit-up-enabled", &tmp ) )
|
||||
tr_torrentSetSpeedMode( tor, TR_UP, tmp ? TR_SPEEDLIMIT_SINGLE
|
||||
: TR_SPEEDLIMIT_GLOBAL );
|
||||
|
||||
if( tr_bencDictFindDouble( args_in, "ratio-limit", &d ) )
|
||||
tr_torrentSetRatioLimit( tor, d );
|
||||
if( tr_bencDictFindInt( args_in, "ratio-limit-mode", &tmp ) )
|
||||
tr_torrentSetRatioMode( tor, tmp );
|
||||
notify( session, TR_RPC_TORRENT_CHANGED, tor );
|
||||
}
|
||||
|
||||
|
@ -786,6 +790,7 @@ sessionSet( tr_session * session,
|
|||
struct tr_rpc_idle_data * idle_data )
|
||||
{
|
||||
int64_t i;
|
||||
double d;
|
||||
const char * str;
|
||||
|
||||
assert( idle_data == NULL );
|
||||
|
@ -808,6 +813,10 @@ sessionSet( tr_session * session,
|
|||
tr_sessionSetSpeedLimit( session, TR_UP, i );
|
||||
if( tr_bencDictFindInt( args_in, "speed-limit-up-enabled", &i ) )
|
||||
tr_sessionSetSpeedLimitEnabled( session, TR_UP, i );
|
||||
if( tr_bencDictFindDouble( args_in, "ratio-limit", &d ) )
|
||||
tr_sessionSetRatioLimit( session, d );
|
||||
if( tr_bencDictFindInt( args_in, "ratio-limit-enabled", &i ) )
|
||||
tr_sessionSetRatioLimited( session, i );
|
||||
if( tr_bencDictFindStr( args_in, "encryption", &str ) )
|
||||
{
|
||||
if( !strcmp( str, "required" ) )
|
||||
|
@ -892,6 +901,8 @@ sessionGet( tr_session * session,
|
|||
tr_bencDictAddInt( d, "speed-limit-up-enabled", tr_sessionIsSpeedLimitEnabled( session, TR_UP ) );
|
||||
tr_bencDictAddInt( d, "speed-limit-down", tr_sessionGetSpeedLimit( session, TR_DOWN ) );
|
||||
tr_bencDictAddInt( d, "speed-limit-down-enabled", tr_sessionIsSpeedLimitEnabled( session, TR_DOWN ) );
|
||||
tr_bencDictAddDouble( d, "ratio-limit", tr_sessionGetRatioLimit( session ) );
|
||||
tr_bencDictAddInt( d, "ratio-limit-enabled", tr_sessionIsRatioLimited( session ) );
|
||||
tr_bencDictAddStr( d, "version", LONG_VERSION_STRING );
|
||||
switch( tr_sessionGetEncryption( session ) ) {
|
||||
case TR_CLEAR_PREFERRED: str = "tolerated"; break;
|
||||
|
|
|
@ -245,6 +245,8 @@ tr_sessionGetDefaultSettings( tr_benc * d )
|
|||
tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_PORT, 80 );
|
||||
tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_TYPE, TR_PROXY_HTTP );
|
||||
tr_bencDictAddStr( d, TR_PREFS_KEY_PROXY_USERNAME, "" );
|
||||
tr_bencDictAddDouble( d, TR_PREFS_KEY_RATIO, 2.0 );
|
||||
tr_bencDictAddInt( d, TR_PREFS_KEY_RATIO_ENABLED, FALSE );
|
||||
tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED, FALSE );
|
||||
tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_ENABLED, TRUE );
|
||||
tr_bencDictAddStr( d, TR_PREFS_KEY_RPC_PASSWORD, "" );
|
||||
|
@ -291,6 +293,8 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
|
|||
tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_PORT, s->proxyPort );
|
||||
tr_bencDictAddInt( d, TR_PREFS_KEY_PROXY_TYPE, s->proxyType );
|
||||
tr_bencDictAddStr( d, TR_PREFS_KEY_PROXY_USERNAME, s->proxyUsername );
|
||||
tr_bencDictAddDouble( d, TR_PREFS_KEY_RATIO, s->desiredRatio );
|
||||
tr_bencDictAddInt( d, TR_PREFS_KEY_RATIO_ENABLED, s->isRatioLimited );
|
||||
tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_AUTH_REQUIRED, tr_sessionIsRPCPasswordEnabled( s ) );
|
||||
tr_bencDictAddInt( d, TR_PREFS_KEY_RPC_ENABLED, tr_sessionIsRPCEnabled( s ) );
|
||||
tr_bencDictAddStr( d, TR_PREFS_KEY_RPC_PASSWORD, freeme[n++] = tr_sessionGetRPCPassword( s ) );
|
||||
|
@ -408,6 +412,7 @@ tr_sessionInitImpl( void * vdata )
|
|||
{
|
||||
int64_t i;
|
||||
int64_t j;
|
||||
double d;
|
||||
tr_bool found;
|
||||
const char * str;
|
||||
tr_benc settings;
|
||||
|
@ -555,6 +560,12 @@ tr_sessionInitImpl( void * vdata )
|
|||
tr_sessionSetSpeedLimit( session, TR_DOWN, i );
|
||||
tr_sessionSetSpeedLimitEnabled( session, TR_DOWN, j );
|
||||
|
||||
found = tr_bencDictFindDouble( &settings, TR_PREFS_KEY_RATIO, &d )
|
||||
&& tr_bencDictFindInt( &settings, TR_PREFS_KEY_RATIO_ENABLED, &j );
|
||||
assert( found );
|
||||
tr_sessionSetRatioLimit( session, d );
|
||||
tr_sessionSetRatioLimited( session, j );
|
||||
|
||||
/* initialize the blocklist */
|
||||
filename = tr_buildPath( session->configDir, "blocklists", NULL );
|
||||
tr_mkdirp( filename, 0777 );
|
||||
|
@ -737,6 +748,15 @@ tr_sessionSetSpeedLimitEnabled( tr_session * session,
|
|||
updateBandwidth( session, dir );
|
||||
}
|
||||
|
||||
void
|
||||
tr_sessionSetRatioLimited( tr_session * session,
|
||||
tr_bool isLimited )
|
||||
{
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
session->isRatioLimited = isLimited;
|
||||
}
|
||||
|
||||
void
|
||||
tr_sessionSetSpeedLimit( tr_session * session,
|
||||
tr_direction dir,
|
||||
|
@ -749,6 +769,15 @@ tr_sessionSetSpeedLimit( tr_session * session,
|
|||
updateBandwidth( session, dir );
|
||||
}
|
||||
|
||||
void
|
||||
tr_sessionSetRatioLimit( tr_session * session,
|
||||
double desiredRatio )
|
||||
{
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
session->desiredRatio = desiredRatio;
|
||||
}
|
||||
|
||||
tr_bool
|
||||
tr_sessionIsSpeedLimitEnabled( const tr_session * session,
|
||||
tr_direction dir )
|
||||
|
@ -759,6 +788,14 @@ tr_sessionIsSpeedLimitEnabled( const tr_session * session,
|
|||
return session->isSpeedLimited[dir];
|
||||
}
|
||||
|
||||
tr_bool
|
||||
tr_sessionIsRatioLimited( const tr_session * session )
|
||||
{
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
return session->isRatioLimited;
|
||||
}
|
||||
|
||||
int
|
||||
tr_sessionGetSpeedLimit( const tr_session * session,
|
||||
tr_direction dir )
|
||||
|
@ -769,6 +806,14 @@ tr_sessionGetSpeedLimit( const tr_session * session,
|
|||
return session->speedLimit[dir];
|
||||
}
|
||||
|
||||
double
|
||||
tr_sessionGetRatioLimit( const tr_session * session )
|
||||
{
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
return session->desiredRatio;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
|
|
@ -66,6 +66,7 @@ struct tr_session
|
|||
tr_bool isClosed;
|
||||
tr_bool isWaiting;
|
||||
tr_bool useLazyBitfield;
|
||||
tr_bool isRatioLimited;
|
||||
|
||||
tr_bool isSpeedLimited[2];
|
||||
int speedLimit[2];
|
||||
|
@ -128,7 +129,9 @@ struct tr_session
|
|||
int so_rcvbuf;
|
||||
|
||||
/* monitors the "global pool" speeds */
|
||||
struct tr_bandwidth * bandwidth;
|
||||
struct tr_bandwidth * bandwidth;
|
||||
|
||||
double desiredRatio;
|
||||
};
|
||||
|
||||
const char * tr_sessionFindTorrentFile( const tr_session * session,
|
||||
|
@ -141,7 +144,6 @@ void tr_sessionSetTorrentFile( tr_session * session,
|
|||
tr_bool tr_sessionIsAddressBlocked( const tr_session * session,
|
||||
const struct tr_address * addr );
|
||||
|
||||
|
||||
void tr_globalLock( tr_session * );
|
||||
|
||||
void tr_globalUnlock( tr_session * );
|
||||
|
|
|
@ -145,9 +145,46 @@ int
|
|||
tr_torrentGetSpeedLimit( const tr_torrent * tor,
|
||||
tr_direction dir )
|
||||
{
|
||||
assert( tr_isTorrent( tor ) );
|
||||
|
||||
return tr_bandwidthGetDesiredSpeed( tor->bandwidth, dir );
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrentSetRatioMode( tr_torrent * tor,
|
||||
tr_ratiolimit mode )
|
||||
{
|
||||
assert( tr_isTorrent( tor ) );
|
||||
assert( mode==TR_RATIOLIMIT_GLOBAL || mode==TR_RATIOLIMIT_SINGLE || mode==TR_RATIOLIMIT_UNLIMITED );
|
||||
|
||||
tor->ratioLimitMode = mode;
|
||||
}
|
||||
|
||||
tr_ratiolimit
|
||||
tr_torrentGetRatioMode( const tr_torrent * tor )
|
||||
{
|
||||
assert( tr_isTorrent( tor ) );
|
||||
|
||||
return tor->ratioLimitMode;
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrentSetRatioLimit( tr_torrent * tor,
|
||||
double desiredRatio )
|
||||
{
|
||||
assert( tr_isTorrent( tor ) );
|
||||
|
||||
tor->desiredRatio = desiredRatio;
|
||||
}
|
||||
|
||||
double
|
||||
tr_torrentGetRatioLimit( const tr_torrent * tor )
|
||||
{
|
||||
assert( tr_isTorrent( tor ) );
|
||||
|
||||
return tor->desiredRatio;
|
||||
}
|
||||
|
||||
tr_bool
|
||||
tr_torrentIsPieceTransferAllowed( const tr_torrent * tor,
|
||||
tr_direction direction )
|
||||
|
@ -177,6 +214,33 @@ tr_torrentIsPieceTransferAllowed( const tr_torrent * tor,
|
|||
return isEnabled;
|
||||
}
|
||||
|
||||
tr_bool
|
||||
tr_torrentGetSeedRatio( const tr_torrent * tor, double * ratio )
|
||||
{
|
||||
double r = 0;
|
||||
tr_bool isLimited;
|
||||
|
||||
switch( tr_torrentGetRatioMode( tor ) )
|
||||
{
|
||||
case TR_RATIOLIMIT_SINGLE:
|
||||
isLimited = TRUE;
|
||||
r = tr_torrentGetRatioLimit( tor );
|
||||
break;
|
||||
|
||||
case TR_RATIOLIMIT_GLOBAL:
|
||||
if(( isLimited = tr_sessionIsRatioLimited( tor->session )))
|
||||
r = tr_sessionGetRatioLimit( tor->session );
|
||||
break;
|
||||
|
||||
case TR_RATIOLIMIT_UNLIMITED:
|
||||
isLimited = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
*ratio = r;
|
||||
return isLimited;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -525,8 +589,14 @@ torrentRealInit( tr_session * session,
|
|||
tr_torrentSetSpeedLimit( tor, TR_UP,
|
||||
tr_sessionGetSpeedLimit( tor->session, TR_UP ) );
|
||||
tr_torrentSetSpeedLimit( tor, TR_DOWN,
|
||||
tr_sessionGetSpeedLimit( tor->session,
|
||||
TR_DOWN ) );
|
||||
tr_sessionGetSpeedLimit( tor->session, TR_DOWN ) );
|
||||
}
|
||||
|
||||
if( !( loaded & TR_FR_RATIOLIMIT ) )
|
||||
{
|
||||
tr_torrentSetRatioMode( tor, tr_sessionIsRatioLimited( tor-> session )
|
||||
? TR_RATIOLIMIT_GLOBAL : TR_RATIOLIMIT_UNLIMITED );
|
||||
tr_torrentSetRatioLimit( tor, tr_sessionGetRatioLimit( tor->session ) );
|
||||
}
|
||||
|
||||
tor->completeness = tr_cpGetStatus( &tor->completion );
|
||||
|
@ -1296,12 +1366,29 @@ tr_torrentSetCompletenessCallback( tr_torrent * tor,
|
|||
tor->completeness_func_user_data = user_data;
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrentSetRatioLimitHitCallback( tr_torrent * tor,
|
||||
tr_torrent_ratio_limit_hit_func func,
|
||||
void * user_data )
|
||||
{
|
||||
assert( tr_isTorrent( tor ) );
|
||||
|
||||
tor->ratio_limit_hit_func = func;
|
||||
tor->ratio_limit_hit_func_user_data = user_data;
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrentClearCompletenessCallback( tr_torrent * torrent )
|
||||
{
|
||||
tr_torrentSetCompletenessCallback( torrent, NULL, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrentClearRatioLimitHitCallback( tr_torrent * torrent )
|
||||
{
|
||||
tr_torrentSetRatioLimitHitCallback( torrent, NULL, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrentRecheckCompleteness( tr_torrent * tor )
|
||||
{
|
||||
|
|
|
@ -70,6 +70,9 @@ tr_torrent* tr_torrentFindFromObfuscatedHash( tr_session * session,
|
|||
tr_bool tr_torrentIsPieceTransferAllowed( const tr_torrent * torrent,
|
||||
tr_direction direction );
|
||||
|
||||
tr_bool tr_torrentGetSeedRatio( const tr_torrent * tor, double * ratio );
|
||||
|
||||
|
||||
|
||||
#define tr_block( a, b ) _tr_block( tor, a, b )
|
||||
tr_block_index_t _tr_block( const tr_torrent * tor,
|
||||
|
@ -185,6 +188,9 @@ struct tr_torrent
|
|||
tr_torrent_completeness_func * completeness_func;
|
||||
void * completeness_func_user_data;
|
||||
|
||||
tr_torrent_ratio_limit_hit_func * ratio_limit_hit_func;
|
||||
void * ratio_limit_hit_func_user_data;
|
||||
|
||||
tr_bool isRunning;
|
||||
tr_bool isDeleting;
|
||||
|
||||
|
@ -202,6 +208,9 @@ struct tr_torrent
|
|||
struct tr_bandwidth * bandwidth;
|
||||
|
||||
struct tr_torrent_peers * torrentPeers;
|
||||
|
||||
double desiredRatio;
|
||||
tr_ratiolimit ratioLimitMode;
|
||||
};
|
||||
|
||||
/* get the index of this piece's first block */
|
||||
|
|
|
@ -29,11 +29,11 @@ extern int tr_optind;
|
|||
|
||||
typedef struct tr_option
|
||||
{
|
||||
int val; /* the value to return from tr_getopt() */
|
||||
int val; /* the value to return from tr_getopt() */
|
||||
const char * longName; /* --long-form */
|
||||
const char * description; /* option's description for tr_getopt_usage() */
|
||||
const char * shortName; /* short form */
|
||||
int has_arg; /* 0 for no argument, 1 for argument */
|
||||
int has_arg; /* 0 for no argument, 1 for argument */
|
||||
const char * argName; /* argument's description for tr_getopt_usage() */
|
||||
}
|
||||
tr_option;
|
||||
|
|
|
@ -176,6 +176,8 @@ static TR_INLINE tr_bool tr_isEncryptionMode( tr_encryption_mode m )
|
|||
#define TR_PREFS_KEY_PROXY "proxy"
|
||||
#define TR_PREFS_KEY_PROXY_TYPE "proxy-type"
|
||||
#define TR_PREFS_KEY_PROXY_USERNAME "proxy-auth-username"
|
||||
#define TR_PREFS_KEY_RATIO "ratio-limit"
|
||||
#define TR_PREFS_KEY_RATIO_ENABLED "ratio-limit-enabled"
|
||||
#define TR_PREFS_KEY_RPC_AUTH_REQUIRED "rpc-authentication-required"
|
||||
#define TR_PREFS_KEY_RPC_ENABLED "rpc-enabled"
|
||||
#define TR_PREFS_KEY_RPC_PASSWORD "rpc-password"
|
||||
|
@ -560,6 +562,16 @@ void tr_sessionSetSpeedLimit ( tr_session * session,
|
|||
int tr_sessionGetSpeedLimit ( const tr_session * session,
|
||||
tr_direction direction );
|
||||
|
||||
void tr_sessionSetRatioLimited ( tr_session * session,
|
||||
tr_bool isEnabled );
|
||||
|
||||
tr_bool tr_sessionIsRatioLimited ( const tr_session * session);
|
||||
|
||||
void tr_sessionSetRatioLimit ( tr_session * session,
|
||||
double desiredRatio);
|
||||
|
||||
double tr_sessionGetRatioLimit ( const tr_session * session);
|
||||
|
||||
double tr_sessionGetRawSpeed ( const tr_session * session,
|
||||
tr_direction direction );
|
||||
|
||||
|
@ -866,6 +878,14 @@ typedef enum
|
|||
}
|
||||
tr_speedlimit;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_RATIOLIMIT_GLOBAL = 0, /* follow the global settings */
|
||||
TR_RATIOLIMIT_SINGLE = 1, /* override the global settings, seeding until a certain ratio */
|
||||
TR_RATIOLIMIT_UNLIMITED = 2 /* override the global settings, seeding regardless of ratio */
|
||||
}
|
||||
tr_ratiolimit;
|
||||
|
||||
void tr_torrentSetSpeedMode( tr_torrent * tor,
|
||||
tr_direction up_or_down,
|
||||
tr_speedlimit mode );
|
||||
|
@ -880,6 +900,16 @@ void tr_torrentSetSpeedLimit( tr_torrent * tor,
|
|||
int tr_torrentGetSpeedLimit( const tr_torrent * tor,
|
||||
tr_direction direction );
|
||||
|
||||
void tr_torrentSetRatioMode( tr_torrent * tor,
|
||||
tr_ratiolimit mode );
|
||||
|
||||
tr_ratiolimit tr_torrentGetRatioMode( const tr_torrent * tor );
|
||||
|
||||
void tr_torrentSetRatioLimit( tr_torrent * tor,
|
||||
double ratio );
|
||||
|
||||
double tr_torrentGetRatioLimit( const tr_torrent * tor );
|
||||
|
||||
/****
|
||||
***** Peer Limits
|
||||
****/
|
||||
|
@ -994,6 +1024,9 @@ typedef void ( tr_torrent_completeness_func )( tr_torrent * torrent,
|
|||
tr_completeness completeness,
|
||||
void * user_data );
|
||||
|
||||
typedef void ( tr_torrent_ratio_limit_hit_func )( tr_torrent * torrent,
|
||||
void * user_data );
|
||||
|
||||
/**
|
||||
* Register to be notified whenever a torrent's "completeness"
|
||||
* changes. This will be called, for example, when a torrent
|
||||
|
@ -1015,6 +1048,21 @@ void tr_torrentSetCompletenessCallback(
|
|||
void tr_torrentClearCompletenessCallback( tr_torrent * torrent );
|
||||
|
||||
|
||||
/**
|
||||
* Register to be notified whenever a torrent's ratio limit
|
||||
* has been hit. This will be called when the torrent's
|
||||
* ul/dl ratio has met or exceeded the designated ratio limit.
|
||||
*
|
||||
* Has the same restrictions as tr_torrentSetCompletenessCallback
|
||||
*/
|
||||
void tr_torrentSetRatioLimitHitCallback(
|
||||
tr_torrent * torrent,
|
||||
tr_torrent_ratio_limit_hit_func func,
|
||||
void * user_data );
|
||||
|
||||
void tr_torrentClearRatioLimitHitCallback( tr_torrent * torrent );
|
||||
|
||||
|
||||
/**
|
||||
* MANUAL ANNOUNCE
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue