quick_frontend (widget, chat): implementation of new sync mechanism, first draft:

QuickWidget implement base of sync mechanism with a sync property which can be overriden, and resync method which is called when resynchronisation is needed.
When resync is required, chat widget get missing occupant and history elements
A new callable argument can be used with historyPrint, when set it is called when history has been fully printed.
This commit is contained in:
Goffi 2019-03-10 18:03:11 +01:00
commit 4c8f108192
2 changed files with 80 additions and 2 deletions

View file

@ -281,6 +281,9 @@ class QuickChat(quick_widgets.QuickWidget):
self.type = type_
self.encrypted = False # True if this session is currently encrypted
self._locked = False
# True when resync is in progress, avoid resynchronising twice when resync is called
# and history is still being updated. For internal use only
self._resync_lock = False
self.setLocked()
if type_ == C.CHAT_GROUP:
if target.resource:
@ -363,6 +366,43 @@ class QuickChat(quick_widgets.QuickWidget):
def contact_list(self):
return self.host.contact_lists[self.profile]
## synchornisation handling ##
@quick_widgets.QuickWidget.sync.setter
def sync(self, state):
quick_widgets.QuickWidget.sync.fset(self, state)
if not state:
self.setLocked()
def _resyncComplete(self):
self.sync = True
self._resync_lock = False
def resync(self):
if self._resync_lock:
return
self._resync_lock = True
log.debug(u"resynchronising {self}".format(self=self))
for mess in reversed(self.messages.values()):
if mess.type == C.MESS_TYPE_INFO:
continue
last_message = mess
break
else:
# we have no message yet, we can get normal history
self.historyPrint(callback=self._resyncComplete, profile=self.profile)
return
if self.type == C.CHAT_GROUP:
self.occupants.clear()
self.host.bridge.mucOccupantsGet(
unicode(self.target), self.profile, callback=self.updateOccupants,
errback=log.error)
self.historyPrint(
size=C.HISTORY_LIMIT_NONE,
filters={'timestamp_start': last_message.timestamp},
callback=self._resyncComplete,
profile=self.profile)
## Widget management ##
def __unicode__(self):
@ -428,9 +468,11 @@ class QuickChat(quick_widgets.QuickWidget):
## occupants ##
def setOccupants(self, occupants):
"""set the whole list of occupants"""
"""Set the whole list of occupants"""
assert len(self.occupants) == 0
for nick, data in occupants.iteritems():
log.debug(u"adding occupant {nick} to {room}".format(
nick=nick, room=self.target))
self.occupants[nick] = Occupant(self, data, self.profile)
def updateOccupants(self, occupants):
@ -523,12 +565,14 @@ class QuickChat(quick_widgets.QuickWidget):
"""
self.setUnlocked()
def historyPrint(self, size=C.HISTORY_LIMIT_DEFAULT, filters=None, profile="@NONE@"):
def historyPrint(self, size=C.HISTORY_LIMIT_DEFAULT, filters=None, callback=None,
profile="@NONE@"):
"""Print the current history
Note: self.setUnlocked will be called once history is printed
@param size (int): number of messages
@param search (str): pattern to filter the history results
@param callback(callable, None): method to call when history has been printed
@param profile (str): %(doc_profile)s
"""
if filters is None:
@ -589,10 +633,14 @@ class QuickChat(quick_widgets.QuickWidget):
profile,
)
self._onHistoryPrinted()
if callback is not None:
callback()
def _historyGetEb(err):
log.error(_(u"Can't get history: {}").format(err))
self._onHistoryPrinted()
if callback is not None:
callback()
self.host.bridge.historyGet(
unicode(self.host.profiles[profile].whoami.bare),

View file

@ -334,6 +334,7 @@ class QuickWidget(object):
self.targets = set()
self.addTarget(target)
self.profiles = set()
self._sync = True
if isinstance(profiles, basestring):
self.addProfile(profiles)
elif profiles is None:
@ -354,6 +355,31 @@ class QuickWidget(object):
)
return list(self.profiles)[0]
# synchronisation state
@property
def sync(self):
return self._sync
@sync.setter
def sync(self, state):
"""state of synchronisation with backend
@param state(bool): True when backend is synchronised
False is set by core
True must be set by the widget when resynchronisation is finished
"""
self._sync = state
def resync(self):
"""Method called when backend can be resynchronized
The widget has to set self.sync itself when the synchronisation if finished
"""
pass
# target/profile
def addTarget(self, target):
"""Add a target if it doesn't already exists
@ -370,6 +396,8 @@ class QuickWidget(object):
raise ValueError("multiple profiles are not allowed")
self.profiles.add(profile)
# widget identitication
@staticmethod
def getWidgetHash(target, profiles):
"""Return the hash associated with this target for this widget class
@ -386,6 +414,8 @@ class QuickWidget(object):
"""
return unicode(target) # by defaut, there is one hash for one target
# widget life events
def onDelete(self, *args, **kwargs):
"""Called when a widget is being deleted