2018-08-26 02:45:37 +02:00
import time
import os
import logging
import json
import atexit
import gevent
from Config import config
from Plugin import PluginManager
from util import helper
class TrackerStorage ( object ) :
def __init__ ( self ) :
self . log = logging . getLogger ( " TrackerStorage " )
self . file_path = " %s /trackers.json " % config . data_dir
2019-01-20 19:12:11 +01:00
self . load ( )
2018-08-26 02:45:37 +02:00
self . time_discover = 0.0
atexit . register ( self . save )
def getDefaultFile ( self ) :
return { " shared " : { } }
def onTrackerFound ( self , tracker_address , type = " shared " , my = False ) :
2018-08-27 11:49:24 +02:00
if not tracker_address . startswith ( " zero:// " ) :
return False
2018-08-26 02:45:37 +02:00
trackers = self . getTrackers ( )
2018-08-29 19:51:26 +02:00
added = False
2018-08-26 02:45:37 +02:00
if tracker_address not in trackers :
trackers [ tracker_address ] = {
" time_added " : time . time ( ) ,
" time_success " : 0 ,
" latency " : 99.0 ,
" num_error " : 0 ,
" my " : False
}
2018-08-26 22:52:30 +02:00
self . log . debug ( " New tracker found: %s " % tracker_address )
2018-08-29 19:51:26 +02:00
added = True
2018-08-27 11:49:05 +02:00
2018-08-26 02:45:37 +02:00
trackers [ tracker_address ] [ " time_found " ] = time . time ( )
trackers [ tracker_address ] [ " my " ] = my
2018-08-29 19:51:26 +02:00
return added
2018-08-26 02:45:37 +02:00
def onTrackerSuccess ( self , tracker_address , latency ) :
trackers = self . getTrackers ( )
if tracker_address not in trackers :
return False
trackers [ tracker_address ] [ " latency " ] = latency
trackers [ tracker_address ] [ " time_success " ] = time . time ( )
trackers [ tracker_address ] [ " num_error " ] = 0
def onTrackerError ( self , tracker_address ) :
trackers = self . getTrackers ( )
if tracker_address not in trackers :
return False
trackers [ tracker_address ] [ " time_error " ] = time . time ( )
trackers [ tracker_address ] [ " num_error " ] + = 1
2018-09-17 15:20:02 +02:00
if len ( self . getWorkingTrackers ( ) ) > = config . working_shared_trackers_limit :
error_limit = 5
2018-09-02 02:17:18 +02:00
else :
error_limit = 30
error_limit
if trackers [ tracker_address ] [ " num_error " ] > error_limit and trackers [ tracker_address ] [ " time_success " ] < time . time ( ) - 60 * 60 :
2018-08-26 02:45:37 +02:00
self . log . debug ( " Tracker %s looks down, removing. " % tracker_address )
del trackers [ tracker_address ]
def getTrackers ( self , type = " shared " ) :
return self . file_content . setdefault ( type , { } )
2018-08-27 11:48:52 +02:00
def getWorkingTrackers ( self , type = " shared " ) :
2018-08-26 02:45:37 +02:00
trackers = {
key : tracker for key , tracker in self . getTrackers ( type ) . iteritems ( )
2018-08-26 22:50:46 +02:00
if tracker [ " time_success " ] > time . time ( ) - 60 * 60
2018-08-26 02:45:37 +02:00
}
return trackers
2019-01-20 19:12:11 +01:00
def getFileContent ( self ) :
2018-08-26 02:45:37 +02:00
if not os . path . isfile ( self . file_path ) :
open ( self . file_path , " w " ) . write ( " {} " )
return self . getDefaultFile ( )
try :
return json . load ( open ( self . file_path ) )
except Exception as err :
self . log . error ( " Error loading trackers list: %s " % err )
return self . getDefaultFile ( )
2019-01-20 19:12:11 +01:00
def load ( self ) :
self . file_content = self . getFileContent ( )
trackers = self . getTrackers ( )
self . log . debug ( " Loaded %s shared trackers " % len ( trackers ) )
for address , tracker in trackers . items ( ) :
tracker [ " num_error " ] = 0
if not address . startswith ( " zero:// " ) :
del trackers [ address ]
2018-08-26 02:45:37 +02:00
def save ( self ) :
s = time . time ( )
helper . atomicWrite ( self . file_path , json . dumps ( self . file_content , indent = 2 , sort_keys = True ) )
self . log . debug ( " Saved in %.3f s " % ( time . time ( ) - s ) )
def discoverTrackers ( self , peers ) :
2018-09-02 02:17:42 +02:00
if len ( self . getWorkingTrackers ( ) ) > config . working_shared_trackers_limit :
2018-08-27 11:48:39 +02:00
return False
2018-08-26 02:45:37 +02:00
s = time . time ( )
num_success = 0
for peer in peers :
if peer . connection and peer . connection . handshake . get ( " rev " , 0 ) < 3560 :
continue # Not supported
res = peer . request ( " getTrackers " )
if not res or " error " in res :
continue
num_success + = 1
for tracker_address in res [ " trackers " ] :
2018-08-27 11:48:25 +02:00
added = self . onTrackerFound ( tracker_address )
if added : # Only add one tracker from one source
break
2018-08-26 02:45:37 +02:00
if not num_success and len ( peers ) < 20 :
self . time_discover = 0.0
if num_success :
self . save ( )
2018-09-17 15:20:02 +02:00
self . log . debug ( " Trackers discovered from %s / %s peers in %.3f s " % ( num_success , len ( peers ) , time . time ( ) - s ) )
2018-08-26 02:45:37 +02:00
2018-08-27 11:48:11 +02:00
if " tracker_storage " not in locals ( ) :
tracker_storage = TrackerStorage ( )
2018-08-26 02:45:37 +02:00
@PluginManager.registerTo ( " SiteAnnouncer " )
class SiteAnnouncerPlugin ( object ) :
def getTrackers ( self ) :
if tracker_storage . time_discover < time . time ( ) - 5 * 60 :
tracker_storage . time_discover = time . time ( )
gevent . spawn ( tracker_storage . discoverTrackers , self . site . getConnectedPeers ( ) )
trackers = super ( SiteAnnouncerPlugin , self ) . getTrackers ( )
shared_trackers = tracker_storage . getTrackers ( " shared " ) . keys ( )
if shared_trackers :
return trackers + shared_trackers
else :
return trackers
def announceTracker ( self , tracker , * args , * * kwargs ) :
res = super ( SiteAnnouncerPlugin , self ) . announceTracker ( tracker , * args , * * kwargs )
if res :
latency = res
tracker_storage . onTrackerSuccess ( tracker , latency )
2018-08-26 22:52:21 +02:00
elif res is False :
2018-08-26 02:45:37 +02:00
tracker_storage . onTrackerError ( tracker )
return res
@PluginManager.registerTo ( " FileRequest " )
class FileRequestPlugin ( object ) :
def actionGetTrackers ( self , params ) :
shared_trackers = tracker_storage . getWorkingTrackers ( " shared " ) . keys ( )
self . response ( { " trackers " : shared_trackers } )
@PluginManager.registerTo ( " FileServer " )
class FileServerPlugin ( object ) :
2019-01-20 19:12:11 +01:00
def portCheck ( self , * args , * * kwargs ) :
res = super ( FileServerPlugin , self ) . portCheck ( * args , * * kwargs )
2018-08-26 02:45:37 +02:00
if res and not config . tor == " always " and " Bootstrapper " in PluginManager . plugin_manager . plugin_names :
my_tracker_address = " zero:// %s : %s " % ( config . ip_external , config . fileserver_port )
tracker_storage . onTrackerFound ( my_tracker_address , my = True )
return res
2018-09-02 02:17:42 +02:00
2019-01-20 19:12:11 +01:00
2018-09-02 02:17:42 +02:00
@PluginManager.registerTo ( " ConfigPlugin " )
class ConfigPlugin ( object ) :
def createArguments ( self ) :
group = self . parser . add_argument_group ( " AnnounceShare plugin " )
group . add_argument ( ' --working_shared_trackers_limit ' , help = ' Stop discovering new shared trackers after this number of shared trackers reached ' , default = 5 , type = int , metavar = ' limit ' )
return super ( ConfigPlugin , self ) . createArguments ( )