470 lines
16 KiB
Python
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()
|
|
|
|
|
|
|