hydrus/include/ClientDaemons.py

412 lines
13 KiB
Python
Raw Normal View History

2015-08-19 21:48:21 +00:00
import ClientDownloading
2015-03-18 21:46:29 +00:00
import ClientFiles
2016-02-17 22:06:47 +00:00
import ClientThreading
2015-03-04 22:44:32 +00:00
import collections
import hashlib
import httplib
import itertools
import HydrusConstants as HC
2015-08-19 21:48:21 +00:00
import HydrusData
2015-03-04 22:44:32 +00:00
import HydrusExceptions
import HydrusImageHandling
import HydrusNATPunch
2015-11-04 22:30:28 +00:00
import HydrusPaths
2015-06-03 21:05:13 +00:00
import HydrusSerialisable
2015-03-04 22:44:32 +00:00
import HydrusTagArchive
import HydrusTags
import HydrusThreading
import ClientConstants as CC
import os
import Queue
import random
import shutil
import sqlite3
import stat
import sys
import threading
import time
import traceback
import wx
import yaml
2015-11-04 22:30:28 +00:00
def DAEMONCheckExportFolders( controller ):
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
options = controller.GetOptions()
2015-05-13 20:22:39 +00:00
if not options[ 'pause_export_folders_sync' ]:
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
export_folders = controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_EXPORT_FOLDER )
2015-03-04 22:44:32 +00:00
2015-06-24 22:10:14 +00:00
for export_folder in export_folders:
2015-03-04 22:44:32 +00:00
2015-10-21 21:53:10 +00:00
if options[ 'pause_export_folders_sync' ]:
break
2015-06-24 22:10:14 +00:00
export_folder.DoWork()
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
def DAEMONCheckImportFolders( controller ):
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
options = controller.GetOptions()
2015-05-13 20:22:39 +00:00
if not options[ 'pause_import_folders_sync' ]:
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
import_folders = controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_IMPORT_FOLDER )
2015-03-04 22:44:32 +00:00
2015-09-09 22:04:39 +00:00
for import_folder in import_folders:
2015-03-04 22:44:32 +00:00
2015-10-21 21:53:10 +00:00
if options[ 'pause_import_folders_sync' ]:
break
2015-09-09 22:04:39 +00:00
import_folder.DoWork()
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
def DAEMONCheckMouseIdle( controller ):
2015-10-28 21:29:05 +00:00
2015-11-04 22:30:28 +00:00
wx.CallAfter( controller.CheckMouseIdle )
2015-10-28 21:29:05 +00:00
2015-11-04 22:30:28 +00:00
def DAEMONDownloadFiles( controller ):
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
hashes = controller.Read( 'downloads' )
2015-03-04 22:44:32 +00:00
num_downloads = len( hashes )
2015-07-22 19:40:39 +00:00
if num_downloads > 0:
2015-03-04 22:44:32 +00:00
2016-08-24 18:36:56 +00:00
client_files_manager = controller.GetClientFilesManager()
2015-07-22 19:40:39 +00:00
successful_hashes = set()
2015-03-04 22:44:32 +00:00
2016-02-17 22:06:47 +00:00
job_key = ClientThreading.JobKey()
2015-03-04 22:44:32 +00:00
2015-07-22 19:40:39 +00:00
job_key.SetVariable( 'popup_text_1', 'initialising downloader' )
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
controller.pub( 'message', job_key )
2015-07-22 19:40:39 +00:00
for hash in hashes:
job_key.SetVariable( 'popup_text_1', 'downloading ' + HydrusData.ConvertIntToPrettyString( num_downloads - len( successful_hashes ) ) + ' files from repositories' )
2016-05-04 21:50:55 +00:00
( media_result, ) = controller.Read( 'media_results', ( hash, ) )
2015-03-04 22:44:32 +00:00
2015-07-22 19:40:39 +00:00
service_keys = list( media_result.GetLocationsManager().GetCurrent() )
2015-03-04 22:44:32 +00:00
2015-07-22 19:40:39 +00:00
random.shuffle( service_keys )
2015-03-04 22:44:32 +00:00
2015-07-22 19:40:39 +00:00
for service_key in service_keys:
2015-03-04 22:44:32 +00:00
2015-07-22 19:40:39 +00:00
if service_key == CC.LOCAL_FILE_SERVICE_KEY: break
elif service_key == CC.TRASH_SERVICE_KEY: continue
2016-02-17 22:06:47 +00:00
try:
file_repository = controller.GetServicesManager().GetService( service_key )
except:
continue
2015-07-22 19:40:39 +00:00
if file_repository.CanDownload():
2015-03-04 22:44:32 +00:00
2015-03-25 22:04:19 +00:00
try:
2015-07-22 19:40:39 +00:00
request_args = { 'hash' : hash.encode( 'hex' ) }
2015-03-25 22:04:19 +00:00
2015-11-04 22:30:28 +00:00
( os_file_handle, temp_path ) = HydrusPaths.GetTempPath()
2015-03-25 22:04:19 +00:00
2015-07-22 19:40:39 +00:00
try:
file_repository.Request( HC.GET, 'file', request_args = request_args, temp_path = temp_path )
2015-11-04 22:30:28 +00:00
controller.WaitUntilPubSubsEmpty()
2015-07-22 19:40:39 +00:00
2016-08-24 18:36:56 +00:00
client_files_manager.ImportFile( temp_path, override_deleted = True )
2015-07-22 19:40:39 +00:00
successful_hashes.add( hash )
break
finally:
2015-11-04 22:30:28 +00:00
HydrusPaths.CleanUpTempPath( os_file_handle, temp_path )
2015-07-22 19:40:39 +00:00
2015-03-25 22:04:19 +00:00
2015-07-22 19:40:39 +00:00
except HydrusExceptions.ServerBusyException:
2015-03-25 22:04:19 +00:00
2015-07-22 19:40:39 +00:00
job_key.SetVariable( 'popup_text_1', file_repository.GetName() + ' was busy. waiting 30s before trying again' )
2015-03-25 22:04:19 +00:00
2015-07-22 19:40:39 +00:00
time.sleep( 30 )
job_key.Delete()
2015-11-04 22:30:28 +00:00
controller.pub( 'notify_new_downloads' )
2015-07-22 19:40:39 +00:00
return
except Exception as e:
HydrusData.ShowText( 'Error downloading file!' )
HydrusData.ShowException( e )
2015-03-25 22:04:19 +00:00
2015-03-04 22:44:32 +00:00
2015-09-16 18:11:00 +00:00
if HydrusThreading.IsThreadShuttingDown():
return
2015-07-22 19:40:39 +00:00
if len( successful_hashes ) > 0:
2015-03-04 22:44:32 +00:00
2015-07-22 19:40:39 +00:00
job_key.SetVariable( 'popup_text_1', HydrusData.ConvertIntToPrettyString( len( successful_hashes ) ) + ' files downloaded' )
2015-03-04 22:44:32 +00:00
2015-07-22 19:40:39 +00:00
else:
job_key.SetVariable( 'popup_text_1', 'all files failed to download' )
job_key.Delete()
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
def DAEMONFlushServiceUpdates( controller, list_of_service_keys_to_service_updates ):
2015-03-04 22:44:32 +00:00
2015-03-25 22:04:19 +00:00
service_keys_to_service_updates = HydrusData.MergeKeyToListDicts( list_of_service_keys_to_service_updates )
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
controller.WriteSynchronous( 'service_updates', service_keys_to_service_updates )
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
def DAEMONMaintainTrash( controller ):
2015-07-15 20:28:26 +00:00
2015-08-12 20:35:24 +00:00
if HC.options[ 'trash_max_size' ] is not None:
max_size = HC.options[ 'trash_max_size' ] * 1048576
2015-07-15 20:28:26 +00:00
2015-11-04 22:30:28 +00:00
service_info = controller.Read( 'service_info', CC.TRASH_SERVICE_KEY )
2015-07-15 20:28:26 +00:00
while service_info[ HC.SERVICE_INFO_TOTAL_SIZE ] > max_size:
2015-09-16 18:11:00 +00:00
if HydrusThreading.IsThreadShuttingDown():
2015-07-15 20:28:26 +00:00
return
2016-06-01 20:04:15 +00:00
hashes = controller.Read( 'trash_hashes', limit = 10 )
2015-07-15 20:28:26 +00:00
if len( hashes ) == 0:
return
2015-10-14 21:02:25 +00:00
content_update = HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_DELETE, hashes )
2015-07-15 20:28:26 +00:00
service_keys_to_content_updates = { CC.TRASH_SERVICE_KEY : [ content_update ] }
2015-11-04 22:30:28 +00:00
controller.WaitUntilPubSubsEmpty()
2015-07-15 20:28:26 +00:00
2015-11-04 22:30:28 +00:00
controller.WriteSynchronous( 'content_updates', service_keys_to_content_updates )
2015-07-15 20:28:26 +00:00
2015-11-04 22:30:28 +00:00
service_info = controller.Read( 'service_info', CC.TRASH_SERVICE_KEY )
2015-07-15 20:28:26 +00:00
2015-08-12 20:35:24 +00:00
if HC.options[ 'trash_max_age' ] is not None:
max_age = HC.options[ 'trash_max_age' ] * 3600
2015-07-15 20:28:26 +00:00
2016-06-01 20:04:15 +00:00
hashes = controller.Read( 'trash_hashes', limit = 10, minimum_age = max_age )
2015-07-15 20:28:26 +00:00
while len( hashes ) > 0:
2015-09-16 18:11:00 +00:00
if HydrusThreading.IsThreadShuttingDown():
2015-07-15 20:28:26 +00:00
return
2015-10-14 21:02:25 +00:00
content_update = HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_DELETE, hashes )
2015-07-15 20:28:26 +00:00
service_keys_to_content_updates = { CC.TRASH_SERVICE_KEY : [ content_update ] }
2015-11-04 22:30:28 +00:00
controller.WaitUntilPubSubsEmpty()
2015-07-15 20:28:26 +00:00
2015-11-04 22:30:28 +00:00
controller.WriteSynchronous( 'content_updates', service_keys_to_content_updates )
2015-07-15 20:28:26 +00:00
2016-06-01 20:04:15 +00:00
hashes = controller.Read( 'trash_hashes', limit = 10, minimum_age = max_age )
2015-07-15 20:28:26 +00:00
2015-12-02 22:32:18 +00:00
def DAEMONRebalanceClientFiles( controller ):
2016-01-13 22:08:19 +00:00
if controller.CurrentlyIdle():
2015-12-02 22:32:18 +00:00
controller.GetClientFilesManager().Rebalance()
2015-11-04 22:30:28 +00:00
def DAEMONSynchroniseAccounts( controller ):
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
services = controller.GetServicesManager().GetServices( HC.RESTRICTED_SERVICES )
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
options = controller.GetOptions()
2015-05-13 20:22:39 +00:00
2015-03-04 22:44:32 +00:00
do_notify = False
for service in services:
service_key = service.GetServiceKey()
service_type = service.GetServiceType()
account = service.GetInfo( 'account' )
credentials = service.GetCredentials()
if service_type in HC.REPOSITORIES:
2015-05-13 20:22:39 +00:00
if options[ 'pause_repo_sync' ]: continue
2015-03-04 22:44:32 +00:00
info = service.GetInfo()
if info[ 'paused' ]: continue
if account.IsStale() and credentials.HasAccessKey() and not service.HasRecentError():
try:
response = service.Request( HC.GET, 'account' )
account = response[ 'account' ]
account.MakeFresh()
2015-11-04 22:30:28 +00:00
controller.WriteSynchronous( 'service_updates', { service_key : [ HydrusData.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, account ) ] } )
2015-03-04 22:44:32 +00:00
do_notify = True
2016-03-16 22:19:14 +00:00
except HydrusExceptions.NetworkException as e:
HydrusData.Print( 'Failed to refresh account for ' + service.GetName() + ':' )
HydrusData.Print( e )
except Exception:
2015-03-04 22:44:32 +00:00
2015-11-18 22:44:07 +00:00
HydrusData.Print( 'Failed to refresh account for ' + service.GetName() + ':' )
2015-03-04 22:44:32 +00:00
2015-11-18 22:44:07 +00:00
HydrusData.Print( traceback.format_exc() )
2015-03-04 22:44:32 +00:00
2015-10-21 21:53:10 +00:00
if do_notify:
2015-11-04 22:30:28 +00:00
controller.pub( 'notify_new_permissions' )
2015-10-21 21:53:10 +00:00
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
def DAEMONSynchroniseRepositories( controller ):
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
options = controller.GetOptions()
2015-05-13 20:22:39 +00:00
if not options[ 'pause_repo_sync' ]:
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
services = controller.GetServicesManager().GetServices( HC.REPOSITORIES )
2015-07-15 20:28:26 +00:00
2015-03-04 22:44:32 +00:00
for service in services:
2015-10-07 21:56:22 +00:00
if options[ 'pause_repo_sync' ]:
break
2015-11-04 22:30:28 +00:00
if controller.CurrentlyIdle():
2015-08-26 21:18:39 +00:00
service.Sync( only_when_idle = True )
2015-03-04 22:44:32 +00:00
time.sleep( 5 )
2015-11-04 22:30:28 +00:00
def DAEMONSynchroniseSubscriptions( controller ):
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
options = controller.GetOptions()
2015-05-13 20:22:39 +00:00
2015-11-04 22:30:28 +00:00
subscription_names = controller.Read( 'serialisable_names', HydrusSerialisable.SERIALISABLE_TYPE_SUBSCRIPTION )
2015-10-07 21:56:22 +00:00
for name in subscription_names:
2015-03-04 22:44:32 +00:00
2015-10-07 21:56:22 +00:00
p1 = options[ 'pause_subs_sync' ]
2015-11-04 22:30:28 +00:00
p2 = controller.ViewIsShutdown()
2015-03-04 22:44:32 +00:00
2015-10-07 21:56:22 +00:00
if p1 or p2:
2015-03-04 22:44:32 +00:00
2015-10-07 21:56:22 +00:00
return
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
subscription = controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_SUBSCRIPTION, name )
2015-10-07 21:56:22 +00:00
subscription.Sync()
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
def DAEMONUPnP( controller ):
2015-03-04 22:44:32 +00:00
try:
local_ip = HydrusNATPunch.GetLocalIP()
current_mappings = HydrusNATPunch.GetUPnPMappings()
our_mappings = { ( internal_client, internal_port ) : external_port for ( description, internal_client, internal_port, external_ip_address, external_port, protocol, enabled ) in current_mappings }
2016-03-30 22:56:50 +00:00
except:
return # This IGD probably doesn't support UPnP, so don't spam the user with errors they can't fix!
2015-03-04 22:44:32 +00:00
2015-11-04 22:30:28 +00:00
services = controller.GetServicesManager().GetServices( ( HC.LOCAL_BOORU, ) )
2015-03-04 22:44:32 +00:00
for service in services:
info = service.GetInfo()
internal_port = info[ 'port' ]
upnp = info[ 'upnp' ]
if ( local_ip, internal_port ) in our_mappings:
current_external_port = our_mappings[ ( local_ip, internal_port ) ]
if upnp is None or current_external_port != upnp: HydrusNATPunch.RemoveUPnPMapping( current_external_port, 'TCP' )
for service in services:
info = service.GetInfo()
internal_port = info[ 'port' ]
upnp = info[ 'upnp' ]
if upnp is not None:
if ( local_ip, internal_port ) not in our_mappings:
service_type = service.GetServiceType()
external_port = upnp
protocol = 'TCP'
description = HC.service_string_lookup[ service_type ] + ' at ' + local_ip + ':' + str( internal_port )
duration = 3600
HydrusNATPunch.AddUPnPMapping( local_ip, internal_port, external_port, protocol, description, duration = duration )