hydrus/include/ClientDaemons.py

386 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
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 HydrusEncryption
import HydrusExceptions
import HydrusFileHandling
import HydrusImageHandling
import HydrusNATPunch
import HydrusServer
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-03-25 22:04:19 +00:00
import HydrusGlobals
2015-03-04 22:44:32 +00:00
def DAEMONCheckExportFolders():
2015-09-16 18:11:00 +00:00
options = HydrusGlobals.client_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-10-21 21:53:10 +00:00
export_folders = HydrusGlobals.client_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
def DAEMONCheckImportFolders():
2015-09-16 18:11:00 +00:00
options = HydrusGlobals.client_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-10-21 21:53:10 +00:00
import_folders = HydrusGlobals.client_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
def DAEMONDownloadFiles():
2015-09-16 18:11:00 +00:00
hashes = HydrusGlobals.client_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
2015-07-22 19:40:39 +00:00
successful_hashes = set()
2015-03-04 22:44:32 +00:00
2015-09-16 18:11:00 +00:00
job_key = HydrusThreading.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-09-16 18:11:00 +00:00
HydrusGlobals.client_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' )
2015-09-16 18:11:00 +00:00
( media_result, ) = HydrusGlobals.client_controller.Read( 'media_results', CC.COMBINED_FILE_SERVICE_KEY, ( 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
2015-09-16 18:11:00 +00:00
try: file_repository = HydrusGlobals.client_controller.GetServicesManager().GetService( service_key )
2015-07-22 19:40:39 +00:00
except HydrusExceptions.NotFoundException: continue
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-07-22 19:40:39 +00:00
( os_file_handle, temp_path ) = HydrusFileHandling.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-09-16 18:11:00 +00:00
HydrusGlobals.client_controller.WaitUntilPubSubsEmpty()
2015-07-22 19:40:39 +00:00
2015-09-16 18:11:00 +00:00
HydrusGlobals.client_controller.WriteSynchronous( 'import_file', temp_path, override_deleted = True )
2015-07-22 19:40:39 +00:00
successful_hashes.add( hash )
break
finally:
HydrusFileHandling.CleanUpTempPath( os_file_handle, temp_path )
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-09-16 18:11:00 +00:00
HydrusGlobals.client_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
def DAEMONFlushServiceUpdates( list_of_service_keys_to_service_updates ):
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-09-16 18:11:00 +00:00
HydrusGlobals.client_controller.WriteSynchronous( 'service_updates', service_keys_to_service_updates )
2015-03-04 22:44:32 +00:00
2015-07-15 20:28:26 +00:00
def DAEMONMaintainTrash():
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-09-16 18:11:00 +00:00
service_info = HydrusGlobals.client_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
2015-09-16 18:11:00 +00:00
hashes = HydrusGlobals.client_controller.Read( 'oldest_trash_hashes' )
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-09-16 18:11:00 +00:00
HydrusGlobals.client_controller.WaitUntilPubSubsEmpty()
2015-07-15 20:28:26 +00:00
2015-09-16 18:11:00 +00:00
HydrusGlobals.client_controller.WriteSynchronous( 'content_updates', service_keys_to_content_updates )
2015-07-15 20:28:26 +00:00
2015-09-16 18:11:00 +00:00
service_info = HydrusGlobals.client_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
2015-09-16 18:11:00 +00:00
hashes = HydrusGlobals.client_controller.Read( 'oldest_trash_hashes', 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-09-16 18:11:00 +00:00
HydrusGlobals.client_controller.WaitUntilPubSubsEmpty()
2015-07-15 20:28:26 +00:00
2015-09-16 18:11:00 +00:00
HydrusGlobals.client_controller.WriteSynchronous( 'content_updates', service_keys_to_content_updates )
2015-07-15 20:28:26 +00:00
2015-09-16 18:11:00 +00:00
hashes = HydrusGlobals.client_controller.Read( 'oldest_trash_hashes', minimum_age = max_age )
2015-07-15 20:28:26 +00:00
2015-03-04 22:44:32 +00:00
def DAEMONSynchroniseAccounts():
2015-09-16 18:11:00 +00:00
services = HydrusGlobals.client_controller.GetServicesManager().GetServices( HC.RESTRICTED_SERVICES )
2015-03-04 22:44:32 +00:00
2015-09-16 18:11:00 +00:00
options = HydrusGlobals.client_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-09-16 18:11:00 +00:00
HydrusGlobals.client_controller.WriteSynchronous( 'service_updates', { service_key : [ HydrusData.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, account ) ] } )
2015-03-04 22:44:32 +00:00
do_notify = True
except Exception as e:
print( 'Failed to refresh account for ' + service.GetName() + ':' )
print( traceback.format_exc() )
2015-10-21 21:53:10 +00:00
if do_notify:
HydrusGlobals.client_controller.pub( 'notify_new_permissions' )
2015-03-04 22:44:32 +00:00
def DAEMONSynchroniseRepositories():
2015-09-16 18:11:00 +00:00
options = HydrusGlobals.client_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-09-16 18:11:00 +00:00
services = HydrusGlobals.client_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-09-16 18:11:00 +00:00
if HydrusGlobals.client_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 )
def DAEMONSynchroniseSubscriptions():
2015-09-16 18:11:00 +00:00
options = HydrusGlobals.client_controller.GetOptions()
2015-05-13 20:22:39 +00:00
2015-10-21 21:53:10 +00:00
subscription_names = HydrusGlobals.client_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' ]
p2 = HydrusGlobals.view_shutdown
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-10-21 21:53:10 +00:00
subscription = HydrusGlobals.client_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
def DAEMONUPnP():
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 }
except: return # This IGD probably doesn't support UPnP, so don't spam the user with errors they can't fix!
2015-09-16 18:11:00 +00:00
services = HydrusGlobals.client_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 )