Skip to content
Snippets Groups Projects
Commit b755651e authored by inso's avatar inso
Browse files

Fix tasks synchronization problems

- When we change account or community, we cancel all related tasks
- We defined some tasks as being able to run only once
- When a task is started a second time and the firt one is not finished,
the second one is canceled
parent 1a3d4b63
Branches
Tags
No related merge requests found
......@@ -60,7 +60,7 @@ class IdentitiesRegistry:
identity.blockchain_state = BlockchainState.VALIDATED
logging.debug("Lookup : found {0}".format(identity))
if not future_identity.cancelled():
future_identity.set_result(True)
future_identity.set_result(identity)
else:
reply = community.bma_access.simple_request(qtbma.wot.Lookup,
req_args={'search': pubkey})
......@@ -69,7 +69,7 @@ class IdentitiesRegistry:
reply = community.bma_access.simple_request(qtbma.wot.CertifiersOf, req_args={'search': pubkey})
reply.finished.connect(lambda: handle_certifiersof_reply(reply, tries=tries+1))
elif not future_identity.cancelled():
future_identity.set_result(True)
future_identity.set_result(identity)
def handle_lookup_reply(reply, tries=0):
status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
......
......@@ -15,11 +15,10 @@ from .wot_tab import WotTabWidget
from .identities_tab import IdentitiesTabWidget
from .transactions_tab import TransactionsTabWidget
from .network_tab import NetworkTabWidget
from .password_asker import PasswordAskerDialog
from . import toast
import asyncio
from ..tools.exceptions import MembershipNotFoundError, LookupFailureError, NoPeerAvailable
from ..tools.decorators import asyncify
from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task
from ..gen_resources.community_view_uic import Ui_CommunityWidget
......@@ -79,7 +78,13 @@ class CommunityWidget(QWidget, Ui_CommunityWidget):
self.button_membership.clicked.connect(self.send_membership_demand)
def cancel_once_tasks(self):
cancel_once_task(self, self.refresh_block)
cancel_once_task(self, self.refresh_status)
cancel_once_task(self, self.refresh_quality_buttons)
def change_account(self, account, password_asker):
self.cancel_once_tasks()
if self.account:
self.account.broadcast_error.disconnect(self.handle_broadcast_error)
self.account.membership_broadcasted.disconnect(self.handle_membership_broadcasted)
......@@ -98,6 +103,8 @@ class CommunityWidget(QWidget, Ui_CommunityWidget):
self.tab_history.change_account(account, self.password_asker)
def change_community(self, community):
self.cancel_once_tasks()
self.tab_network.change_community(community)
self.tab_wot.change_community(community)
self.tab_history.change_community(community)
......@@ -119,6 +126,7 @@ class CommunityWidget(QWidget, Ui_CommunityWidget):
error,
QMessageBox.Ok)
@once_at_a_time
@asyncify
@asyncio.coroutine
def refresh_block(self, block_number):
......@@ -169,6 +177,7 @@ class CommunityWidget(QWidget, Ui_CommunityWidget):
self.tab_history.refresh_balance()
self.refresh_status()
@once_at_a_time
@asyncify
@asyncio.coroutine
def refresh_status(self):
......@@ -203,6 +212,7 @@ class CommunityWidget(QWidget, Ui_CommunityWidget):
self.status_label.setText(label_text)
@once_at_a_time
@asyncify
@asyncio.coroutine
def refresh_quality_buttons(self):
......
......@@ -18,7 +18,7 @@ from .certification import CertificationDialog
import asyncio
from ..core.net.api import bma as qtbma
from ..core.registry import Identity
from ..tools.decorators import asyncify
from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task
class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab):
......@@ -61,17 +61,26 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab):
self.button_search.addAction(direct_connections)
self.button_search.clicked.connect(self._async_execute_search_text)
def cancel_once_tasks(self):
cancel_once_task(self, self.identity_context_menu)
cancel_once_task(self, self._async_execute_search_text)
cancel_once_task(self, self._async_search_members)
cancel_once_task(self, self._async_search_direct_connections)
def change_account(self, account, password_asker):
self.cancel_once_tasks()
self.account = account
self.password_asker = password_asker
if self.account is None:
self.community = None
def change_community(self, community):
self.cancel_once_tasks()
self.community = community
self.table_identities.model().change_community(community)
self._async_search_direct_connections()
@once_at_a_time
@asyncify
@asyncio.coroutine
def identity_context_menu(self, point):
......@@ -160,6 +169,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab):
identity = self.sender().data()
self.view_in_wot.emit(identity)
@once_at_a_time
@asyncify
@asyncio.coroutine
def _async_execute_search_text(self, checked):
......@@ -175,6 +185,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab):
self.edit_textsearch.clear()
self.refresh_identities(identities)
@once_at_a_time
@asyncify
@asyncio.coroutine
def _async_search_members(self, checked=False):
......@@ -191,6 +202,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab):
self.edit_textsearch.clear()
self.refresh_identities(identities)
@once_at_a_time
@asyncify
@asyncio.coroutine
def _async_search_direct_connections(self, checked=False):
......
......@@ -11,7 +11,7 @@ from .transfer import TransferMoneyDialog
from .certification import CertificationDialog
from ..core.wallet import Wallet
from ..core.registry import Identity
from ..tools.decorators import asyncify
from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task
from .transfer import TransferMoneyDialog
from . import toast
......@@ -39,18 +39,42 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget):
self.account = None
self.community = None
self.password_asker = None
ts_from = self.date_from.dateTime().toTime_t()
ts_to = self.date_to.dateTime().toTime_t()
model = HistoryTableModel(self.app, self.account, self.community)
proxy = TxFilterProxyModel(ts_from, ts_to)
proxy.setSourceModel(model)
proxy.setDynamicSortFilter(True)
proxy.setSortRole(Qt.DisplayRole)
self.table_history.setModel(proxy)
self.table_history.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table_history.setSortingEnabled(True)
self.table_history.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
self.table_history.resizeColumnsToContents()
self.progressbar.hide()
self.refresh()
def cancel_once_tasks(self):
cancel_once_task(self, self.refresh_minimum_maximum)
cancel_once_task(self, self.refresh_balance)
cancel_once_task(self, self.history_context_menu)
def change_account(self, account, password_asker):
self.cancel_once_tasks()
self.account = account
self.password_asker = password_asker
self.table_history.model().sourceModel().change_account(account)
def change_community(self, community):
self.cancel_once_tasks()
self.community = community
self.table_history.model().sourceModel().change_community(self.community)
self.refresh()
self.stop_progress([])
@once_at_a_time
@asyncify
@asyncio.coroutine
def refresh_minimum_maximum(self):
......@@ -72,20 +96,6 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget):
#TODO: Use resetmodel instead of destroy/create
if self.community:
self.refresh_minimum_maximum()
ts_from = self.date_from.dateTime().toTime_t()
ts_to = self.date_to.dateTime().toTime_t()
model = HistoryTableModel(self.app, self.community)
proxy = TxFilterProxyModel(ts_from, ts_to)
proxy.setSourceModel(model)
proxy.setDynamicSortFilter(True)
proxy.setSortRole(Qt.DisplayRole)
self.table_history.setModel(proxy)
self.table_history.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table_history.setSortingEnabled(True)
self.table_history.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
self.table_history.resizeColumnsToContents()
self.refresh_balance()
......@@ -114,6 +124,7 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget):
self.table_history.model().sourceModel().refresh_transfers()
self.table_history.resizeColumnsToContents()
@once_at_a_time
@asyncify
@asyncio.coroutine
def refresh_balance(self):
......@@ -130,6 +141,7 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget):
)
)
@once_at_a_time
@asyncify
@asyncio.coroutine
def history_context_menu(self, point):
......
......@@ -6,7 +6,7 @@ from PyQt5.QtWidgets import QWidget, QComboBox, QDialog
from PyQt5.QtCore import pyqtSlot, QEvent, QLocale, QDateTime
from ..tools.exceptions import MembershipNotFoundError
from ..tools.decorators import asyncify
from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task
from ..core.net.api import bma
from ..core.graph import Graph
from ..core.registry import BlockchainState
......@@ -56,14 +56,16 @@ class WotTabWidget(QWidget, Ui_WotTabWidget):
# create node metadata from account
self._current_identity = None
def cancel_once_tasks(self):
cancel_once_task(self, self.draw_graph)
cancel_once_task(self, self.refresh_informations_frame)
cancel_once_task(self, self.reset)
def change_account(self, account, password_asker):
self.account = account
self.password_asker = password_asker
def change_community(self, community):
if self.draw_task and not self.draw_task.done:
self.draw_task.cancel()
if self.community:
self.community.network.new_block_mined.disconnect(self.refresh)
if community:
......@@ -71,6 +73,7 @@ class WotTabWidget(QWidget, Ui_WotTabWidget):
self.community = community
self.reset()
@once_at_a_time
@asyncify
@asyncio.coroutine
def refresh_informations_frame(self):
......@@ -161,17 +164,10 @@ class WotTabWidget(QWidget, Ui_WotTabWidget):
)
)
def draw_graph(self, identity):
if self.draw_task and not self.draw_task.done():
self.draw_task.cancel()
try:
self.draw_task = asyncio.async(self.cor_draw_graph(identity))
except asyncio.CancelledError:
logging.debug("Cancelled drawing task")
@once_at_a_time
@asyncify
@asyncio.coroutine
def cor_draw_graph(self, identity):
def draw_graph(self, identity):
"""
Draw community graph centered on the identity
......@@ -219,6 +215,7 @@ class WotTabWidget(QWidget, Ui_WotTabWidget):
if path:
self.graphicsView.scene().update_path(path)
@once_at_a_time
@asyncify
@asyncio.coroutine
def reset(self, checked=False):
......
......@@ -6,7 +6,7 @@ Created on 5 févr. 2014
from ..core.net.api import bma as qtbma
from ..tools.exceptions import NoPeerAvailable, MembershipNotFoundError
from ..tools.decorators import asyncify
from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task
from PyQt5.QtCore import QAbstractTableModel, QSortFilterProxyModel, Qt, \
QDateTime, QModelIndex, QLocale
from PyQt5.QtGui import QColor
......@@ -95,6 +95,7 @@ class IdentitiesTableModel(QAbstractTableModel):
self._sig_validity = 0
def change_community(self, community):
cancel_once_task(self, self.refresh_identities)
self.community = community
def sig_validity(self):
......@@ -118,6 +119,7 @@ class IdentitiesTableModel(QAbstractTableModel):
return (identity.uid, identity.pubkey, join_date, expiration_date)
@once_at_a_time
@asyncify
@asyncio.coroutine
def refresh_identities(self, identities):
......
......@@ -8,7 +8,7 @@ import datetime
import logging
import asyncio
from ..core.transfer import Transfer
from ..tools.decorators import asyncify
from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task
from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, QSortFilterProxyModel, \
QDateTime, QLocale, QModelIndex
......@@ -171,14 +171,14 @@ class HistoryTableModel(QAbstractTableModel):
A Qt abstract item model to display communities in a tree
"""
def __init__(self, app, community, parent=None):
def __init__(self, app, account, community, parent=None):
"""
Constructor
"""
super().__init__(parent)
self.app = app
self.account = account
self.community = community
self.account._current_ref
self.transfers_data = []
self.refresh_transfers()
self._max_validations = 0
......@@ -208,12 +208,19 @@ class HistoryTableModel(QAbstractTableModel):
'Block Number'
)
@property
def account(self):
return self.app.current_account
def change_account(self, account):
cancel_once_task(self, self.refresh_transfers)
self.account = account
def change_community(self, community):
cancel_once_task(self, self.refresh_transfers)
self.community = community
def transfers(self):
if self.account:
return self.account.transfers(self.community) + self.account.dividends(self.community)
else:
return []
@asyncio.coroutine
def data_received(self, transfer):
......@@ -273,11 +280,13 @@ class HistoryTableModel(QAbstractTableModel):
deposit, "", state, id,
self.account.pubkey, block_number, amount)
@once_at_a_time
@asyncify
@asyncio.coroutine
def refresh_transfers(self):
self.beginResetModel()
self.transfers_data = []
if self.community:
for transfer in self.transfers():
data = None
if type(transfer) is Transfer:
......@@ -303,6 +312,7 @@ class HistoryTableModel(QAbstractTableModel):
return len(self.columns_types)
def headerData(self, section, orientation, role):
if self.account and self.community:
if role == Qt.DisplayRole:
if self.columns_types[section] == 'payment' or self.columns_types[section] == 'deposit':
return '{:}\n({:})'.format(
......
import asyncio
import functools
import logging
def cancel_once_task(object, fn):
if getattr(object, "__tasks", None):
tasks = getattr(object, "__tasks")
if fn.__name__ in tasks and not tasks[fn.__name__].done():
getattr(object, "__tasks")[fn.__name__].cancel()
def once_at_a_time(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
if getattr(args[0], "__tasks", None) is None:
setattr(args[0], "__tasks", {})
if fn.__name__ in args[0].__tasks:
if not args[0].__tasks[fn.__name__].done():
args[0].__tasks[fn.__name__].cancel()
try:
args[0].__tasks[fn.__name__] = fn(*args, **kwargs)
except asyncio.CancelledError:
logging.debug("Cancelled asyncified : {0}".format(fn.__name__))
return args[0].__tasks[fn.__name__]
return wrapper
def asyncify(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
asyncio.async(asyncio.coroutine(fn)(*args, **kwargs))
return asyncio.async(asyncio.coroutine(fn)(*args, **kwargs))
return wrapper
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment