hydrus/include/ServerController.py

259 lines
8.9 KiB
Python
Executable File

import httplib
import HydrusConstants as HC
import HydrusServer
import HydrusSessions
import HydrusThreading
import ServerConstants as SC
import ServerDB
import os
import random
import sys
import threading
import time
import traceback
import wx
import yaml
from twisted.internet import reactor
from twisted.internet import defer
ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
MAINTENANCE_PERIOD = 5 * 60
class Controller( wx.App ):
def _AlreadyRunning( self, port ):
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 20 )
try:
connection.connect()
connection.close()
return True
except: return False
def _Read( self, action, priority, *args, **kwargs ): return self._db.Read( action, priority, *args, **kwargs )
def _Write( self, action, priority, *args, **kwargs ): return self._db.Write( action, priority, *args, **kwargs )
def ActionService( self, service_key, action ):
if action != 'stop': ( service_type, options ) = self.Read( 'service_info', service_key )
def TWISTEDDoIt():
def StartService( *args, **kwargs ):
try:
if 'port' not in options: return
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' ]
if service_type == HC.SERVER_ADMIN: service_object = HydrusServer.HydrusServiceAdmin( service_key, service_type, message )
elif service_type == HC.FILE_REPOSITORY: service_object = HydrusServer.HydrusServiceRepositoryFile( service_key, service_type, message )
elif service_type == HC.TAG_REPOSITORY: service_object = HydrusServer.HydrusServiceRepositoryTag( service_key, service_type, message )
elif service_type == HC.MESSAGE_DEPOT: return
self._services[ service_key ] = 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 action == 'start': StartService()
else:
deferred = defer.maybeDeferred( self._services[ service_key ].stopListening )
if action == 'restart': deferred.addCallback( StartService )
elif action == 'stop': del self._services[ service_key ]
reactor.callFromThread( TWISTEDDoIt )
def EventExit( self, event ): wx.CallAfter( self._tbicon.Destroy )
def EventPubSub( self, event ): HC.pubsub.WXProcessQueueItem()
def GetManager( self, manager_type ): return self._managers[ manager_type ]
def JustWokeFromSleep( self ): return False
def OnInit( self ):
HC.app = self
try:
self.Bind( HC.EVT_PUBSUB, self.EventPubSub )
self._db = ServerDB.DB()
threading.Thread( target = self._db.MainLoop, name = 'Database Main Loop' ).start()
self.Bind( wx.EVT_MENU, self.EventExit, id=wx.ID_EXIT )
self._managers = {}
self._managers[ 'restricted_services_sessions' ] = HydrusSessions.HydrusSessionManagerServer()
self._managers[ 'messaging_sessions' ] = HydrusSessions.HydrusMessagingSessionManagerServer()
HC.pubsub.sub( self, 'ActionService', 'action_service' )
self._services = {}
#
self.Bind( wx.EVT_TIMER, self.TIMEREventMaintenance, id = ID_MAINTENANCE_EVENT_TIMER )
self._maintenance_event_timer = wx.Timer( self, ID_MAINTENANCE_EVENT_TIMER )
self._maintenance_event_timer.Start( MAINTENANCE_PERIOD * 1000, wx.TIMER_CONTINUOUS )
#
( service_type, options ) = self.Read( 'service_info', HC.SERVER_ADMIN_KEY )
port = options[ 'port' ]
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.MessageBox( message )
return False
except: pass
#
service_keys = self.Read( 'service_keys' )
for service_key in service_keys: self.ActionService( service_key, 'start' )
self.StartDaemons()
if HC.PLATFORM_WINDOWS: self._tbicon = TaskBarIcon()
else:
stay_open_frame = wx.Frame( None, title = 'Hydrus Server' )
stay_open_frame.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
stay_open_frame.SetIcon( wx.Icon( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', wx.BITMAP_TYPE_ICO ) )
wx.StaticText( stay_open_frame, label = 'The hydrus server is now running.' + os.linesep * 2 + 'Close this window to stop it.' )
( x, y ) = stay_open_frame.GetEffectiveMinSize()
stay_open_frame.SetInitialSize( ( x, y ) )
stay_open_frame.Show()
return True
except Exception as e:
print( traceback.format_exc() )
return False
def Read( self, action, *args, **kwargs ):
return self._Read( action, HC.HIGH_PRIORITY, *args, **kwargs )
def ReadDaemon( self, action, *args, **kwargs ):
return self._Read( action, HC.LOW_PRIORITY, *args, **kwargs )
def StartDaemons( self ):
HydrusThreading.DAEMONQueue( 'FlushRequestsMade', ServerDB.DAEMONFlushRequestsMade, 'request_made', period = 60 )
HydrusThreading.DAEMONWorker( 'CheckMonthlyData', ServerDB.DAEMONCheckMonthlyData, period = 3600 )
HydrusThreading.DAEMONWorker( 'ClearBans', ServerDB.DAEMONClearBans, period = 3600 )
HydrusThreading.DAEMONWorker( 'DeleteOrphans', ServerDB.DAEMONDeleteOrphans, period = 86400 )
HydrusThreading.DAEMONWorker( 'GenerateUpdates', ServerDB.DAEMONGenerateUpdates, period = 1200 )
HydrusThreading.DAEMONWorker( 'CheckDataUsage', ServerDB.DAEMONCheckDataUsage, period = 86400 )
HydrusThreading.DAEMONWorker( 'UPnP', ServerDB.DAEMONUPnP, ( 'notify_new_options', ), period = 43200 )
def TIMEREventMaintenance( self, event ):
sys.stdout.flush()
sys.stderr.flush()
def Write( self, action, *args, **kwargs ):
return self._Write( action, HC.HIGH_PRIORITY, *args, **kwargs )
def WriteDaemon( self, action, *args, **kwargs ):
return self._Write( action, HC.LOW_PRIORITY, *args, **kwargs )
class TaskBarIcon( wx.TaskBarIcon ):
def __init__( self ):
wx.TaskBarIcon.__init__( self )
icon = wx.Icon( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', wx.BITMAP_TYPE_ICO )
self.SetIcon( icon, 'hydrus server' )
self._tbmenu = wx.Menu()
self._tbmenu.Append( wx.ID_EXIT, 'exit' )
self.Bind( wx.EVT_TASKBAR_RIGHT_DOWN, lambda event: self.PopupMenu( self._tbmenu ) )