Version 87
This commit is contained in:
parent
90b2f8fa26
commit
756e6ad6d1
|
@ -18,7 +18,7 @@ import sys
|
|||
from include import HydrusConstants as HC
|
||||
from include import ClientController
|
||||
import threading
|
||||
#from twisted.internet import reactor
|
||||
from twisted.internet import reactor
|
||||
|
||||
initial_sys_stdout = sys.stdout
|
||||
initial_sys_stderr = sys.stderr
|
||||
|
@ -30,7 +30,7 @@ with open( HC.LOGS_DIR + os.path.sep + 'client.log', 'a' ) as f:
|
|||
|
||||
try:
|
||||
|
||||
#threading.Thread( target = reactor.run, kwargs = { 'installSignalHandlers' : 0 } ).start()
|
||||
threading.Thread( target = reactor.run, kwargs = { 'installSignalHandlers' : 0 } ).start()
|
||||
|
||||
app = ClientController.Controller()
|
||||
|
||||
|
@ -47,6 +47,6 @@ sys.stderr = initial_sys_stderr
|
|||
|
||||
HC.shutdown = True
|
||||
|
||||
#reactor.callFromThread( reactor.stop )
|
||||
reactor.callFromThread( reactor.stop )
|
||||
|
||||
HC.pubsub.pubimmediate( 'shutdown' )
|
||||
|
|
|
@ -8,6 +8,50 @@
|
|||
<div class="content">
|
||||
<h3>changelog</h3>
|
||||
<ul>
|
||||
<li><h3>version 87</h3></li>
|
||||
<ul>
|
||||
<li>misc:</li>
|
||||
<li><ul>
|
||||
<li>fixed system:untagged, which was doing numtags>0 by accident</li>
|
||||
</ul></li>
|
||||
<li>basics:</li>
|
||||
<li><ul>
|
||||
<li>moved client local service to twisted</li>
|
||||
<li>moved server to twisted</li>
|
||||
<li>cleaned up a whole lot of unrelated server stuff I haven't touched in a while</li>
|
||||
<li>fixed some misc typos</li>
|
||||
</ul></li>
|
||||
<li>details:</li>
|
||||
<li><ul>
|
||||
<li>built twisted server framework to plug into hydrus</li>
|
||||
<li>changed hydrus authorisation header</li>
|
||||
<li>changed sessions to manage accounts, reducing server db load</li>
|
||||
<li>reworked session cookie to be neater</li>
|
||||
<li>cleaned up a bunch of server code</li>
|
||||
<li>fixed how certain server errors were being printed to the log</li>
|
||||
<li>reworked response_context to a body/path dichotomy to reduce cpu+memory on file requests</li>
|
||||
<li>collapsed a bunch of GET POST requests to the same path</li>
|
||||
<li>reworked server_service_identifiers to be port-independant</li>
|
||||
<li>improved data use logging to support new session management system</li>
|
||||
<li>moved session management to new system</li>
|
||||
<li>moved error management to new system</li>
|
||||
<li>integrated twisted thread into hydrus controller</li>
|
||||
<li>reworked root and favicon</li>
|
||||
<li>reworked local file and thumbnail requests</li>
|
||||
<li>reworked restricted service requests</li>
|
||||
<li>reworked admin service requests</li>
|
||||
<li>reworked repository service requests</li>
|
||||
<li>removed manage options query; it'll be rolled into manage services admin queries</li>
|
||||
<li>updated serverdb to manage with new system, harmonising internal and external requests to one workflow</li>
|
||||
<li>made server-side data use tracking simpler</li>
|
||||
<li>added Content-Type header to most requests</li>
|
||||
<li>improved how key registration, init, and account GET requests are handled client-side</li>
|
||||
<li>harmonised how account_keys are created server-side</li>
|
||||
<li>moved server management from serverdb to servercontroller, with better pubsub restart</li>
|
||||
<li>moved several useful functions to the new serverconstants.py</li>
|
||||
<li>fixed a max_age sessions issue</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<li><h3>version 86</h3></li>
|
||||
<ul>
|
||||
<li>timeout on connections improved</li>
|
||||
|
|
|
@ -1160,7 +1160,7 @@ class ConnectionToService():
|
|||
|
||||
access_key = self._credentials.GetAccessKey()
|
||||
|
||||
if access_key != '': headers[ 'Authorization' ] = 'hydrus_network ' + access_key.encode( 'hex' )
|
||||
if access_key != '': headers[ 'Hydrus-Key' ] = access_key.encode( 'hex' )
|
||||
|
||||
else: raise Exception( 'No access key!' )
|
||||
|
||||
|
@ -1178,6 +1178,8 @@ class ConnectionToService():
|
|||
|
||||
# prepare
|
||||
|
||||
headers = self._GetHeaders( request )
|
||||
|
||||
if request_type == HC.GET:
|
||||
|
||||
request_type_string = 'GET'
|
||||
|
@ -1232,11 +1234,21 @@ class ConnectionToService():
|
|||
|
||||
request_string = '/' + request
|
||||
|
||||
if request == 'file': body = request_args[ 'file' ]
|
||||
else: body = yaml.safe_dump( request_args )
|
||||
if request == 'file':
|
||||
|
||||
content_type = HC.APPLICATION_OCTET_STREAM
|
||||
|
||||
body = request_args[ 'file' ]
|
||||
|
||||
else:
|
||||
|
||||
content_type = HC.APPLICATION_YAML
|
||||
|
||||
body = yaml.safe_dump( request_args )
|
||||
|
||||
|
||||
headers[ 'Content-Type' ] = HC.mime_string_lookup[ content_type ]
|
||||
|
||||
|
||||
headers = self._GetHeaders( request )
|
||||
|
||||
# send
|
||||
|
||||
|
@ -1261,54 +1273,7 @@ class ConnectionToService():
|
|||
except: pass
|
||||
|
||||
|
||||
def Get( self, request, **kwargs ):
|
||||
|
||||
response = self._SendRequest( HC.GET, request, kwargs )
|
||||
|
||||
if request in ( 'registration_keys', 'init' ):
|
||||
|
||||
if request == 'registration_keys':
|
||||
|
||||
body = os.linesep.join( [ 'r' + key.encode( 'hex' ) for key in response ] )
|
||||
|
||||
filename = 'registration keys.txt'
|
||||
|
||||
elif request == 'init':
|
||||
|
||||
filename = 'admin access key.txt'
|
||||
|
||||
access_key = response
|
||||
|
||||
body = access_key.encode( 'hex' )
|
||||
|
||||
( host, port ) = self._credentials.GetAddress()
|
||||
|
||||
self._credentials = Credentials( host, port, access_key )
|
||||
|
||||
edit_log = [ ( 'edit', ( self._service_identifier, ( self._service_identifier, self._credentials, None ) ) ) ]
|
||||
|
||||
HC.app.Write( 'update_services', edit_log )
|
||||
|
||||
|
||||
with wx.FileDialog( None, style=wx.FD_SAVE, defaultFile = filename ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
with open( dlg.GetPath(), 'wb' ) as f: f.write( body )
|
||||
|
||||
|
||||
|
||||
elif request == 'account':
|
||||
|
||||
account = response
|
||||
|
||||
account.MakeFresh()
|
||||
|
||||
HC.app.Write( 'service_updates', { self._service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, account ) ] } )
|
||||
|
||||
|
||||
return response
|
||||
|
||||
def Get( self, request, **kwargs ): return self._SendRequest( HC.GET, request, kwargs )
|
||||
|
||||
def GetCookies( self ): return self._connection.GetCookies()
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import time
|
|||
import traceback
|
||||
import wx
|
||||
import wx.richtext
|
||||
#from twisted.internet import reactor
|
||||
from twisted.internet import reactor
|
||||
|
||||
ID_ANIMATED_EVENT_TIMER = wx.NewId()
|
||||
ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
|
||||
|
@ -210,7 +210,8 @@ class Controller( wx.App ):
|
|||
|
||||
except HydrusExceptions.DBAccessException as e:
|
||||
|
||||
print( repr( HC.u( e ) ) )
|
||||
try: print( HC.u( e ) )
|
||||
except: print( repr( HC.u( e ) ) )
|
||||
|
||||
message = 'This instance of the client had a problem connecting to the database, which probably means an old instance is still closing.'
|
||||
message += os.linesep + os.linesep
|
||||
|
@ -324,55 +325,7 @@ class Controller( wx.App ):
|
|||
|
||||
def RestartServer( self ):
|
||||
|
||||
def do_it():
|
||||
|
||||
# stick it on a thread because the connection test stuff blocks
|
||||
|
||||
if self._server is not None: self._server.shutdown()
|
||||
|
||||
port = HC.options[ 'local_port' ]
|
||||
|
||||
time.sleep( 1 )
|
||||
|
||||
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
|
||||
|
||||
try:
|
||||
|
||||
connection.connect()
|
||||
connection.close()
|
||||
|
||||
message = 'Something was already bound to port ' + HC.u( port )
|
||||
|
||||
wx.CallAfter( HC.pubsub.pub, 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, message ) )
|
||||
|
||||
except:
|
||||
|
||||
local_file_server_service_identifier = HC.ServerServiceIdentifier( HC.LOCAL_FILE, port )
|
||||
|
||||
self._server = HydrusServer.HydrusHTTPServer( local_file_server_service_identifier )
|
||||
|
||||
server_thread = threading.Thread( target=self._server.serve_forever )
|
||||
server_thread.start()
|
||||
|
||||
time.sleep( 1 )
|
||||
|
||||
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
|
||||
|
||||
try:
|
||||
|
||||
connection.connect()
|
||||
connection.close()
|
||||
|
||||
except:
|
||||
|
||||
message = 'Tried to bind port ' + HC.u( port ) + ' but it failed'
|
||||
|
||||
wx.CallAfter( HC.pubsub.pub, 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, message ) )
|
||||
|
||||
|
||||
|
||||
|
||||
threading.Thread( target = do_it ).start()
|
||||
port = HC.options[ 'local_port' ]
|
||||
|
||||
def TWISTEDRestartServer():
|
||||
|
||||
|
@ -380,13 +333,42 @@ class Controller( wx.App ):
|
|||
|
||||
try:
|
||||
|
||||
local_file_server_service_identifier = HC.ServerServiceIdentifier( HC.LOCAL_FILE, 1050 )
|
||||
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
|
||||
|
||||
self._local_service = reactor.listenTCP( 1050, HydrusServer.HydrusServiceLocal( local_file_server_service_identifier, 'hello' ) )
|
||||
try:
|
||||
|
||||
connection.connect()
|
||||
connection.close()
|
||||
|
||||
message = 'Something was already bound to port ' + HC.u( port )
|
||||
|
||||
wx.CallAfter( HC.pubsub.pub, 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, message ) )
|
||||
|
||||
except:
|
||||
|
||||
local_file_server_service_identifier = HC.ServerServiceIdentifier( 'local file', HC.LOCAL_FILE )
|
||||
|
||||
self._local_service = reactor.listenTCP( port, HydrusServer.HydrusServiceLocal( local_file_server_service_identifier, 'hello' ) )
|
||||
|
||||
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
|
||||
|
||||
try:
|
||||
|
||||
connection.connect()
|
||||
connection.close()
|
||||
|
||||
except:
|
||||
|
||||
message = 'Tried to bind port ' + HC.u( port ) + ' but it failed'
|
||||
|
||||
wx.CallAfter( HC.pubsub.pub, 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, message ) )
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
|
||||
wx.CallAfter( HC.ShowException, e )
|
||||
|
||||
except Exception as e: HC.ShowException( e )
|
||||
|
||||
# handle problems
|
||||
|
||||
|
||||
if self._local_service is None: StartServer()
|
||||
|
@ -398,7 +380,7 @@ class Controller( wx.App ):
|
|||
|
||||
|
||||
|
||||
#reactor.callFromThread( TWISTEDRestartServer )
|
||||
reactor.callFromThread( TWISTEDRestartServer )
|
||||
|
||||
|
||||
def SetSplashText( self, text ):
|
||||
|
|
|
@ -1892,7 +1892,10 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
|
|||
|
||||
if num_tags_zero or num_tags_nonzero:
|
||||
|
||||
query_hash_ids = { id for ( id, ) in c.execute( 'SELECT hash_id FROM mappings WHERE service_id = ? AND hash_id IN ' + HC.SplayListForDB( query_hash_ids ) + ' AND status IN ' + HC.SplayListForDB( statuses ) + ';', ( tag_service_id, ) ) }
|
||||
tag_query_hash_ids = { id for ( id, ) in c.execute( 'SELECT hash_id FROM mappings WHERE service_id = ? AND hash_id IN ' + HC.SplayListForDB( query_hash_ids ) + ' AND status IN ' + HC.SplayListForDB( statuses ) + ';', ( tag_service_id, ) ) }
|
||||
|
||||
if num_tags_zero: query_hash_ids.difference_update( tag_query_hash_ids )
|
||||
elif num_tags_nonzero: query_hash_ids = tag_query_hash_ids
|
||||
|
||||
|
||||
if len( tag_predicates ) > 0:
|
||||
|
@ -4079,33 +4082,25 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
|
|||
|
||||
if action == HC.ADD:
|
||||
|
||||
server_service_identifier = data
|
||||
( service_type, port ) = data
|
||||
|
||||
service_key = os.urandom( 32 )
|
||||
|
||||
service_type = server_service_identifier.GetType()
|
||||
|
||||
service_port = server_service_identifier.GetPort()
|
||||
port = server_service_identifier.GetPort()
|
||||
|
||||
service_name = HC.service_string_lookup[ service_type ] + ' at ' + host + ':' + HC.u( service_port )
|
||||
service_name = HC.service_string_lookup[ service_type ] + ' at ' + host + ':' + HC.u( port )
|
||||
|
||||
client_service_identifier = HC.ClientServiceIdentifier( service_key, service_type, service_name )
|
||||
|
||||
credentials = CC.Credentials( host, service_port, access_key )
|
||||
credentials = CC.Credentials( host, port, access_key )
|
||||
|
||||
if service_type == HC.MESSAGE_DEPOT: extra_info = ( 'identity@' + service_name, 180, HydrusEncryption.GenerateNewPrivateKey(), True )
|
||||
else: extra_info = None
|
||||
|
||||
self._AddService( c, client_service_identifier, credentials, extra_info )
|
||||
|
||||
elif action == HC.EDIT:
|
||||
|
||||
( server_service_identifier, new_port ) = data
|
||||
|
||||
current_port = server_service_identifier.GetPort()
|
||||
|
||||
c.execute( 'UPDATE addresses SET port = ? WHERE host = ? AND port = ?;', ( new_port, host, current_port ) )
|
||||
|
||||
elif action == HC.DELETE:
|
||||
|
||||
server_service_identifier = data
|
||||
|
@ -6473,61 +6468,63 @@ class DB( ServiceDB ):
|
|||
|
||||
def ProcessWrite( action, args, kwargs ):
|
||||
|
||||
if action == '4chan_pass': self._Set4chanPass( c, *args, **kwargs )
|
||||
elif action == 'add_downloads': self._AddDownloads( c, *args, **kwargs )
|
||||
elif action == 'add_uploads': self._AddUploads( c, *args, **kwargs )
|
||||
elif action == 'archive_conversation': self._ArchiveConversation( c, *args, **kwargs )
|
||||
elif action == 'contact_associated': self._AssociateContact( c, *args, **kwargs )
|
||||
elif action == 'content_updates': self._ProcessContentUpdates( c, *args, **kwargs )
|
||||
elif action == 'copy_files': self._CopyFiles( c, *args, **kwargs )
|
||||
elif action == 'delete_conversation': self._DeleteConversation( c, *args, **kwargs )
|
||||
elif action == 'delete_draft': self._DeleteDraft( c, *args, **kwargs )
|
||||
elif action == 'delete_orphans': self._DeleteOrphans( c, *args, **kwargs )
|
||||
elif action == 'delete_pending': self._DeletePending( c, *args, **kwargs )
|
||||
elif action == 'delete_hydrus_session_key': self._DeleteHydrusSessionKey( c, *args, **kwargs )
|
||||
elif action == 'draft_message': self._DraftMessage( c, *args, **kwargs )
|
||||
elif action == 'fatten_autocomplete_cache': self._FattenAutocompleteCache( c, *args, **kwargs )
|
||||
elif action == 'favourite_custom_filter_actions': self._SetFavouriteCustomFilterActions( c, *args, **kwargs )
|
||||
elif action == 'flush_message_statuses': self._FlushMessageStatuses( c, *args, **kwargs )
|
||||
elif action == 'generate_tag_ids': self._GenerateTagIdsEfficiently( c, *args, **kwargs )
|
||||
if action == '4chan_pass': result = self._Set4chanPass( c, *args, **kwargs )
|
||||
elif action == 'add_downloads': result = self._AddDownloads( c, *args, **kwargs )
|
||||
elif action == 'add_uploads': result = self._AddUploads( c, *args, **kwargs )
|
||||
elif action == 'archive_conversation': result = self._ArchiveConversation( c, *args, **kwargs )
|
||||
elif action == 'contact_associated': result = self._AssociateContact( c, *args, **kwargs )
|
||||
elif action == 'content_updates': result = self._ProcessContentUpdates( c, *args, **kwargs )
|
||||
elif action == 'copy_files': result = self._CopyFiles( c, *args, **kwargs )
|
||||
elif action == 'delete_conversation': result = self._DeleteConversation( c, *args, **kwargs )
|
||||
elif action == 'delete_draft': result = self._DeleteDraft( c, *args, **kwargs )
|
||||
elif action == 'delete_orphans': result = self._DeleteOrphans( c, *args, **kwargs )
|
||||
elif action == 'delete_pending': result = self._DeletePending( c, *args, **kwargs )
|
||||
elif action == 'delete_hydrus_session_key': result = self._DeleteHydrusSessionKey( c, *args, **kwargs )
|
||||
elif action == 'draft_message': result = self._DraftMessage( c, *args, **kwargs )
|
||||
elif action == 'fatten_autocomplete_cache': result = self._FattenAutocompleteCache( c, *args, **kwargs )
|
||||
elif action == 'favourite_custom_filter_actions': result = self._SetFavouriteCustomFilterActions( c, *args, **kwargs )
|
||||
elif action == 'flush_message_statuses': result = self._FlushMessageStatuses( c, *args, **kwargs )
|
||||
elif action == 'generate_tag_ids': result = self._GenerateTagIdsEfficiently( c, *args, **kwargs )
|
||||
elif action == 'hydrus_session': result = self._AddHydrusSession( c, *args, **kwargs )
|
||||
elif action == 'import_file': return self._ImportFile( c, *args, **kwargs )
|
||||
elif action == 'import_file_from_page': self._ImportFilePage( c, *args, **kwargs )
|
||||
elif action == 'import_folder': self._UpdateImportFolder( c, *args, **kwargs )
|
||||
elif action == 'import_folders': self._SetImportFolders( c, *args, **kwargs )
|
||||
elif action == 'inbox_conversation': self._InboxConversation( c, *args, **kwargs )
|
||||
elif action == 'message': self._AddMessage( c, *args, **kwargs )
|
||||
elif action == 'message_info_since': self._AddMessageInfoSince( c, *args, **kwargs )
|
||||
elif action == 'message_statuses': self._UpdateMessageStatuses( c, *args, **kwargs )
|
||||
elif action == 'pixiv_account': self._SetPixivAccount( c, *args, **kwargs )
|
||||
elif action == 'reset_service': self._ResetService( c, *args, **kwargs )
|
||||
elif action == 'save_options': self._SaveOptions( c, *args, **kwargs )
|
||||
elif action == 'service_updates': self._ProcessServiceUpdates( c, *args, **kwargs )
|
||||
elif action == 'session': self._AddSession( c, *args, **kwargs )
|
||||
elif action == 'set_password': self._SetPassword( c, *args, **kwargs )
|
||||
elif action == 'set_tag_service_precedence': self._SetTagServicePrecedence( c, *args, **kwargs )
|
||||
elif action == 'subscription': self._SetSubscription( c, *args, **kwargs )
|
||||
elif action == 'subscriptions': self._SetSubscriptions( c, *args, **kwargs )
|
||||
elif action == 'tag_parents': self._UpdateTagParents( c, *args, **kwargs )
|
||||
elif action == 'tag_siblings': self._UpdateTagSiblings( c, *args, **kwargs )
|
||||
elif action == 'thumbnails': self._AddThumbnails( c, *args, **kwargs )
|
||||
elif action == 'update': self._AddUpdate( c, *args, **kwargs )
|
||||
elif action == 'update_boorus': self._UpdateBoorus( c, *args, **kwargs )
|
||||
elif action == 'update_contacts': self._UpdateContacts( c, *args, **kwargs )
|
||||
elif action == 'update_imageboards': self._UpdateImageboards( c, *args, **kwargs )
|
||||
elif action == 'update_server_services': self._UpdateServerServices( c, *args, **kwargs )
|
||||
elif action == 'update_services': self._UpdateServices( c, *args, **kwargs )
|
||||
elif action == 'vacuum': self._Vacuum()
|
||||
elif action == 'import_file': result = self._ImportFile( c, *args, **kwargs )
|
||||
elif action == 'import_file_from_page': result = self._ImportFilePage( c, *args, **kwargs )
|
||||
elif action == 'import_folder': result = self._UpdateImportFolder( c, *args, **kwargs )
|
||||
elif action == 'import_folders': result = self._SetImportFolders( c, *args, **kwargs )
|
||||
elif action == 'inbox_conversation': result = self._InboxConversation( c, *args, **kwargs )
|
||||
elif action == 'message': result = self._AddMessage( c, *args, **kwargs )
|
||||
elif action == 'message_info_since': result = self._AddMessageInfoSince( c, *args, **kwargs )
|
||||
elif action == 'message_statuses': result = self._UpdateMessageStatuses( c, *args, **kwargs )
|
||||
elif action == 'pixiv_account': result = self._SetPixivAccount( c, *args, **kwargs )
|
||||
elif action == 'reset_service': result = self._ResetService( c, *args, **kwargs )
|
||||
elif action == 'save_options': result = self._SaveOptions( c, *args, **kwargs )
|
||||
elif action == 'service_updates': result = self._ProcessServiceUpdates( c, *args, **kwargs )
|
||||
elif action == 'session': result = self._AddSession( c, *args, **kwargs )
|
||||
elif action == 'set_password': result = self._SetPassword( c, *args, **kwargs )
|
||||
elif action == 'set_tag_service_precedence': result = self._SetTagServicePrecedence( c, *args, **kwargs )
|
||||
elif action == 'subscription': result = self._SetSubscription( c, *args, **kwargs )
|
||||
elif action == 'subscriptions': result = self._SetSubscriptions( c, *args, **kwargs )
|
||||
elif action == 'tag_parents': result = self._UpdateTagParents( c, *args, **kwargs )
|
||||
elif action == 'tag_siblings': result = self._UpdateTagSiblings( c, *args, **kwargs )
|
||||
elif action == 'thumbnails': result = self._AddThumbnails( c, *args, **kwargs )
|
||||
elif action == 'update': result = self._AddUpdate( c, *args, **kwargs )
|
||||
elif action == 'update_boorus': result = self._UpdateBoorus( c, *args, **kwargs )
|
||||
elif action == 'update_contacts': result = self._UpdateContacts( c, *args, **kwargs )
|
||||
elif action == 'update_imageboards': result = self._UpdateImageboards( c, *args, **kwargs )
|
||||
elif action == 'update_server_services': result = self._UpdateServerServices( c, *args, **kwargs )
|
||||
elif action == 'update_services': result = self._UpdateServices( c, *args, **kwargs )
|
||||
elif action == 'vacuum': result = self._Vacuum()
|
||||
elif action == 'web_session': result = self._AddWebSession( c, *args, **kwargs )
|
||||
else: raise Exception( 'db received an unknown write command: ' + action )
|
||||
|
||||
return result
|
||||
|
||||
|
||||
HC.pubsub.pub( 'db_locked_status', 'db locked' )
|
||||
|
||||
action = job.GetAction()
|
||||
|
||||
job_type = job.GetType()
|
||||
|
||||
action = job.GetAction()
|
||||
|
||||
args = job.GetArgs()
|
||||
|
||||
kwargs = job.GetKWArgs()
|
||||
|
@ -6864,7 +6861,12 @@ def DAEMONDownloadThumbnails():
|
|||
|
||||
thumbnails = []
|
||||
|
||||
for hash in thumbnail_hashes_i_need[ i : i + num_per_round ]: thumbnails.append( ( hash, connection.Get( 'thumbnail', hash = hash.encode( 'hex' ) ) ) )
|
||||
for hash in thumbnail_hashes_i_need[ i : i + num_per_round ]:
|
||||
|
||||
thumbnail = connection.Get( 'thumbnail', hash = hash.encode( 'hex' ) )
|
||||
|
||||
thumbnails.append( ( hash, thumbnail ) )
|
||||
|
||||
|
||||
HC.app.WaitUntilGoodTimeToUseGUIThread()
|
||||
|
||||
|
@ -6958,12 +6960,20 @@ def DAEMONSynchroniseAccounts():
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
connection.Get( 'account' )
|
||||
response = connection.Get( 'account' )
|
||||
|
||||
account = response[ 'account' ]
|
||||
|
||||
account.MakeFresh()
|
||||
|
||||
HC.app.Write( 'service_updates', { service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, account ) ] } )
|
||||
|
||||
do_notify = True
|
||||
|
||||
except Exception as e:
|
||||
|
||||
print( traceback.format_exc() )
|
||||
|
||||
name = service_identifier.GetName()
|
||||
|
||||
message = 'Failed to refresh account for ' + name + ':' + os.linesep + os.linesep + HC.u( e )
|
||||
|
|
|
@ -184,9 +184,9 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
content_updates = [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_ADD, content_update_row ) ]
|
||||
|
||||
service_identfiers_to_content_updates = { service_identifier : content_updates }
|
||||
service_identifiers_to_content_updates = { service_identifier : content_updates }
|
||||
|
||||
HC.app.Write( 'content_updates', service_identfiers_to_content_updates )
|
||||
HC.app.Write( 'content_updates', service_identifiers_to_content_updates )
|
||||
|
||||
except Exception as e:
|
||||
|
||||
|
@ -206,9 +206,9 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
content_updates = update.GetContentUpdates( for_client = True )
|
||||
|
||||
service_identfiers_to_content_updates = { service_identifier : content_updates }
|
||||
service_identifiers_to_content_updates = { service_identifier : content_updates }
|
||||
|
||||
HC.app.Write( 'content_updates', service_identfiers_to_content_updates )
|
||||
HC.app.Write( 'content_updates', service_identifiers_to_content_updates )
|
||||
|
||||
|
||||
elif service_type == HC.TAG_REPOSITORY:
|
||||
|
@ -237,9 +237,9 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
connection.Post( 'update', update = update )
|
||||
|
||||
service_identfiers_to_content_updates = { service_identifier : update.GetContentUpdates( for_client = True ) }
|
||||
service_identifiers_to_content_updates = { service_identifier : update.GetContentUpdates( for_client = True ) }
|
||||
|
||||
HC.app.Write( 'content_updates', service_identfiers_to_content_updates )
|
||||
HC.app.Write( 'content_updates', service_identifiers_to_content_updates )
|
||||
|
||||
|
||||
|
||||
|
@ -281,7 +281,9 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
account_info = connection.Get( 'account_info', subject_access_key = subject_access_key.encode( 'hex' ) )
|
||||
response = connection.Get( 'account_info', subject_access_key = subject_access_key.encode( 'hex' ) )
|
||||
|
||||
account_info = response[ 'account_info' ]
|
||||
|
||||
wx.MessageBox( HC.u( account_info ) )
|
||||
|
||||
|
@ -409,17 +411,36 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
connection.Get( 'init' )
|
||||
response = connection.Get( 'init' )
|
||||
|
||||
filename = 'admin access key.txt'
|
||||
|
||||
access_key = response[ 'access_key' ]
|
||||
|
||||
body = access_key.encode( 'hex' )
|
||||
|
||||
( host, port ) = service.GetCredentials().GetAddress()
|
||||
|
||||
credentials = Credentials( host, port, access_key )
|
||||
|
||||
edit_log = [ ( 'edit', ( self._service_identifier, ( self._service_identifier, credentials, None ) ) ) ]
|
||||
|
||||
HC.app.Write( 'update_services', edit_log )
|
||||
|
||||
with wx.FileDialog( None, style=wx.FD_SAVE, defaultFile = filename ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
with open( dlg.GetPath(), 'wb' ) as f: f.write( body )
|
||||
|
||||
|
||||
|
||||
edit_log = []
|
||||
|
||||
tag_service_identifier = HC.ServerServiceIdentifier( HC.TAG_REPOSITORY, HC.DEFAULT_SERVICE_PORT )
|
||||
file_service_identifier = HC.ServerServiceIdentifier( HC.FILE_REPOSITORY, HC.DEFAULT_SERVICE_PORT + 1 )
|
||||
edit_log.append( ( HC.ADD, ( HC.TAG_REPOSITORY, HC.DEFAULT_SERVICE_PORT ) ) )
|
||||
edit_log.append( ( HC.ADD, ( HC.FILE_REPOSITORY, HC.DEFAULT_SERVICE_PORT + 1 ) ) )
|
||||
|
||||
edit_log.append( ( HC.ADD, tag_service_identifier ) )
|
||||
edit_log.append( ( HC.ADD, file_service_identifier ) )
|
||||
|
||||
connection.Post( 'services_modification', edit_log = edit_log )
|
||||
connection.Post( 'services', edit_log = edit_log )
|
||||
|
||||
HC.app.Write( 'update_server_services', admin_service_identifier, edit_log )
|
||||
|
||||
|
@ -508,7 +529,9 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
stats = connection.Get( 'stats' )
|
||||
response = connection.Get( 'stats' )
|
||||
|
||||
stats = response[ 'stats' ]
|
||||
|
||||
wx.MessageBox( HC.u( stats ) )
|
||||
|
||||
|
@ -525,7 +548,10 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
with wx.BusyCursor(): ( ip, timestamp ) = connection.Get( 'ip', hash = hash.encode( 'hex' ) )
|
||||
with wx.BusyCursor(): response = connection.Get( 'ip', hash = hash.encode( 'hex' ) )
|
||||
|
||||
ip = response[ 'ip' ]
|
||||
timestamp = response[ 'timestamp' ]
|
||||
|
||||
message = 'File Hash: ' + hash.encode( 'hex' ) + os.linesep + 'Uploader\'s IP: ' + ip + os.linesep + 'Upload Time (GMT): ' + time.asctime( time.gmtime( int( timestamp ) ) )
|
||||
|
||||
|
@ -1498,8 +1524,6 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'modify_account', s_i ), p( '&Modify an Account' ), p( 'Modify a specific account\'s type and expiration.' ) )
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'account_info', s_i ), p( '&Get an Account\'s Info' ), p( 'Fetch information about an account from the tag repository.' ) )
|
||||
submenu.AppendSeparator()
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'options', s_i ), p( '&Options' ), p( 'Set the tag repository\'s options.' ) )
|
||||
submenu.AppendSeparator()
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'stats', s_i ), p( '&Get Stats' ), p( 'Fetch operating statistics from the tag repository.' ) )
|
||||
submenu.AppendSeparator()
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'post_news', s_i ), p( '&Post News' ), p( 'Post a news item to the tag repository.' ) )
|
||||
|
@ -1517,8 +1541,6 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'account_info', s_i ), p( '&Get an Account\'s Info' ), p( 'Fetch information about an account from the file repository.' ) )
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'fetch_ip', s_i ), p( '&Get an Uploader\'s IP Address' ), p( 'Fetch an uploader\'s ip address.' ) )
|
||||
submenu.AppendSeparator()
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'options', s_i ), p( '&Options' ), p( 'Set the file repository\'s options.' ) )
|
||||
submenu.AppendSeparator()
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'stats', s_i ), p( '&Get Stats' ), p( 'Fetch operating statistics from the file repository.' ) )
|
||||
submenu.AppendSeparator()
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'post_news', s_i ), p( '&Post News' ), p( 'Post a news item to the file repository.' ) )
|
||||
|
@ -1541,9 +1563,8 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
|
||||
submenu = wx.Menu()
|
||||
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'options', s_i ), p( '&Options' ), p( 'Set the server\'s options.' ) )
|
||||
submenu.AppendSeparator()
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'manage_server_services', s_i ), p( 'Manage &Services' ), p( 'Add, edit, and delete this server\'s services.' ) )
|
||||
menu_item = submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'manage_server_services', s_i ), p( 'Manage &Services' ), p( 'Add, edit, and delete this server\'s services.' ) )
|
||||
submenu.Enable( menu_item.GetId(), False )
|
||||
submenu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'backup_service', s_i ), p( 'Make a &Backup' ), p( 'Back up this server\'s database.' ) )
|
||||
|
||||
admin.AppendMenu( CC.ID_NULL, p( s_i.GetName() ), submenu )
|
||||
|
@ -1556,7 +1577,8 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
help.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'help' ), p( '&Help' ) )
|
||||
dont_know = wx.Menu()
|
||||
dont_know.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'auto_repo_setup' ), p( 'Just set up some repositories for me, please' ) )
|
||||
dont_know.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'auto_server_setup' ), p( 'Just set up the server on this computer, please' ) )
|
||||
menu_item = dont_know.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'auto_server_setup' ), p( 'Just set up the server on this computer, please' ) )
|
||||
dont_know.Enable( menu_item.GetId(), False )
|
||||
help.AppendMenu( wx.ID_NONE, p( 'I don\'t know what I am doing' ), dont_know )
|
||||
links = wx.Menu()
|
||||
tumblr = wx.MenuItem( links, CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'tumblr' ), p( 'Tumblr' ) )
|
||||
|
@ -2378,7 +2400,29 @@ class FrameReviewServices( ClientGUICommon.Frame ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
connection.Get( 'init' )
|
||||
response = connection.Get( 'init' )
|
||||
|
||||
access_key = response[ 'access_key' ]
|
||||
|
||||
body = access_key.encode( 'hex' )
|
||||
|
||||
( host, port ) = service.GetCredentials().GetAddress()
|
||||
|
||||
credentials = CC.Credentials( host, port, access_key )
|
||||
|
||||
edit_log = [ ( 'edit', ( self._service_identifier, ( self._service_identifier, credentials, None ) ) ) ]
|
||||
|
||||
HC.app.Write( 'update_services', edit_log )
|
||||
|
||||
filename = 'admin access key.txt'
|
||||
|
||||
with wx.FileDialog( None, style=wx.FD_SAVE, defaultFile = filename ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
with open( dlg.GetPath(), 'wb' ) as f: f.write( body )
|
||||
|
||||
|
||||
|
||||
|
||||
def EventServiceRefreshAccount( self, event ):
|
||||
|
@ -2387,7 +2431,13 @@ class FrameReviewServices( ClientGUICommon.Frame ):
|
|||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
connection.Get( 'account' )
|
||||
response = connection.Get( 'account' )
|
||||
|
||||
account = response[ 'account' ]
|
||||
|
||||
account.MakeFresh()
|
||||
|
||||
HC.app.Write( 'service_updates', { self._service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, account ) ] } )
|
||||
|
||||
|
||||
def EventServiceReset( self, event ):
|
||||
|
|
|
@ -1994,7 +1994,9 @@ class DialogInputNewAccounts( Dialog ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
account_types = connection.Get( 'account_types' )
|
||||
response = connection.Get( 'account_types' )
|
||||
|
||||
account_types = response[ 'account_types' ]
|
||||
|
||||
for account_type in account_types: self._account_types.Append( account_type.ConvertToString(), account_type )
|
||||
self._account_types.SetSelection( 0 ) # admin
|
||||
|
@ -2057,8 +2059,22 @@ class DialogInputNewAccounts( Dialog ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
if expiration is None: access_keys = connection.Get( 'registration_keys', num = num, title = title )
|
||||
else: access_keys = connection.Get( 'registration_keys', num = num, title = title, expiration = expiration )
|
||||
if expiration is None: response = connection.Get( 'registration_keys', num = num, title = title )
|
||||
else: response = connection.Get( 'registration_keys', num = num, title = title, expiration = expiration )
|
||||
|
||||
registration_keys = response[ 'registration_keys' ]
|
||||
|
||||
filename = 'registration keys.txt'
|
||||
|
||||
with wx.FileDialog( None, style=wx.FD_SAVE, defaultFile = filename ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
body = os.linesep.join( [ 'r' + key.encode( 'hex' ) for key in registration_keys ] )
|
||||
|
||||
with open( dlg.GetPath(), 'wb' ) as f: f.write( body )
|
||||
|
||||
|
||||
|
||||
finally: self.EndModal( wx.ID_OK )
|
||||
|
||||
|
@ -2582,7 +2598,9 @@ class DialogModifyAccounts( Dialog ):
|
|||
|
||||
( subject_identifier, ) = self._subject_identifiers
|
||||
|
||||
subject_string = connection.Get( 'account_info', subject_identifier = subject_identifier )
|
||||
response = connection.Get( 'account_info', subject_identifier = subject_identifier )
|
||||
|
||||
subject_string = HC.u( response[ 'account_info' ] )
|
||||
|
||||
else: subject_string = 'modifying ' + HC.ConvertIntToPrettyString( len( self._subject_identifiers ) ) + ' accounts'
|
||||
|
||||
|
@ -2590,7 +2608,9 @@ class DialogModifyAccounts( Dialog ):
|
|||
|
||||
#
|
||||
|
||||
account_types = connection.Get( 'account_types' )
|
||||
response = connection.Get( 'account_types' )
|
||||
|
||||
account_types = response[ 'account_types' ]
|
||||
|
||||
for account_type in account_types: self._account_types.Append( account_type.ConvertToString(), account_type )
|
||||
|
||||
|
@ -2682,13 +2702,17 @@ class DialogModifyAccounts( Dialog ):
|
|||
kwargs[ 'subject_identifiers' ] = list( self._subject_identifiers )
|
||||
kwargs[ 'action' ] = action
|
||||
|
||||
connection.Post( 'account_modification', **kwargs )
|
||||
connection.Post( 'account', **kwargs )
|
||||
|
||||
if len( self._subject_identifiers ) == 1:
|
||||
|
||||
( subject_identifier, ) = self._subject_identifiers
|
||||
|
||||
self._subject_text.SetLabel( HC.u( connection.Get( 'account_info', subject_identifier = subject_identifier ) ) )
|
||||
response = connection.Get( 'account_info', subject_identifier = subject_identifier )
|
||||
|
||||
account_info = response[ 'account_info' ]
|
||||
|
||||
self._subject_text.SetLabel( HC.u( account_info ) )
|
||||
|
||||
|
||||
if len( self._subject_identifiers ) > 1: wx.MessageBox( 'Done!' )
|
||||
|
@ -3550,9 +3574,11 @@ class DialogRegisterService( Dialog ):
|
|||
|
||||
headers = {}
|
||||
|
||||
headers[ 'Authorization' ] = 'hydrus_network ' + registration_key.encode( 'hex' )
|
||||
headers[ 'Hydrus-Key' ] = registration_key.encode( 'hex' )
|
||||
|
||||
access_key = connection.request( 'GET', '/access_key', headers = headers )
|
||||
response = connection.request( 'GET', '/access_key', headers = headers )
|
||||
|
||||
access_key = response[ 'access_key' ]
|
||||
|
||||
self._credentials = CC.Credentials( host, port, access_key )
|
||||
|
||||
|
|
|
@ -218,7 +218,9 @@ class DialogManageAccountTypes( ClientGUIDialogs.Dialog ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
account_types = connection.Get( 'account_types' )
|
||||
response = connection.Get( 'account_types' )
|
||||
|
||||
account_types = response[ 'account_types' ]
|
||||
|
||||
self._titles_to_account_types = {}
|
||||
|
||||
|
@ -394,7 +396,7 @@ class DialogManageAccountTypes( ClientGUIDialogs.Dialog ):
|
|||
|
||||
connection = service.GetConnection()
|
||||
|
||||
connection.Post( 'account_types_modification', edit_log = self._edit_log )
|
||||
connection.Post( 'account_types', edit_log = self._edit_log )
|
||||
|
||||
self.EndModal( wx.ID_OK )
|
||||
|
||||
|
@ -2453,7 +2455,9 @@ class DialogManageOptionsFileRepository( ClientGUIDialogs.Dialog ):
|
|||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
options = connection.Get( 'options' )
|
||||
response = connection.Get( 'options' )
|
||||
|
||||
options = response[ 'options' ]
|
||||
|
||||
self._max_monthly_data.SetValue( options[ 'max_monthly_data' ] )
|
||||
self._max_storage.SetValue( options[ 'max_storage' ] )
|
||||
|
@ -3446,7 +3450,9 @@ class DialogManageOptionsServerAdmin( ClientGUIDialogs.Dialog ):
|
|||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
options = connection.Get( 'options' )
|
||||
response = connection.Get( 'options' )
|
||||
|
||||
options = response[ 'options' ]
|
||||
|
||||
self._max_monthly_data.SetValue( options[ 'max_monthly_data' ] )
|
||||
self._max_storage.SetValue( options[ 'max_storage' ] )
|
||||
|
@ -3547,7 +3553,9 @@ class DialogManageOptionsTagRepository( ClientGUIDialogs.Dialog ):
|
|||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
options = connection.Get( 'options' )
|
||||
response = connection.Get( 'options' )
|
||||
|
||||
options = response[ 'options' ]
|
||||
|
||||
self._max_monthly_data.SetValue( options[ 'max_monthly_data' ] )
|
||||
|
||||
|
@ -3817,7 +3825,7 @@ class DialogManageRatings( ClientGUIDialogs.Dialog ):
|
|||
|
||||
try:
|
||||
|
||||
service_identfiers_to_content_updates = {}
|
||||
service_identifiers_to_content_updates = {}
|
||||
|
||||
for panel in self._panels:
|
||||
|
||||
|
@ -3825,11 +3833,11 @@ class DialogManageRatings( ClientGUIDialogs.Dialog ):
|
|||
|
||||
( service_identifier, content_updates ) = panel.GetContentUpdates()
|
||||
|
||||
service_identfiers_to_content_updates[ service_identifier ] = content_updates
|
||||
service_identifiers_to_content_updates[ service_identifier ] = content_updates
|
||||
|
||||
|
||||
|
||||
HC.app.Write( 'content_updates', service_identfiers_to_content_updates )
|
||||
HC.app.Write( 'content_updates', service_identifiers_to_content_updates )
|
||||
|
||||
except Exception as e: wx.MessageBox( 'Saving ratings changes to DB raised this error: ' + HC.u( e ) )
|
||||
|
||||
|
@ -4125,8 +4133,6 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
|
||||
def InitialiseControls():
|
||||
|
||||
self._edit_log = []
|
||||
|
||||
self._services_listbook = ClientGUICommon.ListBook( self )
|
||||
self._services_listbook.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGED, self.EventServiceChanged )
|
||||
self._services_listbook.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
||||
|
@ -4141,24 +4147,8 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
|
||||
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
|
||||
|
||||
self._ok = wx.Button( self, label='ok' )
|
||||
self._ok.Bind( wx.EVT_BUTTON, self.EventOK )
|
||||
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
||||
|
||||
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label='cancel' )
|
||||
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
|
||||
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
||||
|
||||
# goes after self._remove, because of events
|
||||
|
||||
for service_identifier in self._service_identifiers:
|
||||
|
||||
page = self._Panel( self._services_listbook, service_identifier )
|
||||
|
||||
name = HC.service_string_lookup[ service_identifier.GetType() ]
|
||||
|
||||
self._services_listbook.AddPage( page, name )
|
||||
|
||||
self._done = wx.Button( self, label='done' )
|
||||
self._done.Bind( wx.EVT_BUTTON, self.EventDone )
|
||||
|
||||
|
||||
def PopulateControls():
|
||||
|
@ -4167,6 +4157,21 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
|
||||
self._service_types.SetSelection( 0 )
|
||||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
response = connection.Get( 'services' )
|
||||
|
||||
services_info = response[ 'services_info' ]
|
||||
|
||||
for ( service_identifier, options ) in services_info:
|
||||
|
||||
page = self._Panel( self._services_listbook, service_identifier, options )
|
||||
|
||||
name = HC.service_string_lookup[ service_identifier.GetType() ]
|
||||
|
||||
self._services_listbook.AddPage( page, name )
|
||||
|
||||
|
||||
|
||||
def ArrangeControls():
|
||||
|
||||
|
@ -4175,14 +4180,10 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
add_remove_hbox.AddF( self._add, FLAGS_MIXED )
|
||||
add_remove_hbox.AddF( self._remove, FLAGS_MIXED )
|
||||
|
||||
ok_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
||||
ok_hbox.AddF( self._ok, FLAGS_MIXED )
|
||||
ok_hbox.AddF( self._cancel, FLAGS_MIXED )
|
||||
|
||||
vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
vbox.AddF( self._services_listbook, FLAGS_EXPAND_BOTH_WAYS )
|
||||
vbox.AddF( add_remove_hbox, FLAGS_SMALL_INDENT )
|
||||
vbox.AddF( ok_hbox, FLAGS_BUTTON_SIZERS )
|
||||
vbox.AddF( self._done, FLAGS_LONE_BUTTON )
|
||||
|
||||
self.SetSizer( vbox )
|
||||
|
||||
|
@ -4199,7 +4200,9 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
self._service_identifiers = connection.Get( 'services' )
|
||||
response = connection.Get( 'services' )
|
||||
|
||||
self._service_identifiers = response[ 'service_identifiers' ]
|
||||
|
||||
InitialiseControls()
|
||||
|
||||
|
@ -4221,11 +4224,11 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
|
||||
if service_panel is not None:
|
||||
|
||||
port = service_panel.GetInfo()
|
||||
( service_identifier, options ) = service_panel.GetInfo()
|
||||
|
||||
for existing_port in [ page.GetInfo() for page in self._services_listbook.GetNameToPageDict().values() if page != service_panel ]:
|
||||
for ( existing_service_identifier, existing_options ) in [ page.GetInfo() for page in self._services_listbook.GetNameToPageDict().values() if page != service_panel ]:
|
||||
|
||||
if port == existing_port: raise Exception( 'That port is already in use!' )
|
||||
if options[ 'port' ] == existing_options[ 'port' ]: raise Exception( 'That port is already in use!' )
|
||||
|
||||
|
||||
|
||||
|
@ -4236,26 +4239,23 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
|
||||
service_type = self._service_types.GetClientData( self._service_types.GetSelection() )
|
||||
|
||||
existing_ports = [ page.GetInfo() for page in self._services_listbook.GetNameToPageDict().values() ]
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
port = HC.DEFAULT_SERVICE_PORT
|
||||
response = connection.Post( 'services', action = 'add', data = service_type )
|
||||
|
||||
while port in existing_ports: port += 1
|
||||
service_identifier = response[ 'service_identifier' ]
|
||||
options = response[ 'options' ]
|
||||
|
||||
service_identifier = HC.ServerServiceIdentifier( service_type, port )
|
||||
# commit to local db now
|
||||
|
||||
self._edit_log.append( ( HC.ADD, service_identifier ) )
|
||||
|
||||
page = self._Panel( self._services_listbook, service_identifier )
|
||||
page = self._Panel( self._services_listbook, service_identifier, options )
|
||||
|
||||
name = HC.service_string_lookup[ service_type ]
|
||||
|
||||
self._services_listbook.AddPage( page, name, select = True )
|
||||
|
||||
|
||||
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
||||
|
||||
def EventOK( self, event ):
|
||||
def EventDone( self, event ):
|
||||
|
||||
try: self._CheckCurrentServiceIsValid()
|
||||
except Exception as e:
|
||||
|
@ -4267,22 +4267,9 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
|
||||
for page in self._services_listbook.GetNameToPageDict().values():
|
||||
|
||||
if page.HasChanges(): self._edit_log.append( ( HC.EDIT, ( page.GetOriginalServiceIdentifier(), page.GetInfo() ) ) )
|
||||
if page.HasChanges(): page.CommitChanges()
|
||||
|
||||
|
||||
try:
|
||||
|
||||
if len( self._edit_log ) > 0:
|
||||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
connection.Post( 'services_modification', edit_log = self._edit_log )
|
||||
|
||||
HC.app.Write( 'update_server_services', self._service.GetServiceIdentifier(), self._edit_log )
|
||||
|
||||
|
||||
except Exception as e: wx.MessageBox( 'Saving services to server raised this error: ' + HC.u( e ) )
|
||||
|
||||
self.EndModal( wx.ID_OK )
|
||||
|
||||
|
||||
|
@ -4292,9 +4279,11 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
|
||||
if service_panel is not None:
|
||||
|
||||
service_identifier = service_panel.GetOriginalServiceIdentifier()
|
||||
service_identifier = service_panel.GetServiceIdentifier()
|
||||
|
||||
self._edit_log.append( ( HC.DELETE, service_identifier ) )
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
response = connection.Post( 'services', action = 'delete', data = service_identifier )
|
||||
|
||||
self._services_listbook.DeleteCurrentPage()
|
||||
|
||||
|
@ -4321,18 +4310,23 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
|
||||
class _Panel( wx.Panel ):
|
||||
|
||||
def __init__( self, parent, service_identifier ):
|
||||
def __init__( self, parent, service_identifier, options ):
|
||||
|
||||
wx.Panel.__init__( self, parent )
|
||||
|
||||
self._service_identifier = service_identifier
|
||||
self._options = options
|
||||
|
||||
def InitialiseControls():
|
||||
|
||||
self._service_panel = ClientGUICommon.StaticBox( self, 'service' )
|
||||
|
||||
# all possible options here. hide as appropriate in arrange
|
||||
|
||||
self._service_port = wx.SpinCtrl( self._service_panel, min = 1, max = 65535 )
|
||||
|
||||
# a button to commit options, should enable when changes
|
||||
|
||||
|
||||
def PopulateControls():
|
||||
|
||||
|
@ -4366,6 +4360,20 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
|
|||
ArrangeControls()
|
||||
|
||||
|
||||
def EventUploadOptions( self, event ):
|
||||
|
||||
# create service/connection to service/whatever
|
||||
|
||||
connection.Post( 'options', options = options )
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def CommitChanges( self ):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def GetInfo( self ):
|
||||
|
||||
port = self._service_port.GetValue()
|
||||
|
@ -6866,16 +6874,16 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
|
|||
|
||||
try:
|
||||
|
||||
service_identfiers_to_content_updates = {}
|
||||
service_identifiers_to_content_updates = {}
|
||||
|
||||
for page in self._tag_repositories.GetNameToPageDict().values():
|
||||
|
||||
( service_identifier, content_updates ) = page.GetContentUpdates()
|
||||
|
||||
service_identfiers_to_content_updates[ service_identifier ] = content_updates
|
||||
service_identifiers_to_content_updates[ service_identifier ] = content_updates
|
||||
|
||||
|
||||
if len( service_identfiers_to_content_updates ) > 0: HC.app.Write( 'content_updates', service_identfiers_to_content_updates )
|
||||
if len( service_identifiers_to_content_updates ) > 0: HC.app.Write( 'content_updates', service_identifiers_to_content_updates )
|
||||
|
||||
except Exception as e: wx.MessageBox( 'Saving mapping changes to DB raised this error: ' + HC.u( e ) )
|
||||
|
||||
|
|
|
@ -2604,7 +2604,9 @@ class ManagementPanelPetitions( ManagementPanel ):
|
|||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
self._current_petition = connection.Get( 'petition' )
|
||||
response = connection.Get( 'petition' )
|
||||
|
||||
self._current_petition = response[ 'petition' ]
|
||||
|
||||
self._DrawCurrentPetition()
|
||||
|
||||
|
@ -2631,7 +2633,9 @@ class ManagementPanelPetitions( ManagementPanel ):
|
|||
|
||||
connection = self._service.GetConnection()
|
||||
|
||||
self._num_petitions = connection.Get( 'num_petitions' )
|
||||
response = connection.Get( 'num_petitions' )
|
||||
|
||||
self._num_petitions = response[ 'num_petitions' ]
|
||||
|
||||
self._DrawNumPetitions()
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ TEMP_DIR = BASE_DIR + os.path.sep + 'temp'
|
|||
|
||||
# Misc
|
||||
|
||||
NETWORK_VERSION = 10
|
||||
SOFTWARE_VERSION = 86
|
||||
NETWORK_VERSION = 11
|
||||
SOFTWARE_VERSION = 87
|
||||
|
||||
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
|
||||
|
||||
|
@ -127,7 +127,15 @@ service_string_lookup[ TAG_REPOSITORY ] = 'hydrus tag repository'
|
|||
service_string_lookup[ FILE_REPOSITORY ] = 'hydrus file repository'
|
||||
service_string_lookup[ LOCAL_FILE ] = 'hydrus local file service'
|
||||
service_string_lookup[ MESSAGE_DEPOT ] = 'hydrus message depot'
|
||||
service_string_lookup[ LOCAL_TAG ] = 'local tag service'
|
||||
service_string_lookup[ LOCAL_RATING_NUMERICAL ] = 'local numerical rating service'
|
||||
service_string_lookup[ LOCAL_RATING_LIKE ] = 'local like/dislike rating service'
|
||||
service_string_lookup[ RATING_NUMERICAL_REPOSITORY ] = 'hydrus numerical rating repository'
|
||||
service_string_lookup[ RATING_LIKE_REPOSITORY ] = 'hydrus like/dislike rating repository'
|
||||
service_string_lookup[ COMBINED_TAG ] = 'virtual combined tag service'
|
||||
service_string_lookup[ COMBINED_FILE ] = 'virtual combined file service'
|
||||
service_string_lookup[ SERVER_ADMIN ] = 'hydrus server administration'
|
||||
service_string_lookup[ NULL_SERVICE ] = 'null service'
|
||||
|
||||
RATINGS_SERVICES = [ LOCAL_RATING_LIKE, LOCAL_RATING_NUMERICAL, RATING_LIKE_REPOSITORY, RATING_NUMERICAL_REPOSITORY ]
|
||||
REPOSITORIES = [ TAG_REPOSITORY, FILE_REPOSITORY, RATING_LIKE_REPOSITORY, RATING_NUMERICAL_REPOSITORY ]
|
||||
|
@ -453,15 +461,15 @@ restricted_requests.append( ( GET, 'options', GENERAL_ADMIN ) )
|
|||
restricted_requests.append( ( GET, 'registration_keys', GENERAL_ADMIN ) )
|
||||
restricted_requests.append( ( GET, 'session_key', None ) )
|
||||
restricted_requests.append( ( GET, 'stats', GENERAL_ADMIN ) )
|
||||
restricted_requests.append( ( POST, 'account_modification', ( MANAGE_USERS, GENERAL_ADMIN ) ) )
|
||||
restricted_requests.append( ( POST, 'account_types_modification', GENERAL_ADMIN ) )
|
||||
restricted_requests.append( ( POST, 'account', ( MANAGE_USERS, GENERAL_ADMIN ) ) )
|
||||
restricted_requests.append( ( POST, 'account_types', GENERAL_ADMIN ) )
|
||||
restricted_requests.append( ( POST, 'options', GENERAL_ADMIN ) )
|
||||
|
||||
admin_requests = list( restricted_requests )
|
||||
admin_requests.append( ( GET, 'init', None ) )
|
||||
admin_requests.append( ( GET, 'services', EDIT_SERVICES ) )
|
||||
admin_requests.append( ( POST, 'backup', EDIT_SERVICES ) )
|
||||
admin_requests.append( ( POST, 'services_modification', EDIT_SERVICES ) )
|
||||
admin_requests.append( ( POST, 'services', EDIT_SERVICES ) )
|
||||
|
||||
repository_requests = list( restricted_requests )
|
||||
repository_requests.append( ( GET, 'num_petitions', RESOLVE_PETITIONS ) )
|
||||
|
@ -984,7 +992,8 @@ def ShowExceptionDefault( e ):
|
|||
|
||||
message = u( etype.__name__ ) + ': ' + u( value ) + os.linesep + u( trace )
|
||||
|
||||
print( repr( message ) )
|
||||
try: print( message )
|
||||
except: print( repr( message ) )
|
||||
|
||||
ShowException = ShowExceptionDefault
|
||||
|
||||
|
@ -1431,9 +1440,7 @@ class Account( HydrusYAMLBase ):
|
|||
else: return GetNow() > self._expires
|
||||
|
||||
|
||||
def CheckPermissions( self, permissions ):
|
||||
|
||||
if type( permissions ) == int: permissions = ( permissions, )
|
||||
def CheckPermission( self, permission ):
|
||||
|
||||
if self._IsBanned(): raise HydrusExceptions.PermissionException( 'This account is banned!' )
|
||||
|
||||
|
@ -1443,11 +1450,11 @@ class Account( HydrusYAMLBase ):
|
|||
|
||||
( used_bytes, used_requests ) = self._used_data
|
||||
|
||||
if max_num_bytes is not None and used_bytes > max_num_bytes: raise HydrusExceptions.PermissionException( 'You have hit your data transfer limit (' + ConvertIntToBytes( max_num_bytes ) + '), and cannot download any more for the month.' )
|
||||
if max_num_bytes is not None and used_bytes > max_num_bytes: raise HydrusExceptions.PermissionException( 'You have hit your data transfer limit (' + ConvertIntToBytes( max_num_bytes ) + '), and cannot make any more requests for the month.' )
|
||||
|
||||
if max_num_requests is not None and used_requests > max_num_requests: raise HydrusExceptions.PermissionException( 'You have hit your requests limit (' + ConvertIntToPrettyString( max_num_requests ) + '), and cannot download any more for the month.' )
|
||||
if max_num_requests is not None and used_requests > max_num_requests: raise HydrusExceptions.PermissionException( 'You have hit your requests limit (' + ConvertIntToPrettyString( max_num_requests ) + '), and cannot make any more requests for the month.' )
|
||||
|
||||
if len( permissions ) > 0 and True not in [ self._account_type.HasPermission( permission ) for permission in permissions ]: raise HydrusExceptions.PermissionException( 'You do not have permission to do that.' )
|
||||
if not self._account_type.HasPermission( permission ): raise HydrusExceptions.PermissionException( 'You do not have permission to do that.' )
|
||||
|
||||
|
||||
def ConvertToString( self ): return ConvertTimestampToPrettyAge( self._created ) + os.linesep + self._account_type.ConvertToString( self._used_data ) + os.linesep + 'which '+ ConvertTimestampToPrettyExpires( self._expires )
|
||||
|
@ -1497,6 +1504,8 @@ class Account( HydrusYAMLBase ):
|
|||
|
||||
def HasPermission( self, permission ):
|
||||
|
||||
if self._IsBanned(): return False
|
||||
|
||||
if self._IsExpired(): return False
|
||||
|
||||
( max_num_bytes, max_num_requests ) = self._account_type.GetMaxMonthlyData()
|
||||
|
@ -1636,7 +1645,7 @@ class ClientServiceIdentifier( HydrusYAMLBase ):
|
|||
|
||||
def __ne__( self, other ): return self.__hash__() != other.__hash__()
|
||||
|
||||
def __repr__( self ): return 'Client Service Identifier: ' + u( ( self._name, self._type, self._service_key ) )
|
||||
def __repr__( self ): return 'Client Service Identifier: ' + u( ( self._name, service_string_lookup[ self._type ] ) )
|
||||
|
||||
def GetInfo( self ): return ( self._service_key, self._type, self._name )
|
||||
|
||||
|
@ -2256,53 +2265,58 @@ SYSTEM_PREDICATE_NOT_LOCAL = Predicate( PREDICATE_TYPE_SYSTEM, ( SYSTEM_PREDICAT
|
|||
|
||||
class ResponseContext():
|
||||
|
||||
def __init__( self, status_code, mime = None, body = '', filename = None, cookies = [] ):
|
||||
def __init__( self, status_code, mime = APPLICATION_YAML, body = None, path = None, is_yaml = False, cookies = [] ):
|
||||
|
||||
self._status_code = status_code
|
||||
self._mime = mime
|
||||
self._body = body
|
||||
self._filename = filename
|
||||
self._path = path
|
||||
self._is_yaml = is_yaml
|
||||
self._cookies = cookies
|
||||
|
||||
|
||||
def GetCookies( self ): return self._cookies
|
||||
|
||||
def GetFilename( self ): return self._filename
|
||||
|
||||
def GetLength( self ): return len( self._body )
|
||||
|
||||
def GetMimeBody( self ): return ( self._mime, self._body )
|
||||
|
||||
def GetPath( self ): return self._path
|
||||
|
||||
def GetStatusCode( self ): return self._status_code
|
||||
|
||||
def HasBody( self ): return self._body != ''
|
||||
def HasBody( self ): return self._body is not None
|
||||
|
||||
def HasPath( self ): return self._path is not None
|
||||
|
||||
def IsYAML( self ): return self._is_yaml
|
||||
|
||||
def HasFilename( self ): return self._filename is not None
|
||||
|
||||
class ServerServiceIdentifier( HydrusYAMLBase ):
|
||||
|
||||
yaml_tag = u'!ServerServiceIdentifier'
|
||||
|
||||
def __init__( self, type, port ):
|
||||
def __init__( self, service_key, type ):
|
||||
|
||||
HydrusYAMLBase.__init__( self )
|
||||
|
||||
self._service_key = service_key
|
||||
self._type = type
|
||||
self._port = port
|
||||
|
||||
|
||||
def __eq__( self, other ): return self.__hash__() == other.__hash__()
|
||||
|
||||
def __hash__( self ): return ( self._type, self._port ).__hash__()
|
||||
def __hash__( self ): return self._service_key.__hash__()
|
||||
|
||||
def __ne__( self, other ): return self.__hash__() != other.__hash__()
|
||||
|
||||
def __repr__( self ): return 'Server Service Identifier: ' + u( ( self._type, self._port ) )
|
||||
def __repr__( self ): return 'Server Service Identifier: ' + service_string_lookup[ self._type ]
|
||||
|
||||
def GetPort( self ): return self._port
|
||||
def GetServiceKey( self ): return self._service_key
|
||||
|
||||
def GetType( self ): return self._type
|
||||
|
||||
SERVER_ADMIN_IDENTIFIER = ServerServiceIdentifier( 'server admin', SERVER_ADMIN )
|
||||
|
||||
class ServiceUpdate():
|
||||
|
||||
def __init__( self, action, row = None ):
|
||||
|
|
|
@ -10,17 +10,21 @@ import HydrusExceptions
|
|||
import HydrusFileHandling
|
||||
import HydrusFlashHandling
|
||||
import HydrusImageHandling
|
||||
import HydrusServerResources
|
||||
import HydrusVideoHandling
|
||||
import os
|
||||
import random
|
||||
import ServerConstants as SC
|
||||
import SocketServer
|
||||
import traceback
|
||||
import urllib
|
||||
import wx
|
||||
import yaml
|
||||
#from twisted.web.server import Site
|
||||
#from twisted.web.resource import Resource
|
||||
#from twisted.web.static import File as FileResource
|
||||
from twisted.internet import reactor, defer
|
||||
from twisted.internet.threads import deferToThread
|
||||
from twisted.web.server import Request, Site, NOT_DONE_YET
|
||||
from twisted.web.resource import Resource
|
||||
from twisted.web.static import File as FileResource, NoRangeStaticProducer
|
||||
|
||||
eris = '''<html><head><title>hydrus</title></head><body><pre>
|
||||
<font color="red">8888 8888888</font>
|
||||
|
@ -226,384 +230,7 @@ ROOT_MESSAGE_BEGIN = '''<html>
|
|||
ROOT_MESSAGE_END = '''</p>
|
||||
</body>
|
||||
</html>'''
|
||||
|
||||
def ParseAccessKey( authorisation_text ):
|
||||
|
||||
if authorisation_text is None: access_key = None
|
||||
else:
|
||||
|
||||
( format, access_key_encoded ) = authorisation_text.split( ' ' )
|
||||
|
||||
if format != 'hydrus_network': raise HydrusExceptions.ForbiddenException( 'Authorisation format error!' )
|
||||
|
||||
try: access_key = access_key_encoded.decode( 'hex' )
|
||||
except: raise HydrusExceptions.ForbiddenException( 'Attempted to parse access key, but could not understand it.' )
|
||||
|
||||
|
||||
return access_key
|
||||
|
||||
def ParseFileArguments( path ):
|
||||
|
||||
HydrusImageHandling.ConvertToPngIfBmp( path )
|
||||
|
||||
hash = HydrusFileHandling.GetHashFromPath( path )
|
||||
|
||||
try: ( size, mime, width, height, duration, num_frames, num_words ) = HydrusFileHandling.GetFileInfo( path, hash )
|
||||
except HydrusExceptions.SizeException: raise HydrusExceptions.ForbiddenException( 'File is of zero length!' )
|
||||
except HydrusExceptions.MimeException: raise HydrusExceptions.ForbiddenException( 'Filetype is not permitted!' )
|
||||
except Exception as e: raise HydrusExceptions.ForbiddenException( HC.u( e ) )
|
||||
|
||||
args = {}
|
||||
|
||||
args[ 'path' ] = path
|
||||
args[ 'hash' ] = hash
|
||||
args[ 'size' ] = size
|
||||
args[ 'mime' ] = mime
|
||||
|
||||
if width is not None: args[ 'width' ] = width
|
||||
if height is not None: args[ 'height' ] = height
|
||||
if duration is not None: args[ 'duration' ] = duration
|
||||
if num_frames is not None: args[ 'num_frames' ] = num_frames
|
||||
if num_words is not None: args[ 'num_words' ] = num_words
|
||||
|
||||
if mime in HC.IMAGES:
|
||||
|
||||
try: thumbnail = HydrusImageHandling.GenerateThumbnail( path )
|
||||
except: raise HydrusExceptions.ForbiddenException( 'Could not generate thumbnail from that file.' )
|
||||
|
||||
args[ 'thumbnail' ] = thumbnail
|
||||
|
||||
|
||||
return args
|
||||
|
||||
def ParseHTTPGETArguments( path ):
|
||||
|
||||
path = urllib.unquote( path )
|
||||
|
||||
arguments = {}
|
||||
|
||||
if '?' in path:
|
||||
|
||||
raw_arguments = path.split( '?', 1 )[1]
|
||||
|
||||
for raw_argument in raw_arguments.split( '&' ):
|
||||
|
||||
if '=' in raw_argument:
|
||||
|
||||
[ name, value ] = raw_argument.split( '=', 1 )
|
||||
|
||||
if name in ( 'begin', 'num', 'expiration', 'subject_account_id', 'service_type', 'service_port', 'since' ):
|
||||
|
||||
try: arguments[ name ] = int( value )
|
||||
except: raise HydrusExceptions.ForbiddenException( 'I was expecting to parse \'' + name + '\' as an integer, but it failed.' )
|
||||
|
||||
elif name in ( 'access_key', 'title', 'subject_access_key', 'contact_key', 'hash', 'subject_hash', 'subject_tag', 'message_key' ):
|
||||
|
||||
try: arguments[ name ] = value.decode( 'hex' )
|
||||
except: raise HydrusExceptions.ForbiddenException( 'I was expecting to parse \'' + name + '\' as a hex-encoded string, but it failed.' )
|
||||
|
||||
|
||||
|
||||
|
||||
if 'subject_account_id' in arguments: arguments[ 'subject_identifier' ] = HC.AccountIdentifier( access_key = arguments[ 'subject_account_id' ] )
|
||||
elif 'subject_access_key' in arguments: arguments[ 'subject_identifier' ] = HC.AccountIdentifier( access_key = arguments[ 'subject_access_key' ] )
|
||||
elif 'subject_tag' in arguments and 'subject_hash' in arguments: arguments[ 'subject_identifier' ] = HC.AccountIdentifier( tag = arguments[ 'subject_tag' ], hash = arguments[ 'subject_hash' ] )
|
||||
elif 'subject_hash' in arguments: arguments[ 'subject_identifier' ] = HC.AccountIdentifier( hash = arguments[ 'subject_hash' ] )
|
||||
|
||||
|
||||
return arguments
|
||||
|
||||
def ParseHTTPPOSTArguments( body ):
|
||||
|
||||
if body == '': args = ()
|
||||
else: args = yaml.safe_load( body )
|
||||
|
||||
return args
|
||||
|
||||
def ParseHTTPRequest( path ):
|
||||
|
||||
path = urllib.unquote( path )
|
||||
|
||||
if not path.startswith( '/' ): return ''
|
||||
|
||||
after_slash = path.split( '/', 1 )[1]
|
||||
|
||||
return after_slash.split( '?', 1 )[0]
|
||||
|
||||
def ParseSessionKey( cookie_text ):
|
||||
|
||||
if cookie_text is None: session_key = None
|
||||
else:
|
||||
|
||||
try:
|
||||
|
||||
cookies = Cookie.SimpleCookie( cookie_text )
|
||||
|
||||
if 'session_key' not in cookies: session_key = None
|
||||
else: session_key = cookies[ 'session_key' ].value.decode( 'hex' )
|
||||
|
||||
except: raise Exception( 'Problem parsing cookie!' )
|
||||
|
||||
|
||||
return session_key
|
||||
|
||||
class HydrusHTTPServer( SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer ):
|
||||
|
||||
def __init__( self, service_identifier, message = '' ):
|
||||
|
||||
#self.daemon_threads = True
|
||||
|
||||
self._service_identifier = service_identifier
|
||||
self._message = message
|
||||
|
||||
port = service_identifier.GetPort()
|
||||
|
||||
BaseHTTPServer.HTTPServer.__init__( self, ( '', port ), HydrusHTTPRequestHandler )
|
||||
|
||||
HC.pubsub.sub( self, 'shutdown', 'shutdown' )
|
||||
|
||||
|
||||
def GetServiceIdentifier( self ): return self._service_identifier
|
||||
|
||||
def GetMessage( self ): return self._message
|
||||
|
||||
def SetMessage( self, message ): self._message = message
|
||||
|
||||
class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
|
||||
|
||||
server_version = 'hydrus/' + HC.u( HC.NETWORK_VERSION )
|
||||
protocol_version = 'HTTP/1.1'
|
||||
|
||||
with open( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', 'rb' ) as f: _favicon = f.read()
|
||||
|
||||
def __init__( self, request, client_address, server ):
|
||||
|
||||
self._service_identifier = server.GetServiceIdentifier()
|
||||
|
||||
try: BaseHTTPServer.BaseHTTPRequestHandler.__init__( self, request, client_address, server )
|
||||
except: self.log_string( 'Connection reset by peer' )
|
||||
|
||||
|
||||
def _ProcessRequest( self, request_type ):
|
||||
|
||||
try:
|
||||
|
||||
try:
|
||||
|
||||
default_mime = HC.TEXT_HTML
|
||||
default_encoding = lambda x: HC.u( x )
|
||||
|
||||
user_agent_text = self.headers.getheader( 'User-Agent' )
|
||||
|
||||
if user_agent_text is not None:
|
||||
|
||||
user_agents = user_agent_text.split( ' ' )
|
||||
|
||||
for user_agent in user_agents:
|
||||
|
||||
if '/' in user_agent:
|
||||
|
||||
( client, network_version ) = user_agent.split( '/', 1 )
|
||||
|
||||
if client == 'hydrus':
|
||||
|
||||
default_mime = HC.APPLICATION_YAML
|
||||
default_encoding = lambda x: yaml.safe_dump( HC.u( x ) )
|
||||
|
||||
network_version = int( network_version )
|
||||
|
||||
if network_version != HC.NETWORK_VERSION:
|
||||
|
||||
if network_version < HC.NETWORK_VERSION: message = 'Please download the latest release.'
|
||||
else: message = 'Please ask this server\'s admin to update to the latest release.'
|
||||
|
||||
raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! This server\'s network version is ' + HC.u( HC.NETWORK_VERSION ) + ', whereas your client\'s is ' + HC.u( network_version ) + '! ' + message )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
( ip, port ) = self.client_address
|
||||
|
||||
service_type = self._service_identifier.GetType()
|
||||
|
||||
if service_type == HC.LOCAL_FILE and ip != '127.0.0.1': raise HydrusExceptions.ForbiddenException( 'Only local access allowed!' )
|
||||
|
||||
request = ParseHTTPRequest( self.path )
|
||||
|
||||
if ( service_type, request_type, request ) not in HC.ALLOWED_REQUESTS: raise HydrusExceptions.ForbiddenException( 'This service does not support that request.' )
|
||||
|
||||
if request_type == HC.GET:
|
||||
|
||||
request_args = ParseHTTPGETArguments( self.path )
|
||||
request_length = 0
|
||||
|
||||
elif request_type == HC.POST:
|
||||
|
||||
content_length = int( self.headers.getheader( 'Content-Length', default = 0 ) )
|
||||
|
||||
request_length = content_length
|
||||
|
||||
# can do customised test here for max file allowed or whatever
|
||||
if ( request == 'file' and content_length > 100 * 1024 * 1024 ) or ( request != 'file' and content_length > 10 * 1024 * 1024 ): raise HydrusExceptions.ForbiddenException( 'That request is too large!' )
|
||||
|
||||
if request == 'file':
|
||||
|
||||
path = HC.GetTempPath()
|
||||
|
||||
num_bytes_still_to_write = content_length
|
||||
|
||||
block_size = 65536
|
||||
|
||||
next_block_size = min( block_size, num_bytes_still_to_write )
|
||||
|
||||
next_block = self.rfile.read( next_block_size )
|
||||
|
||||
num_bytes_still_to_write -= next_block_size
|
||||
|
||||
with open( path, 'wb' ) as f:
|
||||
|
||||
while True:
|
||||
|
||||
f.write( next_block )
|
||||
|
||||
if num_bytes_still_to_write == 0: break
|
||||
|
||||
next_block_size = min( block_size, num_bytes_still_to_write )
|
||||
|
||||
next_block = self.rfile.read( next_block_size )
|
||||
|
||||
num_bytes_still_to_write -= next_block_size
|
||||
|
||||
|
||||
|
||||
request_args = ParseFileArguments( path )
|
||||
|
||||
else:
|
||||
|
||||
body = self.rfile.read( content_length )
|
||||
|
||||
request_args = ParseHTTPPOSTArguments( body )
|
||||
|
||||
|
||||
|
||||
if request == '':
|
||||
|
||||
if service_type == HC.LOCAL_FILE: body = CLIENT_ROOT_MESSAGE
|
||||
else:
|
||||
|
||||
message = self.server.GetMessage()
|
||||
|
||||
body = ROOT_MESSAGE_BEGIN + message + ROOT_MESSAGE_END
|
||||
|
||||
|
||||
response_context = HC.ResponseContext( 200, mime = HC.TEXT_HTML, body = body )
|
||||
|
||||
elif request == 'favicon.ico': response_context = HC.ResponseContext( 200, mime = HC.IMAGE_ICON, body = self._favicon, filename = 'favicon.ico' )
|
||||
else:
|
||||
|
||||
if service_type == HC.LOCAL_FILE:
|
||||
|
||||
if request_type == HC.GET:
|
||||
|
||||
if request == 'file':
|
||||
|
||||
hash = request_args[ 'hash' ]
|
||||
|
||||
path = CC.GetFilePath( hash )
|
||||
|
||||
mime = HydrusFileHandling.GetMime( path )
|
||||
|
||||
with open( path, 'rb' ) as f: file = f.read()
|
||||
|
||||
response_context = HC.ResponseContext( 200, mime = mime, body = file, filename = hash.encode( 'hex' ) + HC.mime_ext_lookup[ mime ] )
|
||||
|
||||
elif request == 'thumbnail':
|
||||
|
||||
hash = request_args[ 'hash' ]
|
||||
|
||||
path = CC.GetThumbnailPath( hash, True )
|
||||
|
||||
mime = HydrusFileHandling.GetMime( path )
|
||||
|
||||
with open( path, 'rb' ) as f: thumbnail = f.read()
|
||||
|
||||
response_context = HC.ResponseContext( 200, mime = mime, body = thumbnail, filename = hash.encode( 'hex' ) + '_thumbnail' + HC.mime_ext_lookup[ mime ] )
|
||||
|
||||
|
||||
elif request_type == HC.POST: pass # nothing here yet!
|
||||
|
||||
else:
|
||||
|
||||
session_key = ParseSessionKey( self.headers.getheader( 'Cookie' ) )
|
||||
access_key = ParseAccessKey( self.headers.getheader( 'Authorization' ) )
|
||||
|
||||
response_context = HC.app.GetDB().AddJobServer( self._service_identifier, access_key, session_key, ip, request_type, request, request_args, request_length )
|
||||
|
||||
|
||||
|
||||
except:
|
||||
|
||||
# wx.MessageBox( traceback.format_exc() )
|
||||
|
||||
raise
|
||||
|
||||
|
||||
except KeyError: response_context = HC.ResponseContext( 403, mime = default_mime, body = default_encoding( 'It appears one or more parameters required for that request were missing.' ) )
|
||||
except HydrusExceptions.PermissionException as e: response_context = HC.ResponseContext( 401, mime = default_mime, body = default_encoding( e ) )
|
||||
except HydrusExceptions.ForbiddenException as e: response_context = HC.ResponseContext( 403, mime = default_mime, body = default_encoding( e ) )
|
||||
except HydrusExceptions.NotFoundException as e: response_context = HC.ResponseContext( 404, mime = default_mime, body = default_encoding( e ) )
|
||||
except HydrusExceptions.NetworkVersionException as e: response_context = HC.ResponseContext( 426, mime = default_mime, body = default_encoding( e ) )
|
||||
except HydrusExceptions.SessionException as e: response_context = HC.ResponseContext( 403, mime = default_mime, body = default_encoding( 'Session not found!' ) )
|
||||
except Exception as e:
|
||||
|
||||
self.log_string( traceback.format_exc() )
|
||||
|
||||
response_context = HC.ResponseContext( 500, mime = default_mime, body = default_encoding( 'The repository encountered an error it could not handle! Here is a dump of what happened, which will also be written to your client.log file. If it persists, please forward it to hydrus.admin@gmail.com:' + os.linesep + os.linesep + traceback.format_exc() ) )
|
||||
|
||||
|
||||
try: self._Respond( response_context )
|
||||
except: pass # wx.MessageBox( traceback.format_exc() )
|
||||
|
||||
|
||||
def _Respond( self, response_context ):
|
||||
|
||||
status_code = response_context.GetStatusCode()
|
||||
|
||||
self.send_response( status_code )
|
||||
|
||||
for cookie in response_context.GetCookies(): self.send_header( 'Set-Cookie', cookie )
|
||||
|
||||
if response_context.HasBody():
|
||||
|
||||
( mime, body ) = response_context.GetMimeBody()
|
||||
|
||||
content_type = HC.mime_string_lookup[ mime ]
|
||||
|
||||
if response_context.HasFilename():
|
||||
|
||||
filename = response_context.GetFilename()
|
||||
|
||||
content_type += '; ' + filename
|
||||
|
||||
|
||||
self.send_header( 'Content-Type', content_type )
|
||||
self.send_header( 'Content-Length', len( body ) )
|
||||
|
||||
self.end_headers()
|
||||
|
||||
self.wfile.write( body )
|
||||
|
||||
else:
|
||||
|
||||
self.send_header( 'Content-Length', '0' )
|
||||
self.end_headers()
|
||||
|
||||
|
||||
|
||||
def do_GET( self ): self._ProcessRequest( HC.GET )
|
||||
|
||||
'''
|
||||
def do_OPTIONS( self ):
|
||||
|
||||
service_type = self._service_identifier.GetType()
|
||||
|
@ -622,189 +249,26 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
|
|||
self.send_header( 'Allow', ','.join( allowed ) )
|
||||
self.end_headers()
|
||||
|
||||
'''
|
||||
class HydrusRequest( Request ):
|
||||
|
||||
def do_POST( self ): self._ProcessRequest( HC.POST )
|
||||
|
||||
def log_message( self, format, *args ): print( "[%s] %s%s" % ( self.log_date_time_string(), format%args, os.linesep ) )
|
||||
|
||||
def log_request( self, *args ): pass
|
||||
|
||||
def log_string( self, message ): print( repr( message ) )
|
||||
|
||||
# this overrides the base method to no longer use the class variable server_version
|
||||
def version_string( self ):
|
||||
def __init__( self, *args, **kwargs ):
|
||||
|
||||
service_type = self._service_identifier.GetType()
|
||||
Request.__init__( self, *args, **kwargs )
|
||||
|
||||
server_version = HC.service_string_lookup[ service_type ] + '/' + HC.u( HC.NETWORK_VERSION )
|
||||
|
||||
return server_version + ' ' + self.sys_version
|
||||
|
||||
|
||||
#
|
||||
'''
|
||||
hydrus_favicon = FileResource( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', defaultType = HC.IMAGE_ICON )
|
||||
|
||||
class HydrusResourceWelcome( Resource ):
|
||||
|
||||
def __init__( self, service_identifier, message ):
|
||||
|
||||
Resource.__init__( self )
|
||||
|
||||
if service_identifier.GetType() == HC.LOCAL_FILE: body = CLIENT_ROOT_MESSAGE
|
||||
else: body = ROOT_MESSAGE_BEGIN + message + ROOT_MESSAGE_END
|
||||
|
||||
self._body = body.encode( 'utf-8' )
|
||||
|
||||
|
||||
def render_GET( self, request ): return self._body
|
||||
|
||||
class HydrusResourceMakeSession( Resource ):
|
||||
|
||||
def render_GET( self, request ):
|
||||
|
||||
# parse key from authorisation header
|
||||
|
||||
# go to db to fetch account, error as appropriate
|
||||
|
||||
# 200 OK with session key cookie
|
||||
|
||||
pass
|
||||
self.is_hydrus_client = True
|
||||
self.hydrus_args = None
|
||||
self.hydrus_response_context = None
|
||||
self.hydrus_request_data_usage = 0
|
||||
|
||||
|
||||
class HydrusResourceCommand( Resource ):
|
||||
class HydrusRequestRestricted( HydrusRequest ):
|
||||
|
||||
def __init__( self, local_only ):
|
||||
def __init__( self, *args, **kwargs ):
|
||||
|
||||
Resource.__init__( self )
|
||||
HydrusRequest.__init__( self, *args, **kwargs )
|
||||
|
||||
# set default mime, which is like self.defaultContentType
|
||||
|
||||
self._local_only = local_only
|
||||
|
||||
|
||||
def _checkLocal( self, request ):
|
||||
|
||||
if self._local_only and request.getClientIP() != '127.0.0.1': raise HydrusExceptions.ForbiddenException( 'Only local access allowed!' )
|
||||
|
||||
|
||||
def _checkRestrictions( self, request ):
|
||||
|
||||
self._checkLocal( request )
|
||||
|
||||
|
||||
def _renderResponseContext( self, response_context, request ):
|
||||
|
||||
status_code = response_context.GetStatusCode()
|
||||
|
||||
request.setResponseCode( status_code )
|
||||
|
||||
# this is wrong; addcookie takes k, v
|
||||
# should move to sessions anyway
|
||||
for cookie in response_context.GetCookies(): request.addCookie( cookie )
|
||||
|
||||
if response_context.HasBody():
|
||||
|
||||
( mime, body ) = response_context.GetMimeBody()
|
||||
|
||||
content_type = HC.mime_string_lookup[ mime ]
|
||||
|
||||
if response_context.HasFilename():
|
||||
|
||||
filename = response_context.GetFilename()
|
||||
|
||||
content_type += '; ' + filename
|
||||
|
||||
|
||||
request.setHeader( 'Content-Type', content_type )
|
||||
request.setHeader( 'Content-Length', len( body ) )
|
||||
|
||||
return body
|
||||
|
||||
else: return ''
|
||||
|
||||
|
||||
def render_GET( self, request ):
|
||||
|
||||
try:
|
||||
|
||||
self._checkRestrictions( request )
|
||||
|
||||
args = FilterGETArgs( request.args )
|
||||
|
||||
# WAIT, NO. MAKE EVERY REQUEST DEFERRED. THAT'S 10000% easier
|
||||
|
||||
# d = reactor.deferToThread or something
|
||||
# d.addCallBack( self._renderResponseContext )
|
||||
# and maybe an errback too, or the same one! whatever!
|
||||
|
||||
# return NOT_READY or whatever
|
||||
|
||||
except: pass
|
||||
|
||||
|
||||
class HydrusResourceCommandRestricted( HydrusResourceCommand ):
|
||||
|
||||
GET_PERMISSION = HC.GENERAL_ADMIN
|
||||
POST_PERMISSION = HC.GENERAL_ADMIN
|
||||
|
||||
def _checkPermission( self, method, request ):
|
||||
|
||||
# get session
|
||||
# get account
|
||||
# test account for that permission
|
||||
# depending on method, use class variable GET_PERMISSION or POST_PERMISSION
|
||||
|
||||
# fail with a no session found
|
||||
# fail with you do not have that permission
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def _checkRestrictions( self, request ):
|
||||
|
||||
HydrusResourceCommand._checkRestrictions( self, request )
|
||||
|
||||
self._checkGETPermission( request )
|
||||
|
||||
|
||||
def _doDatabase( self, args ): pass
|
||||
|
||||
def _databaseDone( self, response_context ):
|
||||
|
||||
# after a deferred, can I set the response code?
|
||||
pass # renderresponse
|
||||
|
||||
|
||||
class HydrusResourceLocalFile( Resource ):
|
||||
|
||||
def render_GET( self, request ):
|
||||
|
||||
if request.getClientIP() != '127.0.0.1':
|
||||
|
||||
request.setResponseCode( 403 )
|
||||
|
||||
return 'nope'
|
||||
|
||||
else:
|
||||
|
||||
try:
|
||||
|
||||
hash = request.args[ 'hash' ][0]
|
||||
print( 'ok')
|
||||
# test hash is ok
|
||||
|
||||
# test os.path.exists
|
||||
|
||||
# return a fileresource
|
||||
|
||||
return hydrus_favicon
|
||||
|
||||
except:
|
||||
print( traceback.format_exc())
|
||||
return NoResource()
|
||||
|
||||
|
||||
self.hydrus_account = None
|
||||
|
||||
|
||||
class HydrusService( Site ):
|
||||
|
@ -818,13 +282,15 @@ class HydrusService( Site ):
|
|||
|
||||
Site.__init__( self, root )
|
||||
|
||||
self.requestFactory = HydrusRequest
|
||||
|
||||
|
||||
def _InitRoot( self ):
|
||||
|
||||
root = Resource()
|
||||
|
||||
root.putChild( '', HydrusResourceWelcome( self._service_identifier, self._message ) )
|
||||
root.putChild( 'favicon.ico', hydrus_favicon )
|
||||
root.putChild( '', HydrusServerResources.HydrusResourceWelcome( self._service_identifier, self._message ) )
|
||||
root.putChild( 'favicon.ico', HydrusServerResources.hydrus_favicon )
|
||||
|
||||
return root
|
||||
|
||||
|
@ -835,95 +301,75 @@ class HydrusServiceLocal( HydrusService ):
|
|||
|
||||
root = HydrusService._InitRoot( self )
|
||||
|
||||
root.putChild( 'file', HydrusResourceLocalFile() )
|
||||
root.putChild( 'file', HydrusServerResources.HydrusResourceCommandFileLocal( self._service_identifier ) )
|
||||
root.putChild( 'thumbnail', HydrusServerResources.HydrusResourceCommandThumbnailLocal( self._service_identifier ) )
|
||||
|
||||
return root
|
||||
|
||||
|
||||
class HydrusServiceRestricted( HydrusService ):
|
||||
|
||||
def makeSession( self ):
|
||||
def __init__( self, service_identifier, message ):
|
||||
|
||||
uid = os.urandom( 32 ) # only change here is this hydrus-style uid
|
||||
HydrusService.__init__( self, service_identifier, message )
|
||||
|
||||
session = self.sessions[uid] = self.sessionFactory(self, uid)
|
||||
self.requestFactory = HydrusRequestRestricted
|
||||
|
||||
session.startCheckingExpiration()
|
||||
|
||||
def _InitRoot( self ):
|
||||
|
||||
return session
|
||||
root = HydrusService._InitRoot( self )
|
||||
|
||||
root.putChild( 'access_key', HydrusServerResources.HydrusResourceCommandAccessKey( self._service_identifier ) )
|
||||
root.putChild( 'session_key', HydrusServerResources.HydrusResourceCommandSessionKey( self._service_identifier ) )
|
||||
|
||||
root.putChild( 'account', HydrusServerResources.HydrusResourceCommandRestrictedAccount( self._service_identifier ) )
|
||||
root.putChild( 'account_info', HydrusServerResources.HydrusResourceCommandRestrictedAccountInfo( self._service_identifier ) )
|
||||
root.putChild( 'account_types', HydrusServerResources.HydrusResourceCommandRestrictedAccountTypes( self._service_identifier ) )
|
||||
root.putChild( 'registration_keys', HydrusServerResources.HydrusResourceCommandRestrictedRegistrationKeys( self._service_identifier ) )
|
||||
root.putChild( 'stats', HydrusServerResources.HydrusResourceCommandRestrictedStats( self._service_identifier ) )
|
||||
|
||||
return root
|
||||
|
||||
'''
|
||||
'''
|
||||
|
||||
BANDWIDTH_CONSUMING_REQUESTS = set()
|
||||
class HydrusServiceAdmin( HydrusServiceRestricted ):
|
||||
|
||||
BANDWIDTH_CONSUMING_REQUESTS.add( ( TAG_REPOSITORY, GET, 'update' ) )
|
||||
BANDWIDTH_CONSUMING_REQUESTS.add( ( TAG_REPOSITORY, POST, 'mappings' ) )
|
||||
BANDWIDTH_CONSUMING_REQUESTS.add( ( TAG_REPOSITORY, POST, 'petitions' ) )
|
||||
BANDWIDTH_CONSUMING_REQUESTS.add( ( FILE_REPOSITORY, GET, 'update' ) )
|
||||
BANDWIDTH_CONSUMING_REQUESTS.add( ( FILE_REPOSITORY, GET, 'file' ) )
|
||||
BANDWIDTH_CONSUMING_REQUESTS.add( ( FILE_REPOSITORY, GET, 'thumbnail' ) )
|
||||
BANDWIDTH_CONSUMING_REQUESTS.add( ( FILE_REPOSITORY, POST, 'file' ) )
|
||||
BANDWIDTH_CONSUMING_REQUESTS.add( ( FILE_REPOSITORY, POST, 'petitions' ) )
|
||||
def _InitRoot( self ):
|
||||
|
||||
root = HydrusServiceRestricted._InitRoot( self )
|
||||
|
||||
root.putChild( 'backup', HydrusServerResources.HydrusResourceCommandRestrictedBackup( self._service_identifier ) )
|
||||
root.putChild( 'init', HydrusServerResources.HydrusResourceCommandInit( self._service_identifier ) )
|
||||
root.putChild( 'services', HydrusServerResources.HydrusResourceCommandRestrictedAccountInfo( self._service_identifier ) )
|
||||
|
||||
return root
|
||||
|
||||
|
||||
service_requests = []
|
||||
service_requests.append( ( GET, '', None ) )
|
||||
service_requests.append( ( GET, 'favicon.ico', None ) )
|
||||
class HydrusServiceRepository( HydrusServiceRestricted ):
|
||||
|
||||
local_file_requests = list( service_requests )
|
||||
local_file_requests.append( ( GET, 'file', None ) )
|
||||
local_file_requests.append( ( GET, 'thumbnail', None ) )
|
||||
def _InitRoot( self ):
|
||||
|
||||
root = HydrusServiceRestricted._InitRoot( self )
|
||||
|
||||
root.putChild( 'news', HydrusServerResources.HydrusResourceCommandRestrictedNews( self._service_identifier ) )
|
||||
root.putChild( 'num_petitions', HydrusServerResources.HydrusResourceCommandRestrictedNumPetitions( self._service_identifier ) )
|
||||
root.putChild( 'petition', HydrusServerResources.HydrusResourceCommandRestrictedPetition( self._service_identifier ) )
|
||||
root.putChild( 'update', HydrusServerResources.HydrusResourceCommandRestrictedUpdate( self._service_identifier ) )
|
||||
|
||||
return root
|
||||
|
||||
|
||||
restricted_requests = list( service_requests )
|
||||
restricted_requests.append( ( GET, 'access_key', None ) )
|
||||
restricted_requests.append( ( GET, 'account', None ) )
|
||||
restricted_requests.append( ( GET, 'account_info', MANAGE_USERS ) )
|
||||
restricted_requests.append( ( GET, 'account_types', MANAGE_USERS ) )
|
||||
restricted_requests.append( ( GET, 'options', GENERAL_ADMIN ) )
|
||||
restricted_requests.append( ( GET, 'registration_keys', GENERAL_ADMIN ) )
|
||||
restricted_requests.append( ( GET, 'session_key', None ) )
|
||||
restricted_requests.append( ( GET, 'stats', GENERAL_ADMIN ) )
|
||||
restricted_requests.append( ( POST, 'account_modification', ( MANAGE_USERS, GENERAL_ADMIN ) ) )
|
||||
restricted_requests.append( ( POST, 'account_types_modification', GENERAL_ADMIN ) )
|
||||
restricted_requests.append( ( POST, 'options', GENERAL_ADMIN ) )
|
||||
class HydrusServiceRepositoryFile( HydrusServiceRepository ):
|
||||
|
||||
admin_requests = list( restricted_requests )
|
||||
admin_requests.append( ( GET, 'init', None ) )
|
||||
admin_requests.append( ( GET, 'services', EDIT_SERVICES ) )
|
||||
admin_requests.append( ( POST, 'backup', EDIT_SERVICES ) )
|
||||
admin_requests.append( ( POST, 'services_modification', EDIT_SERVICES ) )
|
||||
def _InitRoot( self ):
|
||||
|
||||
root = HydrusServiceRepository._InitRoot( self )
|
||||
|
||||
root.putChild( 'file', HydrusServerResources.HydrusResourceCommandRestrictedFileRepository( self._service_identifier ) )
|
||||
root.putChild( 'ip', HydrusServerResources.HydrusResourceCommandRestrictedIP( self._service_identifier ) )
|
||||
root.putChild( 'thumbnail', HydrusServerResources.HydrusResourceCommandRestrictedThumbnailRepository( self._service_identifier ) )
|
||||
|
||||
return root
|
||||
|
||||
|
||||
repository_requests = list( restricted_requests )
|
||||
repository_requests.append( ( GET, 'num_petitions', RESOLVE_PETITIONS ) )
|
||||
repository_requests.append( ( GET, 'petition', RESOLVE_PETITIONS ) )
|
||||
repository_requests.append( ( GET, 'update', GET_DATA ) )
|
||||
repository_requests.append( ( POST, 'news', GENERAL_ADMIN ) )
|
||||
repository_requests.append( ( POST, 'update', POST_DATA ) )
|
||||
|
||||
file_repository_requests = list( repository_requests )
|
||||
file_repository_requests.append( ( GET, 'file', GET_DATA ) )
|
||||
file_repository_requests.append( ( GET, 'ip', GENERAL_ADMIN ) )
|
||||
file_repository_requests.append( ( GET, 'thumbnail', GET_DATA ) )
|
||||
file_repository_requests.append( ( POST, 'file', POST_DATA ) )
|
||||
|
||||
tag_repository_requests = list( repository_requests )
|
||||
|
||||
message_depot_requests = list( restricted_requests )
|
||||
message_depot_requests.append( ( GET, 'message', GET_DATA ) )
|
||||
message_depot_requests.append( ( GET, 'message_info_since', GET_DATA ) )
|
||||
message_depot_requests.append( ( GET, 'public_key', None ) )
|
||||
message_depot_requests.append( ( POST, 'contact', POST_DATA ) )
|
||||
message_depot_requests.append( ( POST, 'message', None ) )
|
||||
message_depot_requests.append( ( POST, 'message_statuses', None ) )
|
||||
|
||||
all_requests = []
|
||||
all_requests.extend( [ ( LOCAL_FILE, request_type, request, permissions ) for ( request_type, request, permissions ) in local_file_requests ] )
|
||||
all_requests.extend( [ ( SERVER_ADMIN, request_type, request, permissions ) for ( request_type, request, permissions ) in admin_requests ] )
|
||||
all_requests.extend( [ ( FILE_REPOSITORY, request_type, request, permissions ) for ( request_type, request, permissions ) in file_repository_requests ] )
|
||||
all_requests.extend( [ ( TAG_REPOSITORY, request_type, request, permissions ) for ( request_type, request, permissions ) in tag_repository_requests ] )
|
||||
all_requests.extend( [ ( MESSAGE_DEPOT, request_type, request, permissions ) for ( request_type, request, permissions ) in message_depot_requests ] )
|
||||
|
||||
ALLOWED_REQUESTS = { ( service_type, request_type, request ) for ( service_type, request_type, request, permissions ) in all_requests }
|
||||
|
||||
REQUESTS_TO_PERMISSIONS = { ( service_type, request_type, request ) : permissions for ( service_type, request_type, request, permissions ) in all_requests }
|
||||
'''
|
||||
class HydrusServiceRepositoryTag( HydrusServiceRepository ): pass
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,6 +13,8 @@ import traceback
|
|||
import wx
|
||||
import yaml
|
||||
|
||||
HYDRUS_SESSION_EXPIRY_TIME = 30 * 86400
|
||||
|
||||
class HydrusSessionManagerClient():
|
||||
|
||||
def __init__( self ):
|
||||
|
@ -61,7 +63,7 @@ class HydrusSessionManagerClient():
|
|||
try: session_key = cookies[ 'session_key' ].decode( 'hex' )
|
||||
except: raise Exception( 'Service did not return a session key!' )
|
||||
|
||||
expiry = now + 30 * 86400
|
||||
expiry = now + HYDRUS_SESSION_EXPIRY_TIME
|
||||
|
||||
self._sessions[ service_identifier ] = ( session_key, expiry )
|
||||
|
||||
|
@ -75,21 +77,32 @@ class HydrusSessionManagerServer():
|
|||
|
||||
def __init__( self ):
|
||||
|
||||
existing_sessions = HC.app.GetDB().Read( 'sessions', HC.HIGH_PRIORITY )
|
||||
existing_sessions = HC.app.Read( 'sessions' )
|
||||
|
||||
self._sessions = { ( session_key, service_identifier ) : ( account_identifier, expiry ) for ( session_key, service_identifier, account_identifier, expiry ) in existing_sessions }
|
||||
self._sessions = { ( session_key, service_identifier ) : ( account, expiry ) for ( session_key, service_identifier, account, expiry ) in existing_sessions }
|
||||
|
||||
self._lock = threading.Lock()
|
||||
|
||||
|
||||
def AddSession( self, session_key, service_identifier, account_identifier, expiry ):
|
||||
def AddSession( self, service_identifier, account ):
|
||||
|
||||
HC.app.GetDB().Write( 'session', HC.HIGH_PRIORITY, session_key, service_identifier, account_identifier, expiry )
|
||||
session_key = os.urandom( 32 )
|
||||
|
||||
self._sessions[ ( session_key, service_identifier ) ] = ( account_identifier, expiry )
|
||||
now = HC.GetNow()
|
||||
|
||||
expiry = now + HYDRUS_SESSION_EXPIRY_TIME
|
||||
|
||||
HC.app.Write( 'session', session_key, service_identifier, account, expiry )
|
||||
|
||||
with self._lock:
|
||||
|
||||
self._sessions[ ( session_key, service_identifier ) ] = ( account, expiry )
|
||||
|
||||
|
||||
return ( session_key, expiry )
|
||||
|
||||
|
||||
def GetAccountIdentifier( self, session_key, service_identifier ):
|
||||
def GetAccount( self, session_key, service_identifier ):
|
||||
|
||||
now = HC.GetNow()
|
||||
|
||||
|
@ -97,14 +110,12 @@ class HydrusSessionManagerServer():
|
|||
|
||||
if ( session_key, service_identifier ) in self._sessions:
|
||||
|
||||
( account_identifier, expiry ) = self._sessions[ ( session_key, service_identifier ) ]
|
||||
( account, expiry ) = self._sessions[ ( session_key, service_identifier ) ]
|
||||
|
||||
if now > expiry: del self._sessions[ ( session_key, service_identifier ) ]
|
||||
else: return account_identifier
|
||||
else: return account
|
||||
|
||||
|
||||
# session not found, or expired
|
||||
|
||||
raise HydrusExceptions.SessionException()
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import dircache
|
||||
import HydrusConstants as HC
|
||||
import HydrusExceptions
|
||||
import itertools
|
||||
import os
|
||||
|
||||
def GetExpectedPath( file_type, hash ):
|
||||
|
||||
if file_type == 'file': directory = HC.SERVER_FILES_DIR
|
||||
elif file_type == 'thumbnail': directory = HC.SERVER_THUMBNAILS_DIR
|
||||
elif file_type == 'update': directory = HC.SERVER_UPDATES_DIR
|
||||
elif file_type == 'message': directory = HC.SERVER_MESSAGES_DIR
|
||||
|
||||
hash_encoded = hash.encode( 'hex' )
|
||||
|
||||
first_two_chars = hash_encoded[:2]
|
||||
|
||||
path = directory + os.path.sep + first_two_chars + os.path.sep + hash_encoded
|
||||
|
||||
return path
|
||||
|
||||
def GetPath( file_type, hash ):
|
||||
|
||||
path = GetExpectedPath( file_type, hash )
|
||||
|
||||
if not os.path.exists( path ): raise HydrusExceptions.NotFoundException( file_type + ' not found!' )
|
||||
|
||||
return path
|
||||
|
||||
def GetAllHashes( file_type ): return { os.path.split( path )[1].decode( 'hex' ) for path in IterateAllPaths( file_type ) }
|
||||
|
||||
def IterateAllPaths( file_type ):
|
||||
|
||||
if file_type == 'file': directory = HC.SERVER_FILES_DIR
|
||||
elif file_type == 'thumbnail': directory = HC.SERVER_THUMBNAILS_DIR
|
||||
elif file_type == 'update': directory = HC.SERVER_UPDATES_DIR
|
||||
elif file_type == 'message': directory = HC.SERVER_MESSAGES_DIR
|
||||
|
||||
hex_chars = '0123456789abcdef'
|
||||
|
||||
for ( one, two ) in itertools.product( hex_chars, hex_chars ):
|
||||
|
||||
dir = directory + os.path.sep + one + two
|
||||
|
||||
next_paths = dircache.listdir( dir )
|
||||
|
||||
for path in next_paths: yield dir + os.path.sep + path
|
||||
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import httplib
|
||||
import HydrusConstants as HC
|
||||
import HydrusServer
|
||||
import HydrusSessions
|
||||
import ServerConstants as SC
|
||||
import ServerDB
|
||||
import os
|
||||
import random
|
||||
|
@ -9,6 +11,7 @@ import time
|
|||
import traceback
|
||||
import wx
|
||||
import yaml
|
||||
from twisted.internet import reactor
|
||||
|
||||
class Controller( wx.App ):
|
||||
|
||||
|
@ -26,36 +29,13 @@ class Controller( wx.App ):
|
|||
except: return False
|
||||
|
||||
|
||||
def AddSession( self, session_key, service_identifier, account_identifier, expiry ): self._session_manager.AddSession( session_key, service_identifier, account_identifier, expiry )
|
||||
def _Read( self, action, *args, **kwargs ): return self._db.Read( action, HC.HIGH_PRIORITY, *args, **kwargs )
|
||||
|
||||
def ChangePort( self, port ):
|
||||
|
||||
new_server = self._server_callable( port )
|
||||
|
||||
server_daemon = threading.Thread( target=new_server.serve_forever )
|
||||
server_daemon.setDaemon( True )
|
||||
server_daemon.start()
|
||||
|
||||
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 20 )
|
||||
|
||||
connection.connect()
|
||||
|
||||
connection.request( 'GET', '/' )
|
||||
|
||||
response = connection.getresponse()
|
||||
|
||||
data = response.read()
|
||||
|
||||
if response.status != 200: raise Exception( yaml.safe_load( data ) )
|
||||
|
||||
connection.close()
|
||||
|
||||
self._server.shutdown()
|
||||
|
||||
self._server = new_server
|
||||
|
||||
def _Write( self, action, priority, *args, **kwargs ): return self._db.Write( action, priority, *args, **kwargs )
|
||||
|
||||
def GetAccountIdentifier( self, session_key, service_identifier ): return self._session_manager.GetAccountIdentifier( session_key, service_identifier )
|
||||
def AddSession( self, service_identifier, account ): return self._session_manager.AddSession( service_identifier, account )
|
||||
|
||||
def GetAccount( self, session_key, service_identifier ): return self._session_manager.GetAccount( session_key, service_identifier )
|
||||
|
||||
def EventExit( self, event ): self._tbicon.Destroy()
|
||||
|
||||
|
@ -72,29 +52,110 @@ class Controller( wx.App ):
|
|||
pubsubs_queue.task_done()
|
||||
|
||||
|
||||
def GetDB( self ): return self._db
|
||||
|
||||
def OnInit( self ):
|
||||
|
||||
HC.app = self
|
||||
|
||||
try: self._db = ServerDB.DB()
|
||||
try:
|
||||
|
||||
self._db = ServerDB.DB()
|
||||
|
||||
self.Bind( wx.EVT_MENU, self.EventExit, id=wx.ID_EXIT )
|
||||
|
||||
self.Bind( HC.EVT_PUBSUB, self.EventPubSub )
|
||||
|
||||
self._tbicon = TaskBarIcon()
|
||||
|
||||
self._session_manager = HydrusSessions.HydrusSessionManagerServer()
|
||||
|
||||
HC.pubsub.sub( self, 'RestartService', 'restart_service' )
|
||||
|
||||
self._services = {}
|
||||
|
||||
services_info = self.Read( 'services' )
|
||||
|
||||
for ( service_identifier, options ) in services_info: self.RestartService( service_identifier, options )
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
|
||||
HC.ShowException( e )
|
||||
print( traceback.format_exc() )
|
||||
|
||||
return False
|
||||
|
||||
|
||||
self._session_manager = HydrusSessions.HydrusSessionManagerServer()
|
||||
|
||||
def Read( self, action, *args, **kwargs ):
|
||||
|
||||
self.Bind( wx.EVT_MENU, self.EventExit, id=wx.ID_EXIT )
|
||||
return self._Read( action, *args, **kwargs )
|
||||
|
||||
self.Bind( HC.EVT_PUBSUB, self.EventPubSub )
|
||||
|
||||
def RestartService( self, service_identifier, options ):
|
||||
|
||||
self._tbicon = TaskBarIcon()
|
||||
def TWISTEDRestartService():
|
||||
|
||||
def StartService():
|
||||
|
||||
try:
|
||||
|
||||
port = options[ 'port' ]
|
||||
|
||||
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
|
||||
|
||||
try:
|
||||
|
||||
connection.connect()
|
||||
connection.close()
|
||||
|
||||
raise Exception( 'Something was already bound to port ' + HC.u( port ) )
|
||||
|
||||
except:
|
||||
|
||||
message = options[ 'message' ]
|
||||
|
||||
service_type = service_identifier.GetType()
|
||||
|
||||
if service_type == HC.SERVER_ADMIN: service_object = HydrusServer.HydrusServiceAdmin( service_identifier, message )
|
||||
elif service_type == HC.FILE_REPOSITORY: service_object = HydrusServer.HydrusServiceRepositoryFile( service_identifier, message )
|
||||
elif service_type == HC.TAG_REPOSITORY: service_object = HydrusServer.HydrusServiceRepositoryTag( service_identifier, message )
|
||||
elif service_type == HC.MESSAGE_DEPOT: return
|
||||
|
||||
self._services[ service_identifier ] = reactor.listenTCP( port, service_object )
|
||||
|
||||
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
|
||||
|
||||
try:
|
||||
|
||||
connection.connect()
|
||||
connection.close()
|
||||
|
||||
except:
|
||||
|
||||
raise Exception( 'Tried to bind port ' + HC.u( port ) + ' but it failed.' )
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
|
||||
print( traceback.format_exc() )
|
||||
|
||||
|
||||
if service_identifier not in self._services: StartService()
|
||||
else:
|
||||
|
||||
deferred = self._services[ service_identifier ].stopListening()
|
||||
|
||||
deferred.AddCallback( StartService )
|
||||
|
||||
|
||||
|
||||
return True
|
||||
reactor.callFromThread( TWISTEDRestartService )
|
||||
|
||||
|
||||
def Write( self, action, *args, **kwargs ):
|
||||
|
||||
return self._Write( action, HC.HIGH_PRIORITY, *args, **kwargs )
|
||||
|
||||
|
||||
class TaskBarIcon( wx.TaskBarIcon ):
|
||||
|
|
1469
include/ServerDB.py
1469
include/ServerDB.py
File diff suppressed because it is too large
Load Diff
|
@ -17,6 +17,8 @@ import os
|
|||
import sys
|
||||
from include import HydrusConstants as HC
|
||||
from include import ServerController
|
||||
import threading
|
||||
from twisted.internet import reactor
|
||||
|
||||
initial_sys_stdout = sys.stdout
|
||||
initial_sys_stderr = sys.stderr
|
||||
|
@ -28,6 +30,8 @@ with open( HC.LOGS_DIR + os.path.sep + 'server.log', 'a' ) as f:
|
|||
|
||||
try:
|
||||
|
||||
threading.Thread( target = reactor.run, kwargs = { 'installSignalHandlers' : 0 } ).start()
|
||||
|
||||
app = ServerController.Controller()
|
||||
|
||||
app.MainLoop()
|
||||
|
@ -43,4 +47,6 @@ sys.stderr = initial_sys_stderr
|
|||
|
||||
HC.shutdown = True
|
||||
|
||||
reactor.callFromThread( reactor.stop )
|
||||
|
||||
HC.pubsub.pubimmediate( 'shutdown' )
|
||||
|
|
Loading…
Reference in New Issue