comparison sat_frontends/quick_frontend/quick_app.py @ 2862:b2e898384c25

quick_frontend (app): progress callbacks handling: in addition to listeners, a frontend can now register progression callback and errback which are called when the given progressing action is finished. Those callbacks can be registered using registerProgressCbs or specified in actionManager.
author Goffi <goffi@goffi.org>
date Wed, 20 Mar 2019 09:08:47 +0100
parents e9e33e05d143
children c7c52c0dc13a
comparison
equal deleted inserted replaced
2861:e9e33e05d143 2862:b2e898384c25
311 self.options = None 311 self.options = None
312 312
313 # widget currently selected (must be filled by frontend) 313 # widget currently selected (must be filled by frontend)
314 self.selected_widget = None 314 self.selected_widget = None
315 315
316 # listeners 316 # listeners are callable watching events
317 self._listeners = {} # key: listener type ("avatar", "selected", etc), 317 self._listeners = {} # key: listener type ("avatar", "selected", etc),
318 # value: list of callbacks 318 # value: list of callbacks
319 319
320 # triggers 320 # triggers
321 self.trigger = ( 321 self.trigger = (
326 self.bridge = bridge_factory() 326 self.bridge = bridge_factory()
327 ProfileManager.bridge = self.bridge 327 ProfileManager.bridge = self.bridge
328 if connect_bridge: 328 if connect_bridge:
329 self.connectBridge() 329 self.connectBridge()
330 330
331 # frontend notifications
331 self._notif_id = 0 332 self._notif_id = 0
332 self._notifications = OrderedDict() 333 self._notifications = OrderedDict()
334 # watched progresses and associated callbacks
335 self._progress_ids = {}
336 # available features
337 # FIXME: features are profile specific, to be checked
333 self.features = None 338 self.features = None
334 self.ns_map = {} # map of short name to namespaces 339 #: map of short name to namespaces
340 self.ns_map = {}
341 #: available encryptions
335 self.encryption_plugins = [] 342 self.encryption_plugins = []
336 self._sync = True # state of synchronisation with backend 343 # state of synchronisation with backend
344 self._sync = True
337 345
338 def connectBridge(self): 346 def connectBridge(self):
339 self.bridge.bridgeConnect(callback=self._bridgeCb, errback=self._bridgeEb) 347 self.bridge.bridgeConnect(callback=self._bridgeCb, errback=self._bridgeEb)
340 348
341 def _namespacesGetCb(self, ns_map): 349 def _namespacesGetCb(self, ns_map):
434 442
435 # backend state management 443 # backend state management
436 444
437 @property 445 @property
438 def sync(self): 446 def sync(self):
439 """Get synchronization flag 447 """Synchronization flag
440 448
441 True if this frontend is synchronised with backend 449 True if this frontend is synchronised with backend
442 """ 450 """
443 return self._sync 451 return self._sync
444 452
1040 wid.deleteEntryIfPresent(service_s, node, data["id"], profile) 1048 wid.deleteEntryIfPresent(service_s, node, data["id"], profile)
1041 pass 1049 pass
1042 else: 1050 else:
1043 log.warning("Unmanaged PubSub event type {}".format(event_type)) 1051 log.warning("Unmanaged PubSub event type {}".format(event_type))
1044 1052
1053 def registerProgressCbs(self, progress_id, callback, errback):
1054 """Register progression callbacks
1055
1056 @param progress_id(unicode): id of the progression to check
1057 @param callback(callable, None): method to call when progressing action
1058 successfuly finished.
1059 None to ignore
1060 @param errback(callable, None): method to call when progressions action failed
1061 None to ignore
1062 """
1063 callbacks = self._progress_ids.setdefault(progress_id, [])
1064 callbacks.append((callback, errback))
1065
1045 def progressStartedHandler(self, pid, metadata, profile): 1066 def progressStartedHandler(self, pid, metadata, profile):
1046 log.info(u"Progress {} started".format(pid)) 1067 log.info(u"Progress {} started".format(pid))
1047 1068
1048 def progressFinishedHandler(self, pid, metadata, profile): 1069 def progressFinishedHandler(self, pid, metadata, profile):
1049 log.info(u"Progress {} finished".format(pid)) 1070 log.info(u"Progress {} finished".format(pid))
1071 try:
1072 callbacks = self._progress_ids.pop(pid)
1073 except KeyError:
1074 pass
1075 else:
1076 for callback, __ in callbacks:
1077 if callback is not None:
1078 callback(metadata, profile=profile)
1050 self.callListeners("progressFinished", pid, metadata, profile=profile) 1079 self.callListeners("progressFinished", pid, metadata, profile=profile)
1051 1080
1052 def progressErrorHandler(self, pid, err_msg, profile): 1081 def progressErrorHandler(self, pid, err_msg, profile):
1053 log.warning(u"Progress {pid} error: {err_msg}".format(pid=pid, err_msg=err_msg)) 1082 log.warning(u"Progress {pid} error: {err_msg}".format(pid=pid, err_msg=err_msg))
1083 try:
1084 callbacks = self._progress_ids.pop(pid)
1085 except KeyError:
1086 pass
1087 else:
1088 for __, errback in callbacks:
1089 if errback is not None:
1090 errback(err_msg, profile=profile)
1054 self.callListeners("progressError", pid, err_msg, profile=profile) 1091 self.callListeners("progressError", pid, err_msg, profile=profile)
1055 1092
1056 def _subscribe_cb(self, answer, data): 1093 def _subscribe_cb(self, answer, data):
1057 entity, profile = data 1094 entity, profile = data
1058 type_ = "subscribed" if answer else "unsubscribed" 1095 type_ = "subscribed" if answer else "unsubscribed"
1164 elif key == "avatar" and self.AVATARS_HANDLER: 1201 elif key == "avatar" and self.AVATARS_HANDLER:
1165 if value and entity in self.contact_lists[profile]: 1202 if value and entity in self.contact_lists[profile]:
1166 self.getAvatar(entity, ignore_cache=True, profile=profile) 1203 self.getAvatar(entity, ignore_cache=True, profile=profile)
1167 1204
1168 def actionManager(self, action_data, callback=None, ui_show_cb=None, user_action=True, 1205 def actionManager(self, action_data, callback=None, ui_show_cb=None, user_action=True,
1169 profile=C.PROF_KEY_NONE): 1206 progress_cb=None, progress_eb=None, profile=C.PROF_KEY_NONE):
1170 """Handle backend action 1207 """Handle backend action
1171 1208
1172 @param action_data(dict): action dict as sent by launchAction or returned by an 1209 @param action_data(dict): action dict as sent by launchAction or returned by an
1173 UI action 1210 UI action
1174 @param callback(None, callback): if not None, callback to use on XMLUI answer 1211 @param callback(None, callback): if not None, callback to use on XMLUI answer
1175 @param ui_show_cb(None, callback): if not None, method to call to show the XMLUI 1212 @param ui_show_cb(None, callback): if not None, method to call to show the XMLUI
1176 @param user_action(bool): if True, the action is a result of a user interaction 1213 @param user_action(bool): if True, the action is a result of a user interaction
1177 else the action come from backend direclty (i.e. actionNew) 1214 else the action come from backend direclty (i.e. actionNew).
1215 This is useful to know if the frontend can display a popup immediately (if
1216 True) or if it should add it to a queue that the user can activate later.
1217 @param progress_cb(None, callable): method to call when progression is finished.
1218 Only make sense if a progress is expected in this action
1219 @param progress_eb(None, callable): method to call when something went wrong
1220 during progression.
1221 Only make sense if a progress is expected in this action
1178 """ 1222 """
1179 try: 1223 try:
1180 xmlui = action_data.pop("xmlui") 1224 xmlui = action_data.pop("xmlui")
1181 except KeyError: 1225 except KeyError:
1182 pass 1226 pass
1196 try: 1240 try:
1197 progress_id = action_data.pop("progress") 1241 progress_id = action_data.pop("progress")
1198 except KeyError: 1242 except KeyError:
1199 pass 1243 pass
1200 else: 1244 else:
1245 if progress_cb or progress_eb:
1246 self.registerProgressCbs(progress_id, progress_cb, progress_eb)
1201 self.progressIdHandler(progress_id, profile) 1247 self.progressIdHandler(progress_id, profile)
1202 1248
1203 # we ignore metadata 1249 # we ignore metadata
1204 action_data = { 1250 action_data = {
1205 k: v for k, v in action_data.iteritems() if not k.startswith("meta_") 1251 k: v for k, v in action_data.iteritems() if not k.startswith("meta_")