hydrus/hydrus/client/gui/services/ClientGUIServersideServices.py

470 lines
16 KiB
Python

from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusExceptions
from hydrus.core import HydrusGlobals as HG
from hydrus.core.networking import HydrusNetwork
from hydrus.client import ClientConstants as CC
from hydrus.client.gui import ClientGUIDialogsQuick
from hydrus.client.gui import ClientGUIScrolledPanels
from hydrus.client.gui import ClientGUITopLevelWindowsPanels
from hydrus.client.gui import QtPorting as QP
from hydrus.client.gui.lists import ClientGUIListConstants as CGLC
from hydrus.client.gui.lists import ClientGUIListCtrl
from hydrus.client.gui.widgets import ClientGUICommon
from hydrus.client.gui.widgets import ClientGUIControls
from hydrus.client.gui.widgets import ClientGUIMenuButton
class EditServersideService( ClientGUIScrolledPanels.EditPanel ):
def __init__( self, parent: QW.QWidget, serverside_service: HydrusNetwork.ServerService ):
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
duplicate_serverside_service = serverside_service.Duplicate()
( self._service_key, self._service_type, name, port, self._dictionary ) = duplicate_serverside_service.ToTuple()
self._service_panel = self._ServicePanel( self, name, port, self._dictionary )
self._panels = []
if self._service_type in HC.RESTRICTED_SERVICES:
self._panels.append( self._ServiceRestrictedPanel( self, self._dictionary ) )
if self._service_type == HC.FILE_REPOSITORY:
self._panels.append( self._ServiceFileRepositoryPanel( self, self._dictionary ) )
if self._service_type == HC.SERVER_ADMIN:
self._panels.append( self._ServiceServerAdminPanel( self, self._dictionary ) )
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._service_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
for panel in self._panels:
QP.AddToLayout( vbox, panel, CC.FLAGS_EXPAND_PERPENDICULAR )
self.widget().setLayout( vbox )
def GetValue( self ) -> HydrusNetwork.ServerService:
( name, port, dictionary_part ) = self._service_panel.GetValue()
dictionary = self._dictionary.Duplicate()
dictionary.update( dictionary_part )
for panel in self._panels:
dictionary_part = panel.GetValue()
dictionary.update( dictionary_part )
return HydrusNetwork.GenerateService( self._service_key, self._service_type, name, port, dictionary )
class _ServicePanel( ClientGUICommon.StaticBox ):
def __init__( self, parent: QW.QWidget, name: str, port: int, dictionary ):
ClientGUICommon.StaticBox.__init__( self, parent, 'basic information' )
self._name = QW.QLineEdit( self )
self._port = ClientGUICommon.BetterSpinBox( self, min=1, max=65535 )
self._upnp_port = ClientGUICommon.NoneableSpinCtrl( self, 'external upnp port', none_phrase = 'do not forward port', min = 1, max = 65535 )
self._bandwidth_tracker_st = ClientGUICommon.BetterStaticText( self )
#
self._name.setText( name )
self._port.setValue( port )
upnp_port = dictionary[ 'upnp_port' ]
self._upnp_port.SetValue( upnp_port )
bandwidth_tracker = dictionary[ 'bandwidth_tracker' ]
bandwidth_text = bandwidth_tracker.GetCurrentMonthSummary()
self._bandwidth_tracker_st.setText( bandwidth_text )
#
rows = []
rows.append( ( 'name: ', self._name ) )
rows.append( ( 'port: ', self._port ) )
rows.append( ( 'upnp port: ', self._upnp_port ) )
gridbox = ClientGUICommon.WrapInGrid( self, rows )
self.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
self.Add( self._bandwidth_tracker_st, CC.FLAGS_EXPAND_PERPENDICULAR )
def GetValue( self ):
dictionary_part = {}
name = self._name.text()
port = self._port.value()
upnp_port = self._upnp_port.GetValue()
dictionary_part[ 'upnp_port' ] = upnp_port
return ( name, port, dictionary_part )
class _ServiceRestrictedPanel( QW.QWidget ):
def __init__( self, parent: QW.QWidget, dictionary ):
QW.QWidget.__init__( self, parent )
bandwidth_rules = dictionary[ 'bandwidth_rules' ]
self._bandwidth_rules = ClientGUIControls.BandwidthRulesCtrl( self, bandwidth_rules )
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._bandwidth_rules, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
self.setLayout( vbox )
def GetValue( self ):
dictionary_part = {}
dictionary_part[ 'bandwidth_rules' ] = self._bandwidth_rules.GetValue()
return dictionary_part
class _ServiceFileRepositoryPanel( ClientGUICommon.StaticBox ):
def __init__( self, parent: QW.QWidget, dictionary ):
ClientGUICommon.StaticBox.__init__( self, parent, 'file repository' )
self._log_uploader_ips = QW.QCheckBox( self )
self._max_storage = ClientGUIControls.NoneableBytesControl( self, initial_value = 5 * 1024 * 1024 * 1024 )
#
log_uploader_ips = dictionary[ 'log_uploader_ips' ]
max_storage = dictionary[ 'max_storage' ]
self._log_uploader_ips.setChecked( log_uploader_ips )
self._max_storage.SetValue( max_storage )
#
rows = []
rows.append( ( 'log file uploader IP addresses?: ', self._log_uploader_ips ) )
rows.append( ( 'max file storage: ', self._max_storage ) )
gridbox = ClientGUICommon.WrapInGrid( self, rows )
self.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
def GetValue( self ):
dictionary_part = {}
log_uploader_ips = self._log_uploader_ips.isChecked()
max_storage = self._max_storage.GetValue()
dictionary_part[ 'log_uploader_ips' ] = log_uploader_ips
dictionary_part[ 'max_storage' ] = max_storage
return dictionary_part
class _ServiceServerAdminPanel( ClientGUICommon.StaticBox ):
def __init__( self, parent: QW.QWidget, dictionary ):
ClientGUICommon.StaticBox.__init__( self, parent, 'server-wide bandwidth' )
self._bandwidth_tracker_st = ClientGUICommon.BetterStaticText( self )
bandwidth_rules = dictionary[ 'server_bandwidth_rules' ]
self._bandwidth_rules = ClientGUIControls.BandwidthRulesCtrl( self, bandwidth_rules )
#
bandwidth_tracker = dictionary[ 'server_bandwidth_tracker' ]
bandwidth_text = bandwidth_tracker.GetCurrentMonthSummary()
self._bandwidth_tracker_st.setText( bandwidth_text )
#
self.Add( self._bandwidth_tracker_st, CC.FLAGS_EXPAND_PERPENDICULAR )
self.Add( self._bandwidth_rules, CC.FLAGS_EXPAND_PERPENDICULAR )
def GetValue( self ):
dictionary_part = {}
bandwidth_rules = self._bandwidth_rules.GetValue()
dictionary_part[ 'server_bandwidth_rules' ] = bandwidth_rules
return dictionary_part
class ManageServerServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
def __init__( self, parent, service_key ):
self._clientside_admin_service = HG.client_controller.services_manager.GetService( service_key )
ClientGUIScrolledPanels.ManagePanel.__init__( self, parent )
self._deletee_service_keys = []
self._services_listctrl = ClientGUIListCtrl.BetterListCtrl( self, CGLC.COLUMN_LIST_SERVICES.ID, 20, data_to_tuples_func = self._ConvertServiceToTuples, delete_key_callback = self._Delete, activation_callback = self._Edit )
menu_items = []
menu_items.append( ( 'normal', 'tag repository', 'Create a new tag repository.', self._AddTagRepository ) )
menu_items.append( ( 'normal', 'file repository', 'Create a new file repository.', self._AddFileRepository ) )
self._add_button = ClientGUIMenuButton.MenuButton( self, 'add', menu_items )
self._edit_button = ClientGUICommon.BetterButton( self, 'edit', self._Edit )
self._delete_button = ClientGUICommon.BetterButton( self, 'delete', self._Delete )
#
response = self._clientside_admin_service.Request( HC.GET, 'services' )
serverside_services = response[ 'services' ]
self._services_listctrl.AddDatas( serverside_services )
#self._services_listctrl.SortListItems( 0 )
#
hbox = QP.HBoxLayout()
QP.AddToLayout( hbox, self._add_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._edit_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._delete_button, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._services_listctrl, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( vbox, hbox, CC.FLAGS_ON_RIGHT )
self.widget().setLayout( vbox )
def _ConvertServiceToTuples( self, service ):
port = service.GetPort()
name = service.GetName()
service_type = service.GetServiceType()
pretty_port = str( port )
pretty_name = name
pretty_service_type = HC.service_string_lookup[ service_type ]
return ( ( pretty_port, pretty_name, pretty_service_type ), ( port, name, service_type ) )
def _Add( self, service_type ):
service_key = HydrusData.GenerateKey()
port = self._GetNextPort()
name = 'new service'
dictionary = HydrusNetwork.GenerateDefaultServiceDictionary( service_type )
service = HydrusNetwork.GenerateService( service_key, service_type, name, port, dictionary )
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit serverside service' ) as dlg_edit:
panel = EditServersideService( dlg_edit, service )
dlg_edit.SetPanel( panel )
if dlg_edit.exec() == QW.QDialog.Accepted:
new_service = panel.GetValue()
self._services_listctrl.SetNonDupeName( new_service )
self._SetNonDupePort( new_service )
self._services_listctrl.AddDatas( ( new_service, ) )
def _AddFileRepository( self ):
self._Add( HC.FILE_REPOSITORY )
def _AddTagRepository( self ):
self._Add( HC.TAG_REPOSITORY )
def _Delete( self ):
result = ClientGUIDialogsQuick.GetYesNo( self, 'Remove all selected?' )
if result == QW.QDialog.Accepted:
for service in self._services_listctrl.GetData( only_selected = True ):
self._deletee_service_keys.append( service.GetServiceKey() )
self._services_listctrl.DeleteSelected()
def _Edit( self ):
for service in self._services_listctrl.GetData( only_selected = True ):
original_name = service.GetName()
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit serverside service' ) as dlg_edit:
panel = EditServersideService( dlg_edit, service )
dlg_edit.SetPanel( panel )
result = dlg_edit.exec()
if result == QW.QDialog.Accepted:
edited_service = panel.GetValue()
if edited_service.GetName() != original_name:
self._services_listctrl.SetNonDupeName( edited_service )
self._SetNonDupePort( edited_service )
self._services_listctrl.ReplaceData( service, edited_service )
elif dlg_edit.WasCancelled():
break
def _GetNextPort( self ):
existing_ports = [ service.GetPort() for service in self._services_listctrl.GetData() ]
largest_port = max( existing_ports )
next_port = largest_port
while next_port in existing_ports:
next_port = max( 1, ( next_port + 1 ) % 65536 )
return next_port
def _SetNonDupePort( self, new_service ):
existing_ports = [ service.GetPort() for service in self._services_listctrl.GetData() if service.GetServiceKey() != new_service.GetServiceKey() ]
new_port = new_service.GetPort()
if new_port in existing_ports:
next_port = self._GetNextPort()
new_service.SetPort( next_port )
def CheckValid( self ):
services = self._services_listctrl.GetData()
unique_ports = { service.GetPort() for service in services }
if len( unique_ports ) < len( services ):
raise HydrusExceptions.VetoException( 'It looks like some of those services share ports! Please give them unique ports!' )
def CommitChanges( self ):
services = self._services_listctrl.GetData()
try:
response = self._clientside_admin_service.Request( HC.POST, 'services', { 'services' : services } )
except Exception as e:
HydrusData.ShowException( e )
raise HydrusExceptions.VetoException( 'There was an error: {}'.format( str( e ) ) )
service_keys_to_access_keys = dict( response[ 'service_keys_to_access_keys' ] )
admin_service_key = self._clientside_admin_service.GetServiceKey()
with HG.dirty_object_lock:
HG.client_controller.WriteSynchronous( 'update_server_services', admin_service_key, services, service_keys_to_access_keys, self._deletee_service_keys )
HG.client_controller.RefreshServices()