2015-04-01 20:44:54 +00:00
import httplib
2013-02-19 00:11:43 +00:00
import HydrusConstants as HC
2015-04-01 20:44:54 +00:00
import HydrusController
2015-03-25 22:04:19 +00:00
import HydrusData
2015-09-02 23:16:09 +00:00
import HydrusExceptions
2015-03-25 22:04:19 +00:00
import HydrusGlobals
2015-06-10 19:40:25 +00:00
import HydrusNetworking
2013-03-15 02:38:12 +00:00
import HydrusSessions
2014-05-21 21:37:35 +00:00
import HydrusThreading
2015-09-02 23:16:09 +00:00
import os
2015-03-04 22:44:32 +00:00
import ServerDaemons
2013-02-19 00:11:43 +00:00
import ServerDB
2015-12-02 22:32:18 +00:00
import ServerServer
2015-09-02 23:16:09 +00:00
import sys
import time
2013-02-19 00:11:43 +00:00
import traceback
2016-12-14 21:19:07 +00:00
import twisted . internet . ssl
2013-10-02 22:06:06 +00:00
from twisted . internet import reactor
2013-10-23 21:36:47 +00:00
from twisted . internet import defer
2013-02-19 00:11:43 +00:00
2016-10-12 21:52:50 +00:00
def ProcessStartingAction ( db_dir , action ) :
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
already_running = HydrusData . IsAlreadyRunning ( db_dir , ' server ' )
2015-04-01 20:44:54 +00:00
2016-10-12 21:52:50 +00:00
if action == ' start ' :
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
if already_running :
2013-02-19 00:11:43 +00:00
2016-10-12 21:52:50 +00:00
HydrusData . Print ( ' The server is already running. Would you like to [s]top it, [r]estart it, or e[x]it? ' )
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
answer = raw_input ( )
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
if len ( answer ) > 0 :
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
answer = answer [ 0 ]
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
if answer == ' s ' :
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
return ' stop '
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
elif answer == ' r ' :
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
return ' restart '
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
raise HydrusExceptions . PermissionException ( ' Exiting! ' )
else :
return action
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
elif action == ' stop ' :
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
if already_running :
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
return action
2015-09-02 23:16:09 +00:00
else :
2016-10-12 21:52:50 +00:00
raise HydrusExceptions . PermissionException ( ' The server is not running, so it cannot be stopped! ' )
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
elif action == ' restart ' :
if already_running :
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
return action
else :
return ' start '
2015-09-02 23:16:09 +00:00
2016-10-12 21:52:50 +00:00
def ShutdownSiblingInstance ( db_dir ) :
2015-09-16 18:11:00 +00:00
port_found = False
2016-10-12 21:52:50 +00:00
ports = HydrusData . GetSiblingProcessPorts ( db_dir , ' server ' )
2015-09-16 18:11:00 +00:00
if ports is None :
raise HydrusExceptions . PermissionException ( ' Could not figure out the existing server \' s ports, so could not shut it down! ' )
for port in ports :
try :
2017-01-25 22:56:55 +00:00
connection = HydrusNetworking . GetLocalConnection ( port , https = True )
2015-09-16 18:11:00 +00:00
connection . request ( ' GET ' , ' / ' )
response = connection . getresponse ( )
response . read ( )
server_name = response . getheader ( ' Server ' )
except :
text = ' Could not contact existing server \' s port ' + str ( port ) + ' ! '
text + = os . linesep
text + = traceback . format_exc ( )
raise HydrusExceptions . PermissionException ( text )
if ' server administration ' in server_name :
port_found = True
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Sending shut down instruction... ' )
2015-09-16 18:11:00 +00:00
connection . request ( ' POST ' , ' /shutdown ' )
response = connection . getresponse ( )
result = response . read ( )
if response . status != 200 :
text = ' When told to shut down, the existing server gave an error! '
text + = os . linesep
text + = result
raise HydrusExceptions . PermissionException ( text )
time_waited = 0
2016-10-12 21:52:50 +00:00
while HydrusData . IsAlreadyRunning ( db_dir , ' server ' ) :
2015-09-16 18:11:00 +00:00
time . sleep ( 1 )
time_waited + = 1
if time_waited > 20 :
raise HydrusExceptions . PermissionException ( ' Attempted to shut the existing server down, but it took too long! ' )
break
if not port_found :
raise HydrusExceptions . PermissionException ( ' The existing server did not have an administration service! ' )
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' The existing server is shut down! ' )
2015-09-16 18:11:00 +00:00
2015-09-02 23:16:09 +00:00
class Controller ( HydrusController . HydrusController ) :
2016-10-19 20:02:56 +00:00
def __init__ ( self , db_dir , no_daemons , no_wal ) :
2015-09-16 18:11:00 +00:00
2016-10-19 20:02:56 +00:00
HydrusController . HydrusController . __init__ ( self , db_dir , no_daemons , no_wal )
2015-09-16 18:11:00 +00:00
HydrusGlobals . server_controller = self
2015-09-02 23:16:09 +00:00
def _InitDB ( self ) :
2016-10-12 21:52:50 +00:00
return ServerDB . DB ( self , self . _db_dir , ' server ' , no_wal = self . _no_wal )
2013-02-19 00:11:43 +00:00
2014-09-17 21:28:26 +00:00
def ActionService ( self , service_key , action ) :
2013-02-19 00:11:43 +00:00
2014-09-24 21:50:07 +00:00
if action != ' stop ' : ( service_type , options ) = self . Read ( ' service_info ' , service_key )
2013-07-10 20:25:57 +00:00
2014-09-17 21:28:26 +00:00
def TWISTEDDoIt ( ) :
2013-10-02 22:06:06 +00:00
2013-10-23 21:36:47 +00:00
def StartService ( * args , * * kwargs ) :
2013-10-02 22:06:06 +00:00
try :
2013-10-09 18:13:42 +00:00
if ' port ' not in options : return
2013-10-02 22:06:06 +00:00
port = options [ ' port ' ]
try :
2015-06-10 19:40:25 +00:00
connection = HydrusNetworking . GetLocalConnection ( port )
2013-10-02 22:06:06 +00:00
connection . close ( )
2015-11-04 22:30:28 +00:00
raise Exception ( ' Something was already bound to port ' + str ( port ) )
2013-10-02 22:06:06 +00:00
except :
message = options [ ' message ' ]
2015-12-02 22:32:18 +00:00
if service_type == HC . SERVER_ADMIN : service_object = ServerServer . HydrusServiceAdmin ( service_key , service_type , message )
elif service_type == HC . FILE_REPOSITORY : service_object = ServerServer . HydrusServiceRepositoryFile ( service_key , service_type , message )
elif service_type == HC . TAG_REPOSITORY : service_object = ServerServer . HydrusServiceRepositoryTag ( service_key , service_type , message )
2013-10-02 22:06:06 +00:00
elif service_type == HC . MESSAGE_DEPOT : return
2017-01-04 22:48:23 +00:00
( ssl_cert_path , ssl_key_path ) = self . _db . GetSSLPaths ( )
2016-12-14 21:19:07 +00:00
2017-01-04 22:48:23 +00:00
context_factory = twisted . internet . ssl . DefaultOpenSSLContextFactory ( ssl_key_path , ssl_cert_path )
2016-12-14 21:19:07 +00:00
2017-01-04 22:48:23 +00:00
self . _services [ service_key ] = reactor . listenSSL ( port , service_object , context_factory )
2013-10-02 22:06:06 +00:00
try :
2015-06-10 19:40:25 +00:00
connection = HydrusNetworking . GetLocalConnection ( port )
2013-10-02 22:06:06 +00:00
connection . close ( )
except :
2015-11-04 22:30:28 +00:00
raise Exception ( ' Tried to bind port ' + str ( port ) + ' but it failed. ' )
2013-10-02 22:06:06 +00:00
except Exception as e :
2015-11-18 22:44:07 +00:00
HydrusData . Print ( traceback . format_exc ( ) )
2013-10-02 22:06:06 +00:00
2013-10-09 18:13:42 +00:00
2013-10-02 22:06:06 +00:00
2014-09-17 21:28:26 +00:00
if action == ' start ' : StartService ( )
2013-10-02 22:06:06 +00:00
else :
2015-09-16 18:11:00 +00:00
if service_key in self . _services :
deferred = defer . maybeDeferred ( self . _services [ service_key ] . stopListening )
if action == ' stop ' : del self . _services [ service_key ]
2013-10-02 22:06:06 +00:00
2014-09-17 21:28:26 +00:00
if action == ' restart ' : deferred . addCallback ( StartService )
2013-10-02 22:06:06 +00:00
2014-09-17 21:28:26 +00:00
reactor . callFromThread ( TWISTEDDoIt )
2015-09-02 23:16:09 +00:00
def Exit ( self ) :
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Shutting down daemons and services... ' )
2015-09-16 18:11:00 +00:00
2015-09-02 23:16:09 +00:00
self . ShutdownView ( )
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Shutting down db... ' )
2015-09-16 18:11:00 +00:00
2015-09-02 23:16:09 +00:00
self . ShutdownModel ( )
2015-04-01 20:44:54 +00:00
2016-10-12 21:52:50 +00:00
HydrusData . CleanRunningFile ( self . _db_dir , ' server ' )
def GetFilesDir ( self ) :
return self . _db . GetFilesDir ( )
2016-06-15 18:59:44 +00:00
2014-09-17 21:28:26 +00:00
2015-12-09 23:16:41 +00:00
def GetServerSessionManager ( self ) :
return self . _server_session_manager
2016-10-12 21:52:50 +00:00
def GetUpdatesDir ( self ) :
return self . _db . GetUpdatesDir ( )
2015-12-09 23:16:41 +00:00
2015-09-02 23:16:09 +00:00
def InitModel ( self ) :
HydrusController . HydrusController . InitModel ( self )
2015-12-09 23:16:41 +00:00
self . _server_session_manager = HydrusSessions . HydrusSessionManagerServer ( )
2015-09-02 23:16:09 +00:00
self . _services = { }
self . sub ( self , ' ActionService ' , ' action_service ' )
2014-09-17 21:28:26 +00:00
2015-09-02 23:16:09 +00:00
def InitView ( self ) :
2015-08-26 21:18:39 +00:00
2015-09-02 23:16:09 +00:00
HydrusController . HydrusController . InitView ( self )
2015-08-26 21:18:39 +00:00
2016-01-20 23:57:33 +00:00
if not self . _no_daemons :
self . _daemons . append ( HydrusThreading . DAEMONQueue ( self , ' FlushRequestsMade ' , ServerDaemons . DAEMONFlushRequestsMade , ' request_made ' , period = 60 ) )
self . _daemons . append ( HydrusThreading . DAEMONWorker ( self , ' CheckMonthlyData ' , ServerDaemons . DAEMONCheckMonthlyData , period = 3600 ) )
self . _daemons . append ( HydrusThreading . DAEMONWorker ( self , ' ClearBans ' , ServerDaemons . DAEMONClearBans , period = 3600 ) )
self . _daemons . append ( HydrusThreading . DAEMONWorker ( self , ' DeleteOrphans ' , ServerDaemons . DAEMONDeleteOrphans , period = 86400 ) )
self . _daemons . append ( HydrusThreading . DAEMONWorker ( self , ' GenerateUpdates ' , ServerDaemons . DAEMONGenerateUpdates , period = 600 ) )
2017-02-08 22:27:00 +00:00
self . _daemons . append ( HydrusThreading . DAEMONWorker ( self , ' CheckDataUsage ' , ServerDaemons . DAEMONCheckDataUsage , period = 3600 ) )
2016-01-20 23:57:33 +00:00
self . _daemons . append ( HydrusThreading . DAEMONWorker ( self , ' UPnP ' , ServerDaemons . DAEMONUPnP , ( ' notify_new_options ' , ) , period = 43200 ) )
2015-08-26 21:18:39 +00:00
2016-10-12 21:52:50 +00:00
#
( service_type , options ) = self . Read ( ' service_info ' , HC . SERVER_ADMIN_KEY )
port = options [ ' port ' ]
2015-04-01 20:44:54 +00:00
2016-10-12 21:52:50 +00:00
already_bound = False
2015-04-01 20:44:54 +00:00
2016-10-12 21:52:50 +00:00
try :
connection = HydrusNetworking . GetLocalConnection ( port )
connection . close ( )
already_bound = True
2017-01-25 22:56:55 +00:00
except :
pass
2016-10-12 21:52:50 +00:00
if already_bound :
HydrusData . Print ( ' Something is already bound to port ' + str ( port ) + ' , so your administration service cannot be started. Please quit the server and retry once the port is clear. ' )
else :
service_keys = self . Read ( ' service_keys ' )
for service_key in service_keys : self . ActionService ( service_key , ' start ' )
2015-09-02 23:16:09 +00:00
def JustWokeFromSleep ( self ) : return False
2015-04-01 20:44:54 +00:00
2016-05-11 18:16:39 +00:00
def MaintainDB ( self , stop_time = None ) :
2016-01-06 21:17:20 +00:00
stop_time = HydrusData . GetNow ( ) + 10
2016-04-20 20:42:21 +00:00
self . WriteSynchronous ( ' analyze ' , stop_time )
2016-01-06 21:17:20 +00:00
2015-08-26 21:18:39 +00:00
def NotifyPubSubs ( self ) :
self . CallToThread ( self . ProcessPubSub )
2015-11-18 22:44:07 +00:00
def Run ( self ) :
2014-09-17 21:28:26 +00:00
2016-10-12 21:52:50 +00:00
HydrusData . RecordRunningStart ( self . _db_dir , ' server ' )
2015-09-02 23:16:09 +00:00
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Initialising db... ' )
2015-09-16 18:11:00 +00:00
self . InitModel ( )
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Initialising daemons and services... ' )
2015-09-16 18:11:00 +00:00
self . InitView ( )
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Server is running. Press Ctrl+C to quit. ' )
2015-09-16 18:11:00 +00:00
interrupt_received = False
2015-11-04 22:30:28 +00:00
while not self . _model_shutdown :
2014-09-17 21:28:26 +00:00
2015-09-16 18:11:00 +00:00
try :
2014-11-12 23:33:13 +00:00
2015-09-16 18:11:00 +00:00
time . sleep ( 1 )
except KeyboardInterrupt :
if not interrupt_received :
2015-09-02 23:16:09 +00:00
2015-09-16 18:11:00 +00:00
interrupt_received = True
2015-09-02 23:16:09 +00:00
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Received a keyboard interrupt... ' )
2015-09-02 23:16:09 +00:00
2015-09-16 18:11:00 +00:00
def do_it ( ) :
self . Exit ( )
self . CallToThread ( do_it )
2015-09-02 23:16:09 +00:00
2014-11-12 23:33:13 +00:00
2014-09-17 21:28:26 +00:00
2013-02-19 00:11:43 +00:00
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Shutting down controller... ' )
2015-09-16 18:11:00 +00:00
def ShutdownView ( self ) :
service_keys = self . Read ( ' service_keys ' )
for service_key in service_keys : self . ActionService ( service_key , ' stop ' )
HydrusController . HydrusController . ShutdownView ( self )
def ShutdownFromServer ( self ) :
2015-11-18 22:44:07 +00:00
HydrusData . Print ( ' Received a server shut down request... ' )
2015-09-16 18:11:00 +00:00
def do_it ( ) :
time . sleep ( 1 )
self . Exit ( )
self . CallToThread ( do_it )
2016-12-14 21:19:07 +00:00