hydrus/include/ClientNetworking.py

364 lines
11 KiB
Python
Raw Normal View History

2017-06-28 20:23:21 +00:00
import ClientConstants as CC
2017-06-07 22:05:15 +00:00
import collections
2017-06-28 20:23:21 +00:00
import cPickle
2017-06-21 21:15:59 +00:00
import cStringIO
2015-10-21 21:53:10 +00:00
import HydrusConstants as HC
2017-10-25 21:45:15 +00:00
import HydrusData
2015-10-21 21:53:10 +00:00
import HydrusExceptions
2017-10-25 21:45:15 +00:00
import HydrusGlobals as HG
2017-03-02 02:14:56 +00:00
import HydrusNetwork
2017-06-07 22:05:15 +00:00
import HydrusNetworking
2015-11-04 22:30:28 +00:00
import HydrusPaths
2015-10-21 21:53:10 +00:00
import HydrusSerialisable
2017-10-25 21:45:15 +00:00
import itertools
2015-10-21 21:53:10 +00:00
import os
2017-06-21 21:15:59 +00:00
import random
2016-02-24 21:42:54 +00:00
import requests
2017-06-21 21:15:59 +00:00
import urllib3
from urllib3.exceptions import InsecureRequestWarning
2015-10-21 21:53:10 +00:00
import threading
import time
2017-06-21 21:15:59 +00:00
import traceback
2015-10-21 21:53:10 +00:00
import urllib
import urlparse
import yaml
2017-06-21 21:15:59 +00:00
urllib3.disable_warnings( InsecureRequestWarning )
2017-01-25 22:56:55 +00:00
2018-04-18 22:10:15 +00:00
JOB_STATUS_AWAITING_VALIDITY = 0
JOB_STATUS_AWAITING_BANDWIDTH = 1
JOB_STATUS_AWAITING_LOGIN = 2
JOB_STATUS_AWAITING_SLOT = 3
JOB_STATUS_RUNNING = 4
job_status_str_lookup = {}
job_status_str_lookup[ JOB_STATUS_AWAITING_VALIDITY ] = 'waiting for validation'
job_status_str_lookup[ JOB_STATUS_AWAITING_BANDWIDTH ] = 'waiting for bandwidth'
job_status_str_lookup[ JOB_STATUS_AWAITING_LOGIN ] = 'waiting for login'
job_status_str_lookup[ JOB_STATUS_AWAITING_SLOT ] = 'waiting for slot'
job_status_str_lookup[ JOB_STATUS_RUNNING ] = 'running'
class NetworkEngine( object ):
2017-10-25 21:45:15 +00:00
2018-04-18 22:10:15 +00:00
MAX_JOBS = 10 # turn this into an option
2017-10-25 21:45:15 +00:00
2018-04-18 22:10:15 +00:00
def __init__( self, controller, bandwidth_manager, session_manager, domain_manager, login_manager ):
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
self.controller = controller
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
self.bandwidth_manager = bandwidth_manager
self.session_manager = session_manager
self.domain_manager = domain_manager
self.login_manager = login_manager
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
self.bandwidth_manager.engine = self
self.session_manager.engine = self
self.domain_manager.engine = self
self.login_manager.engine = self
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
self._lock = threading.Lock()
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
self._new_work_to_do = threading.Event()
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
self._jobs_awaiting_validity = []
self._current_validation_process = None
self._jobs_awaiting_bandwidth = []
self._jobs_awaiting_login = []
self._current_login_process = None
self._jobs_awaiting_slot = []
self._jobs_running = []
2017-10-25 21:45:15 +00:00
2018-04-18 22:10:15 +00:00
self._pause_all_new_network_traffic = self.controller.new_options.GetBoolean( 'pause_all_new_network_traffic' )
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
self._is_running = False
self._is_shutdown = False
self._local_shutdown = False
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
def AddJob( self, job ):
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
with self._lock:
2015-10-21 21:53:10 +00:00
2018-04-18 22:10:15 +00:00
job.engine = self
2017-05-31 21:50:53 +00:00
2018-04-18 22:10:15 +00:00
self._jobs_awaiting_validity.append( job )
2017-05-31 21:50:53 +00:00
2018-04-18 22:10:15 +00:00
self._new_work_to_do.set()
2017-06-07 22:05:15 +00:00
2018-04-18 22:10:15 +00:00
def GetJobsSnapshot( self ):
2017-08-16 21:58:06 +00:00
2018-04-18 22:10:15 +00:00
with self._lock:
2017-08-16 21:58:06 +00:00
2018-04-18 22:10:15 +00:00
jobs = []
2017-08-16 21:58:06 +00:00
2018-04-18 22:10:15 +00:00
jobs.extend( ( ( JOB_STATUS_AWAITING_VALIDITY, j ) for j in self._jobs_awaiting_validity ) )
jobs.extend( ( ( JOB_STATUS_AWAITING_BANDWIDTH, j ) for j in self._jobs_awaiting_bandwidth ) )
jobs.extend( ( ( JOB_STATUS_AWAITING_LOGIN, j ) for j in self._jobs_awaiting_login ) )
jobs.extend( ( ( JOB_STATUS_AWAITING_SLOT, j ) for j in self._jobs_awaiting_slot ) )
jobs.extend( ( ( JOB_STATUS_RUNNING, j ) for j in self._jobs_running ) )
2017-06-07 22:05:15 +00:00
2018-04-18 22:10:15 +00:00
return jobs
2017-06-07 22:05:15 +00:00
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
def IsRunning( self ):
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
with self._lock:
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
return self._is_running
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
def IsShutdown( self ):
2017-08-16 21:58:06 +00:00
2018-04-18 22:10:15 +00:00
with self._lock:
2017-08-16 21:58:06 +00:00
2018-04-18 22:10:15 +00:00
return self._is_shutdown
2017-08-16 21:58:06 +00:00
2017-07-05 21:09:28 +00:00
2018-04-18 22:10:15 +00:00
def MainLoop( self ):
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
def ProcessValidationJob( job ):
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
if job.IsDone():
return False
elif job.IsAsleep():
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
return True
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
elif not job.IsValid():
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
if job.CanValidateInPopup():
if self._current_validation_process is None:
validation_process = job.GenerateValidationPopupProcess()
self.controller.CallToThread( validation_process.Start )
self._current_validation_process = validation_process
job.SetStatus( u'validation presented to user\u2026' )
else:
job.SetStatus( u'waiting in user validation queue\u2026' )
job.Sleep( 5 )
return True
else:
error_text = u'network context not currently valid!'
job.SetError( HydrusExceptions.ValidationException( error_text ), error_text )
2017-06-28 20:23:21 +00:00
return False
2018-04-18 22:10:15 +00:00
else:
self._jobs_awaiting_bandwidth.append( job )
return False
2017-06-28 20:23:21 +00:00
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
def ProcessCurrentValidationJob():
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
if self._current_validation_process is not None:
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
if self._current_validation_process.IsDone():
2017-07-27 00:47:13 +00:00
2018-04-18 22:10:15 +00:00
self._current_validation_process = None
2017-07-27 00:47:13 +00:00
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
def ProcessBandwidthJob( job ):
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
if job.IsDone():
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
return False
elif job.IsAsleep():
return True
elif not job.BandwidthOK():
return True
2017-06-28 20:23:21 +00:00
else:
2018-04-18 22:10:15 +00:00
self._jobs_awaiting_login.append( job )
return False
2017-06-28 20:23:21 +00:00
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
def ProcessLoginJob( job ):
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
if job.IsDone():
return False
elif job.IsAsleep():
return True
elif job.NeedsLogin():
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
try:
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
job.CheckCanLogin()
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
except Exception as e:
job.SetError( e, HydrusData.ToUnicode( e ) )
return False
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
if self._current_login_process is None:
login_process = job.GenerateLoginProcess()
self.controller.CallToThread( login_process.Start )
self._current_login_process = login_process
job.SetStatus( u'logging in\u2026' )
else:
job.SetStatus( u'waiting in login queue\u2026' )
job.Sleep( 5 )
return True
else:
self._jobs_awaiting_slot.append( job )
return False
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
def ProcessCurrentLoginJob():
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
if self._current_login_process is not None:
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
if self._current_login_process.IsDone():
2017-07-19 21:21:41 +00:00
2018-04-18 22:10:15 +00:00
self._current_login_process = None
2017-07-19 21:21:41 +00:00
2017-07-12 20:03:45 +00:00
2018-04-18 22:10:15 +00:00
def ProcessReadyJob( job ):
2017-08-16 21:58:06 +00:00
2018-04-18 22:10:15 +00:00
if job.IsDone():
2017-07-12 20:03:45 +00:00
2018-04-18 22:10:15 +00:00
return False
2017-07-12 20:03:45 +00:00
2018-04-18 22:10:15 +00:00
elif len( self._jobs_running ) < self.MAX_JOBS:
if self._pause_all_new_network_traffic:
2017-07-12 20:03:45 +00:00
2018-04-18 22:10:15 +00:00
job.SetStatus( u'all new network traffic is paused\u2026' )
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
return True
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
else:
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
self.controller.CallToThread( job.Start )
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
self._jobs_running.append( job )
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
return False
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
else:
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
job.SetStatus( u'waiting for download slot\u2026' )
2017-07-27 00:47:13 +00:00
2018-04-18 22:10:15 +00:00
return True
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
def ProcessRunningJob( job ):
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
if job.IsDone():
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
return False
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
else:
2017-09-27 21:52:54 +00:00
2018-04-18 22:10:15 +00:00
return True
2017-09-27 21:52:54 +00:00
2017-09-06 20:18:20 +00:00
2018-04-18 22:10:15 +00:00
self._is_running = True
while not ( self._local_shutdown or self.controller.ModelIsShutdown() ):
2017-09-06 20:18:20 +00:00
2018-04-18 22:10:15 +00:00
with self._lock:
2017-09-06 20:18:20 +00:00
2018-04-18 22:10:15 +00:00
self._jobs_awaiting_validity = filter( ProcessValidationJob, self._jobs_awaiting_validity )
2017-09-06 20:18:20 +00:00
2018-04-18 22:10:15 +00:00
ProcessCurrentValidationJob()
2017-09-06 20:18:20 +00:00
2018-04-18 22:10:15 +00:00
self._jobs_awaiting_bandwidth = filter( ProcessBandwidthJob, self._jobs_awaiting_bandwidth )
2017-09-06 20:18:20 +00:00
2018-04-18 22:10:15 +00:00
self._jobs_awaiting_login = filter( ProcessLoginJob, self._jobs_awaiting_login )
2017-10-25 21:45:15 +00:00
2018-04-18 22:10:15 +00:00
ProcessCurrentLoginJob()
2017-10-25 21:45:15 +00:00
2018-04-18 22:10:15 +00:00
self._jobs_awaiting_slot = filter( ProcessReadyJob, self._jobs_awaiting_slot )
2017-10-25 21:45:15 +00:00
2018-04-18 22:10:15 +00:00
self._jobs_running = filter( ProcessRunningJob, self._jobs_running )
2017-10-25 21:45:15 +00:00
2018-04-18 22:10:15 +00:00
# we want to catch the rollover of the second for bandwidth jobs
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
now_with_subsecond = time.time()
subsecond_part = now_with_subsecond % 1
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
time_until_next_second = 1.0 - subsecond_part
2017-06-28 20:23:21 +00:00
2018-04-18 22:10:15 +00:00
self._new_work_to_do.wait( time_until_next_second )
2017-07-27 00:47:13 +00:00
2018-04-18 22:10:15 +00:00
self._new_work_to_do.clear()
2017-06-28 20:23:21 +00:00
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
self._is_running = False
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
self._is_shutdown = True
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
def PausePlayNewJobs( self ):
2018-03-22 00:03:33 +00:00
2018-04-18 22:10:15 +00:00
self._pause_all_new_network_traffic = not self._pause_all_new_network_traffic
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
self.controller.new_options.SetBoolean( 'pause_all_new_network_traffic', self._pause_all_new_network_traffic )
2017-06-21 21:15:59 +00:00
2018-04-18 22:10:15 +00:00
def Shutdown( self ):
2017-07-05 21:09:28 +00:00
2018-04-18 22:10:15 +00:00
self._local_shutdown = True
2017-07-05 21:09:28 +00:00
2018-04-18 22:10:15 +00:00
self._new_work_to_do.set()
2017-07-05 21:09:28 +00:00