Skip to content

Commit

Permalink
Fix race condition in guiEditor
Browse files Browse the repository at this point in the history
Signed-off-by: Loren Eteval <loren.eteval@proton.me>
  • Loading branch information
LorenEteval committed May 11, 2024
1 parent 75f0469 commit 0534f42
Showing 1 changed file with 68 additions and 60 deletions.
128 changes: 68 additions & 60 deletions Furious/Widget/UserServersQTableWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import logging
import icmplib
import functools
import threading

__all__ = ['UserServersQTableWidget']

Expand Down Expand Up @@ -811,6 +812,9 @@ def __init__(self, *args, **kwargs):

# Distinguish double-click and activated
self.doubleClickedFlag = False

self.guiEditorMutex = threading.Lock()

# Signals
self.itemChanged.connect(self.handleItemChanged)
self.itemSelectionChanged.connect(self.handleItemSelectionChanged)
Expand Down Expand Up @@ -914,65 +918,67 @@ def getGuiEditorByFactory(self, factory, **kwargs):

@QtCore.Slot(QTableWidgetItem)
def handleItemDoubleClicked(self, item: QTableWidgetItem):
self.doubleClickedFlag = True
with self.guiEditorMutex:
self.doubleClickedFlag = True

index = item.row()
factory = AS_UserServers()[index]
index = item.row()
factory = AS_UserServers()[index]

guiEditor = self.getGuiEditorByFactory(factory, translatable=False)
guiEditor = self.getGuiEditorByFactory(factory, translatable=False)

if guiEditor is None:
# Unrecognized. Do nothing
return
if guiEditor is None:
# Unrecognized. Do nothing
return

# Dummy ref
setattr(self, '_guiEditorRef0', guiEditor)
# Dummy ref
setattr(self, '_guiEditorRef0', guiEditor)

guiEditor.setWindowTitle(f'{index + 1} - ' + factory.getExtras('remark'))
guiEditor.setWindowTitle(f'{index + 1} - ' + factory.getExtras('remark'))

try:
guiEditor.factoryToInput(factory)
except Exception as ex:
# Any non-exit exceptions
try:
guiEditor.factoryToInput(factory)
except Exception as ex:
# Any non-exit exceptions

logger.error(f'error while converting factory to input: {ex}')
logger.error(f'error while converting factory to input: {ex}')

guiEditor.accepted.connect(
functools.partial(
self.handleGuiEditorAccepted,
guiEditor,
index,
factory,
guiEditor.accepted.connect(
functools.partial(
self.handleGuiEditorAccepted,
guiEditor,
index,
factory,
)
)
)
guiEditor.open()
guiEditor.open()

def handleGuiEditorAccepted(
self,
editor: GuiEditorWidgetQDialog,
index: int,
factory: ConfigurationFactory,
):
logger.debug(f'guiEditor accepted with index {index}')
with self.guiEditorMutex:
logger.debug(f'guiEditor accepted with index {index}')

modified = editor.inputToFactory(factory)
modified = editor.inputToFactory(factory)

# Still flush to row since remark may be modified
self.flushRow(index, factory)
# Still flush to row since remark may be modified
self.flushRow(index, factory)

if modified and index == AS_UserActivatedItemIndex():
try:
if APP().isSystemTrayConnected():
mbox = NewChangesNextTimeMBox()
if modified and index == AS_UserActivatedItemIndex():
try:
if APP().isSystemTrayConnected():
mbox = NewChangesNextTimeMBox()

# Show the MessageBox asynchronously
mbox.open()
except Exception:
# Any non-exit exceptions
# Show the MessageBox asynchronously
mbox.open()
except Exception:
# Any non-exit exceptions

pass
pass

editor.accepted.disconnect()
editor.accepted.disconnect()

@QtCore.Slot(QtCore.QPoint)
def handleCustomContextMenuRequested(self, point):
Expand Down Expand Up @@ -1073,45 +1079,47 @@ def addServerViaGui(
windowTitle: str = APPLICATION_NAME,
**kwargs,
):
factory = getEmptyFactory(protocol)
with self.guiEditorMutex:
factory = getEmptyFactory(protocol)

guiEditor = self.getGuiEditorByFactory(factory, **kwargs)
guiEditor = self.getGuiEditorByFactory(factory, **kwargs)

if guiEditor is None:
# Unrecognized. Do nothing
return
if guiEditor is None:
# Unrecognized. Do nothing
return

# Dummy ref
setattr(self, '_guiEditorRef1', guiEditor)
# Dummy ref
setattr(self, '_guiEditorRef1', guiEditor)

guiEditor.setWindowTitle(windowTitle)
guiEditor.setWindowTitle(windowTitle)

try:
guiEditor.factoryToInput(factory)
except Exception as ex:
# Any non-exit exceptions
try:
guiEditor.factoryToInput(factory)
except Exception as ex:
# Any non-exit exceptions

logger.error(f'error while converting factory to input: {ex}')
logger.error(f'error while converting factory to input: {ex}')

guiEditor.accepted.connect(
functools.partial(
self.handleAddServerViaGui,
guiEditor,
factory,
guiEditor.accepted.connect(
functools.partial(
self.handleAddServerViaGui,
guiEditor,
factory,
)
)
)
guiEditor.open()
guiEditor.open()

def handleAddServerViaGui(
self,
editor: GuiEditorWidgetQDialog,
factory: ConfigurationFactory,
):
editor.inputToFactory(factory)
with self.guiEditorMutex:
editor.inputToFactory(factory)

self.appendNewItemByFactory(factory)
self.appendNewItemByFactory(factory)

editor.accepted.disconnect()
editor.accepted.disconnect()

def flushRow(self, row: int, item: ConfigurationFactory):
for column in list(range(self.columnCount())):
Expand Down

0 comments on commit 0534f42

Please sign in to comment.