# HG changeset patch # User Goffi # Date 1552237391 -3600 # Node ID 7764383a968c1a3e2d32af85f13b9dcac470eeb3 # Parent 272dc905ff207e7bd72013dd93c6a187643b8cc5 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. diff -r 272dc905ff20 -r 7764383a968c sat_frontends/quick_frontend/quick_chat.py --- a/sat_frontends/quick_frontend/quick_chat.py Sun Mar 10 18:03:02 2019 +0100 +++ b/sat_frontends/quick_frontend/quick_chat.py Sun Mar 10 18:03:11 2019 +0100 @@ -281,6 +281,9 @@ 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 @@ 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 @@ ## 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 @@ """ 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 @@ 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), diff -r 272dc905ff20 -r 7764383a968c sat_frontends/quick_frontend/quick_widgets.py --- a/sat_frontends/quick_frontend/quick_widgets.py Sun Mar 10 18:03:02 2019 +0100 +++ b/sat_frontends/quick_frontend/quick_widgets.py Sun Mar 10 18:03:11 2019 +0100 @@ -334,6 +334,7 @@ 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 @@ ) 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 @@ 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 @@ """ 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